Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *   Copyright (C) International Business Machines  Corp., 2000-2004
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 /* convert block number to bmap file page number */
0026 #define BLKTODMAPN(b)\
0027     (((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1)
0028 
0029 /*
0030  *  jfs_extendfs()
0031  *
0032  * function: extend file system;
0033  *
0034  *   |-------------------------------|----------|----------|
0035  *   file system space               fsck       inline log
0036  *                                   workspace  space
0037  *
0038  * input:
0039  *  new LVSize: in LV blocks (required)
0040  *  new LogSize: in LV blocks (optional)
0041  *  new FSSize: in LV blocks (optional)
0042  *
0043  * new configuration:
0044  * 1. set new LogSize as specified or default from new LVSize;
0045  * 2. compute new FSCKSize from new LVSize;
0046  * 3. set new FSSize as MIN(FSSize, LVSize-(LogSize+FSCKSize)) where
0047  *    assert(new FSSize >= old FSSize),
0048  *    i.e., file system must not be shrunk;
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     /* If the volume hasn't grown, get out now */
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         /* check the device */
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     /* Can't extend write-protected drive */
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      *  reconfigure LV spaces
0117      *  ---------------------
0118      *
0119      * validate new size, or, if not specified, determine new size
0120      */
0121 
0122     /*
0123      * reconfigure inline log space:
0124      */
0125     if ((sbi->mntflag & JFS_INLINELOG)) {
0126         if (newLogSize == 0) {
0127             /*
0128              * no size specified: default to 1/256 of aggregate
0129              * size; rounded up to a megabyte boundary;
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              * convert the newLogSize to fs blocks.
0139              *
0140              * Since this is given in megabytes, it will always be
0141              * an even number of pages.
0142              */
0143             newLogSize = (newLogSize * MEGABYTE) >> sbi->l2bsize;
0144         }
0145 
0146     } else
0147         newLogSize = 0;
0148 
0149     newLogAddress = newLVSize - newLogSize;
0150 
0151     /*
0152      * reconfigure fsck work space:
0153      *
0154      * configure it to the end of the logical volume regardless of
0155      * whether file system extends to the end of the aggregate;
0156      * Need enough 4k pages to cover:
0157      *  - 1 bit per block in aggregate rounded up to BPERDMAP boundary
0158      *  - 1 extra page to handle control page and intermediate level pages
0159      *  - 50 extra pages for the chkdsk service log
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      * compute new file system space;
0169      */
0170     newFSSize = newLVSize - newLogSize - newFSCKSize;
0171 
0172     /* file system cannot be shrunk */
0173     if (newFSSize < bmp->db_mapsize) {
0174         rc = -EINVAL;
0175         goto out;
0176     }
0177 
0178     /*
0179      * If we're expanding enough that the inline log does not overlap
0180      * the old one, we can format the new log before we quiesce the
0181      * filesystem.
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      *  quiesce file system
0190      *
0191      * (prepare to move the inline log and to prevent map update)
0192      *
0193      * block any new transactions and wait for completion of
0194      * all wip transactions and flush modified pages s.t.
0195      * on-disk file system is in consistent state and
0196      * log is not required for recovery.
0197      */
0198     txQuiesce(sb);
0199 
0200     /* Reset size of direct inode */
0201     sbi->direct_inode->i_size = bdev_nr_bytes(sb->s_bdev);
0202 
0203     if (sbi->mntflag & JFS_INLINELOG) {
0204         /*
0205          * deactivate old inline log
0206          */
0207         lmLogShutdown(log);
0208 
0209         /*
0210          * mark on-disk super block for fs in transition;
0211          *
0212          * update on-disk superblock for the new space configuration
0213          * of inline log space and fsck work space descriptors:
0214          * N.B. FS descriptor is NOT updated;
0215          *
0216          * crash recovery:
0217          * logredo(): if FM_EXTENDFS, return to fsck() for cleanup;
0218          * fsck(): if FM_EXTENDFS, reformat inline log and fsck
0219          * workspace from superblock inline log descriptor and fsck
0220          * workspace descriptor;
0221          */
0222 
0223         /* read in superblock */
0224         if ((rc = readSuper(sb, &bh)))
0225             goto error_out;
0226         j_sb = (struct jfs_superblock *)bh->b_data;
0227 
0228         /* mark extendfs() in progress */
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         /* synchronously update superblock */
0237         mark_buffer_dirty(bh);
0238         sync_dirty_buffer(bh);
0239         brelse(bh);
0240 
0241         /*
0242          * format new inline log synchronously;
0243          *
0244          * crash recovery: if log move in progress,
0245          * reformat log and exit success;
0246          */
0247         if (!log_formatted)
0248             if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))
0249                 goto error_out;
0250 
0251         /*
0252          * activate new log
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      *  extend block allocation map
0262      *  ---------------------------
0263      *
0264      * extendfs() for new extension, retry after crash recovery;
0265      *
0266      * note: both logredo() and fsck() rebuild map from
0267      * the bitmap and configuration parameter from superblock
0268      * (disregarding all other control information in the map);
0269      *
0270      * superblock:
0271      *  s_size: aggregate size in physical blocks;
0272      */
0273     /*
0274      *  compute the new block allocation map configuration
0275      *
0276      * map dinode:
0277      *  di_size: map file size in byte;
0278      *  di_nblocks: number of blocks allocated for map file;
0279      *  di_mapsize: number of blocks in aggregate (covered by map);
0280      * map control page:
0281      *  db_mapsize: number of blocks in aggregate (covered by map);
0282      */
0283     newMapSize = newFSSize;
0284     /* number of data pages of new bmap file:
0285      * roundup new size to full dmap page boundary and
0286      * add 1 extra dmap page for next extendfs()
0287      */
0288     t64 = (newMapSize - 1) + BPERDMAP;
0289     newNpages = BLKTODMAPN(t64) + 1;
0290 
0291     /*
0292      *  extend map from current map (WITHOUT growing mapfile)
0293      *
0294      * map new extension with unmapped part of the last partial
0295      * dmap page, if applicable, and extra page(s) allocated
0296      * at end of bmap by mkfs() or previous extendfs();
0297      */
0298       extendBmap:
0299     /* compute number of blocks requested to extend */
0300     mapSize = bmp->db_mapsize;
0301     XAddress = mapSize; /* eXtension Address */
0302     XSize = newMapSize - mapSize;   /* eXtension Size */
0303     old_agsize = bmp->db_agsize;    /* We need to know if this changes */
0304 
0305     /* compute number of blocks that can be extended by current mapfile */
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      * update map pages for new extension:
0317      *
0318      * update/init dmap and bubble up the control hierarchy
0319      * incrementally fold up dmaps into upper levels;
0320      * update bmap control page;
0321      */
0322     if ((rc = dbExtendFS(ipbmap, XAddress, nblocks)))
0323         goto error_out;
0324 
0325     agsizechanged |= (bmp->db_agsize != old_agsize);
0326 
0327     /*
0328      * the map now has extended to cover additional nblocks:
0329      * dn_mapsize = oldMapsize + nblocks;
0330      */
0331     /* ipbmap->i_mapsize += nblocks; */
0332     XSize -= nblocks;
0333 
0334     /*
0335      *  grow map file to cover remaining extension
0336      *  and/or one extra dmap page for next extendfs();
0337      *
0338      * allocate new map pages and its backing blocks, and
0339      * update map file xtree
0340      */
0341     /* compute number of data pages of current bmap file */
0342     nPages = ipbmap->i_size >> L2PSIZE;
0343 
0344     /* need to grow map file ? */
0345     if (nPages == newNpages)
0346         goto finalizeBmap;
0347 
0348     /*
0349      * grow bmap file for the new map pages required:
0350      *
0351      * allocate growth at the start of newly extended region;
0352      * bmap file only grows sequentially, i.e., both data pages
0353      * and possibly xtree index pages may grow in append mode,
0354      * s.t. logredo() can reconstruct pre-extension state
0355      * by washing away bmap file of pages outside s_size boundary;
0356      */
0357     /*
0358      * journal map file growth as if a regular file growth:
0359      * (note: bmap is created with di_mode = IFJOURNAL|IFREG);
0360      *
0361      * journaling of bmap file growth is not required since
0362      * logredo() do/can not use log records of bmap file growth
0363      * but it provides careful write semantics, pmap update, etc.;
0364      */
0365     /* synchronous write of data pages: bmap data pages are
0366      * cached in meta-data cache, and not written out
0367      * by txCommit();
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;   /* first new page number */
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     /* update bmap file size */
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      * map file has been grown now to cover extension to further out;
0405      * di_size = new map file size;
0406      *
0407      * if huge extension, the previous extension based on previous
0408      * map file size may not have been sufficient to cover whole extension
0409      * (it could have been used up for new map pages),
0410      * but the newly grown map file now covers lot bigger new free space
0411      * available for further extension of map;
0412      */
0413     /* any more blocks to extend ? */
0414     if (XSize)
0415         goto extendBmap;
0416 
0417       finalizeBmap:
0418     /* finalize bmap */
0419     dbFinalizeBmap(ipbmap);
0420 
0421     /*
0422      *  update inode allocation map
0423      *  ---------------------------
0424      *
0425      * move iag lists from old to new iag;
0426      * agstart field is not updated for logredo() to reconstruct
0427      * iag lists if system crash occurs.
0428      * (computation of ag number from agstart based on agsize
0429      * will correctly identify the new ag);
0430      */
0431     /* if new AG size the same as old AG size, done! */
0432     if (agsizechanged) {
0433         if ((rc = diExtendFS(ipimap, ipbmap)))
0434             goto error_out;
0435 
0436         /* finalize imap */
0437         if ((rc = diSync(ipimap)))
0438             goto error_out;
0439     }
0440 
0441     /*
0442      *  finalize
0443      *  --------
0444      *
0445      * extension is committed when on-disk super block is
0446      * updated with new descriptors: logredo will recover
0447      * crash before it to pre-extension state;
0448      */
0449 
0450     /* sync log to skip log replay of bmap file growth transaction; */
0451     /* lmLogSync(log, 1); */
0452 
0453     /*
0454      * synchronous write bmap global control page;
0455      * for crash before completion of write
0456      * logredo() will recover to pre-extendfs state;
0457      * for crash after completion of write,
0458      * logredo() will recover post-extendfs state;
0459      */
0460     if ((rc = dbSync(ipbmap)))
0461         goto error_out;
0462 
0463     /*
0464      * copy primary bmap inode to secondary bmap inode
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      *  update superblock
0481      */
0482     if ((rc = readSuper(sb, &bh)))
0483         goto error_out;
0484     j_sb = (struct jfs_superblock *)bh->b_data;
0485 
0486     /* mark extendfs() completion */
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     /* update inline log space descriptor */
0493     if (sbi->mntflag & JFS_INLINELOG) {
0494         PXDaddress(&(j_sb->s_logpxd), newLogAddress);
0495         PXDlength(&(j_sb->s_logpxd), newLogSize);
0496     }
0497 
0498     /* record log's mount serial number */
0499     j_sb->s_logserial = cpu_to_le32(log->serial);
0500 
0501     /* update fsck work space descriptor */
0502     PXDaddress(&(j_sb->s_fsckpxd), newFSCKAddress);
0503     PXDlength(&(j_sb->s_fsckpxd), newFSCKSize);
0504     j_sb->s_fscklog = 1;
0505     /* sb->s_fsckloglen remains the same */
0506 
0507     /* Update secondary superblock */
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     /* write primary superblock */
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      *  resume file system transactions
0531      */
0532     txResume(sb);
0533 
0534       out:
0535     return rc;
0536 }