0001
0002
0003
0004
0005
0006 #include <linux/fs.h>
0007 #include <linux/buffer_head.h>
0008 #include <linux/quotaops.h>
0009 #include <linux/blkdev.h>
0010 #include "jfs_incore.h"
0011 #include "jfs_filsys.h"
0012 #include "jfs_metapage.h"
0013 #include "jfs_dinode.h"
0014 #include "jfs_imap.h"
0015 #include "jfs_dmap.h"
0016 #include "jfs_superblock.h"
0017 #include "jfs_txnmgr.h"
0018 #include "jfs_debug.h"
0019
0020 #define BITSPERPAGE (PSIZE << 3)
0021 #define L2MEGABYTE 20
0022 #define MEGABYTE (1 << L2MEGABYTE)
0023 #define MEGABYTE32 (MEGABYTE << 5)
0024
0025
0026 #define BLKTODMAPN(b)\
0027 (((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1)
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050 int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize)
0051 {
0052 int rc = 0;
0053 struct jfs_sb_info *sbi = JFS_SBI(sb);
0054 struct inode *ipbmap = sbi->ipbmap;
0055 struct inode *ipbmap2;
0056 struct inode *ipimap = sbi->ipimap;
0057 struct jfs_log *log = sbi->log;
0058 struct bmap *bmp = sbi->bmap;
0059 s64 newLogAddress, newFSCKAddress;
0060 int newFSCKSize;
0061 s64 newMapSize = 0, mapSize;
0062 s64 XAddress, XSize, nblocks, xoff, xaddr, t64;
0063 s64 oldLVSize;
0064 s64 newFSSize;
0065 s64 VolumeSize;
0066 int newNpages = 0, nPages, newPage, xlen, t32;
0067 int tid;
0068 int log_formatted = 0;
0069 struct inode *iplist[1];
0070 struct jfs_superblock *j_sb, *j_sb2;
0071 s64 old_agsize;
0072 int agsizechanged = 0;
0073 struct buffer_head *bh, *bh2;
0074
0075
0076
0077 if (sbi->mntflag & JFS_INLINELOG)
0078 oldLVSize = addressPXD(&sbi->logpxd) + lengthPXD(&sbi->logpxd);
0079 else
0080 oldLVSize = addressPXD(&sbi->fsckpxd) +
0081 lengthPXD(&sbi->fsckpxd);
0082
0083 if (oldLVSize >= newLVSize) {
0084 printk(KERN_WARNING
0085 "jfs_extendfs: volume hasn't grown, returning\n");
0086 goto out;
0087 }
0088
0089 VolumeSize = sb_bdev_nr_blocks(sb);
0090 if (VolumeSize) {
0091 if (newLVSize > VolumeSize) {
0092 printk(KERN_WARNING "jfs_extendfs: invalid size\n");
0093 rc = -EINVAL;
0094 goto out;
0095 }
0096 } else {
0097
0098 bh = sb_bread(sb, newLVSize - 1);
0099 if (!bh) {
0100 printk(KERN_WARNING "jfs_extendfs: invalid size\n");
0101 rc = -EINVAL;
0102 goto out;
0103 }
0104 bforget(bh);
0105 }
0106
0107
0108
0109 if (isReadOnly(ipbmap)) {
0110 printk(KERN_WARNING "jfs_extendfs: read-only file system\n");
0111 rc = -EROFS;
0112 goto out;
0113 }
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125 if ((sbi->mntflag & JFS_INLINELOG)) {
0126 if (newLogSize == 0) {
0127
0128
0129
0130
0131 newLogSize = newLVSize >> 8;
0132 t32 = (1 << (20 - sbi->l2bsize)) - 1;
0133 newLogSize = (newLogSize + t32) & ~t32;
0134 newLogSize =
0135 min(newLogSize, MEGABYTE32 >> sbi->l2bsize);
0136 } else {
0137
0138
0139
0140
0141
0142
0143 newLogSize = (newLogSize * MEGABYTE) >> sbi->l2bsize;
0144 }
0145
0146 } else
0147 newLogSize = 0;
0148
0149 newLogAddress = newLVSize - newLogSize;
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161 t64 = ((newLVSize - newLogSize + BPERDMAP - 1) >> L2BPERDMAP)
0162 << L2BPERDMAP;
0163 t32 = DIV_ROUND_UP(t64, BITSPERPAGE) + 1 + 50;
0164 newFSCKSize = t32 << sbi->l2nbperpage;
0165 newFSCKAddress = newLogAddress - newFSCKSize;
0166
0167
0168
0169
0170 newFSSize = newLVSize - newLogSize - newFSCKSize;
0171
0172
0173 if (newFSSize < bmp->db_mapsize) {
0174 rc = -EINVAL;
0175 goto out;
0176 }
0177
0178
0179
0180
0181
0182
0183 if ((sbi->mntflag & JFS_INLINELOG) && (newLogAddress > oldLVSize)) {
0184 if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))
0185 goto out;
0186 log_formatted = 1;
0187 }
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198 txQuiesce(sb);
0199
0200
0201 sbi->direct_inode->i_size = bdev_nr_bytes(sb->s_bdev);
0202
0203 if (sbi->mntflag & JFS_INLINELOG) {
0204
0205
0206
0207 lmLogShutdown(log);
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224 if ((rc = readSuper(sb, &bh)))
0225 goto error_out;
0226 j_sb = (struct jfs_superblock *)bh->b_data;
0227
0228
0229 j_sb->s_state |= cpu_to_le32(FM_EXTENDFS);
0230 j_sb->s_xsize = cpu_to_le64(newFSSize);
0231 PXDaddress(&j_sb->s_xfsckpxd, newFSCKAddress);
0232 PXDlength(&j_sb->s_xfsckpxd, newFSCKSize);
0233 PXDaddress(&j_sb->s_xlogpxd, newLogAddress);
0234 PXDlength(&j_sb->s_xlogpxd, newLogSize);
0235
0236
0237 mark_buffer_dirty(bh);
0238 sync_dirty_buffer(bh);
0239 brelse(bh);
0240
0241
0242
0243
0244
0245
0246
0247 if (!log_formatted)
0248 if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))
0249 goto error_out;
0250
0251
0252
0253
0254 log->base = newLogAddress;
0255 log->size = newLogSize >> (L2LOGPSIZE - sb->s_blocksize_bits);
0256 if ((rc = lmLogInit(log)))
0257 goto error_out;
0258 }
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283 newMapSize = newFSSize;
0284
0285
0286
0287
0288 t64 = (newMapSize - 1) + BPERDMAP;
0289 newNpages = BLKTODMAPN(t64) + 1;
0290
0291
0292
0293
0294
0295
0296
0297
0298 extendBmap:
0299
0300 mapSize = bmp->db_mapsize;
0301 XAddress = mapSize;
0302 XSize = newMapSize - mapSize;
0303 old_agsize = bmp->db_agsize;
0304
0305
0306 t64 = dbMapFileSizeToMapSize(ipbmap);
0307 if (mapSize > t64) {
0308 printk(KERN_ERR "jfs_extendfs: mapSize (0x%Lx) > t64 (0x%Lx)\n",
0309 (long long) mapSize, (long long) t64);
0310 rc = -EIO;
0311 goto error_out;
0312 }
0313 nblocks = min(t64 - mapSize, XSize);
0314
0315
0316
0317
0318
0319
0320
0321
0322 if ((rc = dbExtendFS(ipbmap, XAddress, nblocks)))
0323 goto error_out;
0324
0325 agsizechanged |= (bmp->db_agsize != old_agsize);
0326
0327
0328
0329
0330
0331
0332 XSize -= nblocks;
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342 nPages = ipbmap->i_size >> L2PSIZE;
0343
0344
0345 if (nPages == newNpages)
0346 goto finalizeBmap;
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369 rc = filemap_fdatawait(ipbmap->i_mapping);
0370 if (rc)
0371 goto error_out;
0372
0373 rc = filemap_write_and_wait(ipbmap->i_mapping);
0374 if (rc)
0375 goto error_out;
0376
0377 diWriteSpecial(ipbmap, 0);
0378
0379 newPage = nPages;
0380 xoff = newPage << sbi->l2nbperpage;
0381 xlen = (newNpages - nPages) << sbi->l2nbperpage;
0382 xlen = min(xlen, (int) nblocks) & ~(sbi->nbperpage - 1);
0383 xaddr = XAddress;
0384
0385 tid = txBegin(sb, COMMIT_FORCE);
0386
0387 if ((rc = xtAppend(tid, ipbmap, 0, xoff, nblocks, &xlen, &xaddr, 0))) {
0388 txEnd(tid);
0389 goto error_out;
0390 }
0391
0392 ipbmap->i_size += xlen << sbi->l2bsize;
0393 inode_add_bytes(ipbmap, xlen << sbi->l2bsize);
0394
0395 iplist[0] = ipbmap;
0396 rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
0397
0398 txEnd(tid);
0399
0400 if (rc)
0401 goto error_out;
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414 if (XSize)
0415 goto extendBmap;
0416
0417 finalizeBmap:
0418
0419 dbFinalizeBmap(ipbmap);
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432 if (agsizechanged) {
0433 if ((rc = diExtendFS(ipimap, ipbmap)))
0434 goto error_out;
0435
0436
0437 if ((rc = diSync(ipimap)))
0438 goto error_out;
0439 }
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460 if ((rc = dbSync(ipbmap)))
0461 goto error_out;
0462
0463
0464
0465
0466
0467 ipbmap2 = diReadSpecial(sb, BMAP_I, 1);
0468 if (ipbmap2 == NULL) {
0469 printk(KERN_ERR "jfs_extendfs: diReadSpecial(bmap) failed\n");
0470 goto error_out;
0471 }
0472 memcpy(&JFS_IP(ipbmap2)->i_xtroot, &JFS_IP(ipbmap)->i_xtroot, 288);
0473 ipbmap2->i_size = ipbmap->i_size;
0474 ipbmap2->i_blocks = ipbmap->i_blocks;
0475
0476 diWriteSpecial(ipbmap2, 1);
0477 diFreeSpecial(ipbmap2);
0478
0479
0480
0481
0482 if ((rc = readSuper(sb, &bh)))
0483 goto error_out;
0484 j_sb = (struct jfs_superblock *)bh->b_data;
0485
0486
0487 j_sb->s_state &= cpu_to_le32(~FM_EXTENDFS);
0488 j_sb->s_size = cpu_to_le64(bmp->db_mapsize <<
0489 le16_to_cpu(j_sb->s_l2bfactor));
0490 j_sb->s_agsize = cpu_to_le32(bmp->db_agsize);
0491
0492
0493 if (sbi->mntflag & JFS_INLINELOG) {
0494 PXDaddress(&(j_sb->s_logpxd), newLogAddress);
0495 PXDlength(&(j_sb->s_logpxd), newLogSize);
0496 }
0497
0498
0499 j_sb->s_logserial = cpu_to_le32(log->serial);
0500
0501
0502 PXDaddress(&(j_sb->s_fsckpxd), newFSCKAddress);
0503 PXDlength(&(j_sb->s_fsckpxd), newFSCKSize);
0504 j_sb->s_fscklog = 1;
0505
0506
0507
0508 bh2 = sb_bread(sb, SUPER2_OFF >> sb->s_blocksize_bits);
0509 if (bh2) {
0510 j_sb2 = (struct jfs_superblock *)bh2->b_data;
0511 memcpy(j_sb2, j_sb, sizeof (struct jfs_superblock));
0512
0513 mark_buffer_dirty(bh);
0514 sync_dirty_buffer(bh2);
0515 brelse(bh2);
0516 }
0517
0518
0519 mark_buffer_dirty(bh);
0520 sync_dirty_buffer(bh);
0521 brelse(bh);
0522
0523 goto resume;
0524
0525 error_out:
0526 jfs_error(sb, "\n");
0527
0528 resume:
0529
0530
0531
0532 txResume(sb);
0533
0534 out:
0535 return rc;
0536 }