1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/fs.h>
20#include <linux/buffer_head.h>
21#include <linux/quotaops.h>
22#include "jfs_incore.h"
23#include "jfs_filsys.h"
24#include "jfs_metapage.h"
25#include "jfs_dinode.h"
26#include "jfs_imap.h"
27#include "jfs_dmap.h"
28#include "jfs_superblock.h"
29#include "jfs_txnmgr.h"
30#include "jfs_debug.h"
31
32#define BITSPERPAGE (PSIZE << 3)
33#define L2MEGABYTE 20
34#define MEGABYTE (1 << L2MEGABYTE)
35#define MEGABYTE32 (MEGABYTE << 5)
36
37
38#define BLKTODMAPN(b)\
39 (((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1)
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
63{
64 int rc = 0;
65 struct jfs_sb_info *sbi = JFS_SBI(sb);
66 struct inode *ipbmap = sbi->ipbmap;
67 struct inode *ipbmap2;
68 struct inode *ipimap = sbi->ipimap;
69 struct jfs_log *log = sbi->log;
70 struct bmap *bmp = sbi->bmap;
71 s64 newLogAddress, newFSCKAddress;
72 int newFSCKSize;
73 s64 newMapSize = 0, mapSize;
74 s64 XAddress, XSize, nblocks, xoff, xaddr, t64;
75 s64 oldLVSize;
76 s64 newFSSize;
77 s64 VolumeSize;
78 int newNpages = 0, nPages, newPage, xlen, t32;
79 int tid;
80 int log_formatted = 0;
81 struct inode *iplist[1];
82 struct jfs_superblock *j_sb, *j_sb2;
83 s64 old_agsize;
84 int agsizechanged = 0;
85 struct buffer_head *bh, *bh2;
86
87
88
89 if (sbi->mntflag & JFS_INLINELOG)
90 oldLVSize = addressPXD(&sbi->logpxd) + lengthPXD(&sbi->logpxd);
91 else
92 oldLVSize = addressPXD(&sbi->fsckpxd) +
93 lengthPXD(&sbi->fsckpxd);
94
95 if (oldLVSize >= newLVSize) {
96 printk(KERN_WARNING
97 "jfs_extendfs: volume hasn't grown, returning\n");
98 goto out;
99 }
100
101 VolumeSize = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits;
102
103 if (VolumeSize) {
104 if (newLVSize > VolumeSize) {
105 printk(KERN_WARNING "jfs_extendfs: invalid size\n");
106 rc = -EINVAL;
107 goto out;
108 }
109 } else {
110
111 bh = sb_bread(sb, newLVSize - 1);
112 if (!bh) {
113 printk(KERN_WARNING "jfs_extendfs: invalid size\n");
114 rc = -EINVAL;
115 goto out;
116 }
117 bforget(bh);
118 }
119
120
121
122 if (isReadOnly(ipbmap)) {
123 printk(KERN_WARNING "jfs_extendfs: read-only file system\n");
124 rc = -EROFS;
125 goto out;
126 }
127
128
129
130
131
132
133
134
135
136
137
138 if ((sbi->mntflag & JFS_INLINELOG)) {
139 if (newLogSize == 0) {
140
141
142
143
144 newLogSize = newLVSize >> 8;
145 t32 = (1 << (20 - sbi->l2bsize)) - 1;
146 newLogSize = (newLogSize + t32) & ~t32;
147 newLogSize =
148 min(newLogSize, MEGABYTE32 >> sbi->l2bsize);
149 } else {
150
151
152
153
154
155
156 newLogSize = (newLogSize * MEGABYTE) >> sbi->l2bsize;
157 }
158
159 } else
160 newLogSize = 0;
161
162 newLogAddress = newLVSize - newLogSize;
163
164
165
166
167
168
169
170
171
172
173
174 t64 = ((newLVSize - newLogSize + BPERDMAP - 1) >> L2BPERDMAP)
175 << L2BPERDMAP;
176 t32 = DIV_ROUND_UP(t64, BITSPERPAGE) + 1 + 50;
177 newFSCKSize = t32 << sbi->l2nbperpage;
178 newFSCKAddress = newLogAddress - newFSCKSize;
179
180
181
182
183 newFSSize = newLVSize - newLogSize - newFSCKSize;
184
185
186 if (newFSSize < bmp->db_mapsize) {
187 rc = -EINVAL;
188 goto out;
189 }
190
191
192
193
194
195
196 if ((sbi->mntflag & JFS_INLINELOG) && (newLogAddress > oldLVSize)) {
197 if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))
198 goto out;
199 log_formatted = 1;
200 }
201
202
203
204
205
206
207
208
209
210
211 txQuiesce(sb);
212
213
214 sbi->direct_inode->i_size = sb->s_bdev->bd_inode->i_size;
215
216 if (sbi->mntflag & JFS_INLINELOG) {
217
218
219
220 lmLogShutdown(log);
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 if ((rc = readSuper(sb, &bh)))
238 goto error_out;
239 j_sb = (struct jfs_superblock *)bh->b_data;
240
241
242 j_sb->s_state |= cpu_to_le32(FM_EXTENDFS);
243 j_sb->s_xsize = cpu_to_le64(newFSSize);
244 PXDaddress(&j_sb->s_xfsckpxd, newFSCKAddress);
245 PXDlength(&j_sb->s_xfsckpxd, newFSCKSize);
246 PXDaddress(&j_sb->s_xlogpxd, newLogAddress);
247 PXDlength(&j_sb->s_xlogpxd, newLogSize);
248
249
250 mark_buffer_dirty(bh);
251 sync_dirty_buffer(bh);
252 brelse(bh);
253
254
255
256
257
258
259
260 if (!log_formatted)
261 if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))
262 goto error_out;
263
264
265
266
267 log->base = newLogAddress;
268 log->size = newLogSize >> (L2LOGPSIZE - sb->s_blocksize_bits);
269 if ((rc = lmLogInit(log)))
270 goto error_out;
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296 newMapSize = newFSSize;
297
298
299
300
301 t64 = (newMapSize - 1) + BPERDMAP;
302 newNpages = BLKTODMAPN(t64) + 1;
303
304
305
306
307
308
309
310
311 extendBmap:
312
313 mapSize = bmp->db_mapsize;
314 XAddress = mapSize;
315 XSize = newMapSize - mapSize;
316 old_agsize = bmp->db_agsize;
317
318
319 t64 = dbMapFileSizeToMapSize(ipbmap);
320 if (mapSize > t64) {
321 printk(KERN_ERR "jfs_extendfs: mapSize (0x%Lx) > t64 (0x%Lx)\n",
322 (long long) mapSize, (long long) t64);
323 rc = -EIO;
324 goto error_out;
325 }
326 nblocks = min(t64 - mapSize, XSize);
327
328
329
330
331
332
333
334
335 if ((rc = dbExtendFS(ipbmap, XAddress, nblocks)))
336 goto error_out;
337
338 agsizechanged |= (bmp->db_agsize != old_agsize);
339
340
341
342
343
344
345 XSize -= nblocks;
346
347
348
349
350
351
352
353
354
355 nPages = ipbmap->i_size >> L2PSIZE;
356
357
358 if (nPages == newNpages)
359 goto finalizeBmap;
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382 filemap_fdatawait(ipbmap->i_mapping);
383 filemap_write_and_wait(ipbmap->i_mapping);
384 diWriteSpecial(ipbmap, 0);
385
386 newPage = nPages;
387 xoff = newPage << sbi->l2nbperpage;
388 xlen = (newNpages - nPages) << sbi->l2nbperpage;
389 xlen = min(xlen, (int) nblocks) & ~(sbi->nbperpage - 1);
390 xaddr = XAddress;
391
392 tid = txBegin(sb, COMMIT_FORCE);
393
394 if ((rc = xtAppend(tid, ipbmap, 0, xoff, nblocks, &xlen, &xaddr, 0))) {
395 txEnd(tid);
396 goto error_out;
397 }
398
399 ipbmap->i_size += xlen << sbi->l2bsize;
400 inode_add_bytes(ipbmap, xlen << sbi->l2bsize);
401
402 iplist[0] = ipbmap;
403 rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
404
405 txEnd(tid);
406
407 if (rc)
408 goto error_out;
409
410
411
412
413
414
415
416
417
418
419
420
421 if (XSize)
422 goto extendBmap;
423
424 finalizeBmap:
425
426 dbFinalizeBmap(ipbmap);
427
428
429
430
431
432
433
434
435
436
437
438
439 if (agsizechanged) {
440 if ((rc = diExtendFS(ipimap, ipbmap)))
441 goto error_out;
442
443
444 if ((rc = diSync(ipimap)))
445 goto error_out;
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467 if ((rc = dbSync(ipbmap)))
468 goto error_out;
469
470
471
472
473
474 ipbmap2 = diReadSpecial(sb, BMAP_I, 1);
475 if (ipbmap2 == NULL) {
476 printk(KERN_ERR "jfs_extendfs: diReadSpecial(bmap) failed\n");
477 goto error_out;
478 }
479 memcpy(&JFS_IP(ipbmap2)->i_xtroot, &JFS_IP(ipbmap)->i_xtroot, 288);
480 ipbmap2->i_size = ipbmap->i_size;
481 ipbmap2->i_blocks = ipbmap->i_blocks;
482
483 diWriteSpecial(ipbmap2, 1);
484 diFreeSpecial(ipbmap2);
485
486
487
488
489 if ((rc = readSuper(sb, &bh)))
490 goto error_out;
491 j_sb = (struct jfs_superblock *)bh->b_data;
492
493
494 j_sb->s_state &= cpu_to_le32(~FM_EXTENDFS);
495 j_sb->s_size = cpu_to_le64(bmp->db_mapsize <<
496 le16_to_cpu(j_sb->s_l2bfactor));
497 j_sb->s_agsize = cpu_to_le32(bmp->db_agsize);
498
499
500 if (sbi->mntflag & JFS_INLINELOG) {
501 PXDaddress(&(j_sb->s_logpxd), newLogAddress);
502 PXDlength(&(j_sb->s_logpxd), newLogSize);
503 }
504
505
506 j_sb->s_logserial = cpu_to_le32(log->serial);
507
508
509 PXDaddress(&(j_sb->s_fsckpxd), newFSCKAddress);
510 PXDlength(&(j_sb->s_fsckpxd), newFSCKSize);
511 j_sb->s_fscklog = 1;
512
513
514
515 bh2 = sb_bread(sb, SUPER2_OFF >> sb->s_blocksize_bits);
516 if (bh2) {
517 j_sb2 = (struct jfs_superblock *)bh2->b_data;
518 memcpy(j_sb2, j_sb, sizeof (struct jfs_superblock));
519
520 mark_buffer_dirty(bh);
521 sync_dirty_buffer(bh2);
522 brelse(bh2);
523 }
524
525
526 mark_buffer_dirty(bh);
527 sync_dirty_buffer(bh);
528 brelse(bh);
529
530 goto resume;
531
532 error_out:
533 jfs_error(sb, "jfs_extendfs");
534
535 resume:
536
537
538
539 txResume(sb);
540
541 out:
542 return rc;
543}
544