162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2000-2004 462306a36Sopenharmony_ci*/ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/fs.h> 762306a36Sopenharmony_ci#include <linux/buffer_head.h> 862306a36Sopenharmony_ci#include <linux/quotaops.h> 962306a36Sopenharmony_ci#include <linux/blkdev.h> 1062306a36Sopenharmony_ci#include "jfs_incore.h" 1162306a36Sopenharmony_ci#include "jfs_filsys.h" 1262306a36Sopenharmony_ci#include "jfs_metapage.h" 1362306a36Sopenharmony_ci#include "jfs_dinode.h" 1462306a36Sopenharmony_ci#include "jfs_imap.h" 1562306a36Sopenharmony_ci#include "jfs_dmap.h" 1662306a36Sopenharmony_ci#include "jfs_superblock.h" 1762306a36Sopenharmony_ci#include "jfs_txnmgr.h" 1862306a36Sopenharmony_ci#include "jfs_debug.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define BITSPERPAGE (PSIZE << 3) 2162306a36Sopenharmony_ci#define L2MEGABYTE 20 2262306a36Sopenharmony_ci#define MEGABYTE (1 << L2MEGABYTE) 2362306a36Sopenharmony_ci#define MEGABYTE32 (MEGABYTE << 5) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* convert block number to bmap file page number */ 2662306a36Sopenharmony_ci#define BLKTODMAPN(b)\ 2762306a36Sopenharmony_ci (((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * jfs_extendfs() 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * function: extend file system; 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * |-------------------------------|----------|----------| 3562306a36Sopenharmony_ci * file system space fsck inline log 3662306a36Sopenharmony_ci * workspace space 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * input: 3962306a36Sopenharmony_ci * new LVSize: in LV blocks (required) 4062306a36Sopenharmony_ci * new LogSize: in LV blocks (optional) 4162306a36Sopenharmony_ci * new FSSize: in LV blocks (optional) 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * new configuration: 4462306a36Sopenharmony_ci * 1. set new LogSize as specified or default from new LVSize; 4562306a36Sopenharmony_ci * 2. compute new FSCKSize from new LVSize; 4662306a36Sopenharmony_ci * 3. set new FSSize as MIN(FSSize, LVSize-(LogSize+FSCKSize)) where 4762306a36Sopenharmony_ci * assert(new FSSize >= old FSSize), 4862306a36Sopenharmony_ci * i.e., file system must not be shrunk; 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ciint jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci int rc = 0; 5362306a36Sopenharmony_ci struct jfs_sb_info *sbi = JFS_SBI(sb); 5462306a36Sopenharmony_ci struct inode *ipbmap = sbi->ipbmap; 5562306a36Sopenharmony_ci struct inode *ipbmap2; 5662306a36Sopenharmony_ci struct inode *ipimap = sbi->ipimap; 5762306a36Sopenharmony_ci struct jfs_log *log = sbi->log; 5862306a36Sopenharmony_ci struct bmap *bmp = sbi->bmap; 5962306a36Sopenharmony_ci s64 newLogAddress, newFSCKAddress; 6062306a36Sopenharmony_ci int newFSCKSize; 6162306a36Sopenharmony_ci s64 newMapSize = 0, mapSize; 6262306a36Sopenharmony_ci s64 XAddress, XSize, nblocks, xoff, xaddr, t64; 6362306a36Sopenharmony_ci s64 oldLVSize; 6462306a36Sopenharmony_ci s64 newFSSize; 6562306a36Sopenharmony_ci s64 VolumeSize; 6662306a36Sopenharmony_ci int newNpages = 0, nPages, newPage, xlen, t32; 6762306a36Sopenharmony_ci int tid; 6862306a36Sopenharmony_ci int log_formatted = 0; 6962306a36Sopenharmony_ci struct inode *iplist[1]; 7062306a36Sopenharmony_ci struct jfs_superblock *j_sb, *j_sb2; 7162306a36Sopenharmony_ci s64 old_agsize; 7262306a36Sopenharmony_ci int agsizechanged = 0; 7362306a36Sopenharmony_ci struct buffer_head *bh, *bh2; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* If the volume hasn't grown, get out now */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (sbi->mntflag & JFS_INLINELOG) 7862306a36Sopenharmony_ci oldLVSize = addressPXD(&sbi->logpxd) + lengthPXD(&sbi->logpxd); 7962306a36Sopenharmony_ci else 8062306a36Sopenharmony_ci oldLVSize = addressPXD(&sbi->fsckpxd) + 8162306a36Sopenharmony_ci lengthPXD(&sbi->fsckpxd); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (oldLVSize >= newLVSize) { 8462306a36Sopenharmony_ci printk(KERN_WARNING 8562306a36Sopenharmony_ci "jfs_extendfs: volume hasn't grown, returning\n"); 8662306a36Sopenharmony_ci goto out; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci VolumeSize = sb_bdev_nr_blocks(sb); 9062306a36Sopenharmony_ci if (VolumeSize) { 9162306a36Sopenharmony_ci if (newLVSize > VolumeSize) { 9262306a36Sopenharmony_ci printk(KERN_WARNING "jfs_extendfs: invalid size\n"); 9362306a36Sopenharmony_ci rc = -EINVAL; 9462306a36Sopenharmony_ci goto out; 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci } else { 9762306a36Sopenharmony_ci /* check the device */ 9862306a36Sopenharmony_ci bh = sb_bread(sb, newLVSize - 1); 9962306a36Sopenharmony_ci if (!bh) { 10062306a36Sopenharmony_ci printk(KERN_WARNING "jfs_extendfs: invalid size\n"); 10162306a36Sopenharmony_ci rc = -EINVAL; 10262306a36Sopenharmony_ci goto out; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci bforget(bh); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* Can't extend write-protected drive */ 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (isReadOnly(ipbmap)) { 11062306a36Sopenharmony_ci printk(KERN_WARNING "jfs_extendfs: read-only file system\n"); 11162306a36Sopenharmony_ci rc = -EROFS; 11262306a36Sopenharmony_ci goto out; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * reconfigure LV spaces 11762306a36Sopenharmony_ci * --------------------- 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * validate new size, or, if not specified, determine new size 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * reconfigure inline log space: 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci if ((sbi->mntflag & JFS_INLINELOG)) { 12662306a36Sopenharmony_ci if (newLogSize == 0) { 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * no size specified: default to 1/256 of aggregate 12962306a36Sopenharmony_ci * size; rounded up to a megabyte boundary; 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci newLogSize = newLVSize >> 8; 13262306a36Sopenharmony_ci t32 = (1 << (20 - sbi->l2bsize)) - 1; 13362306a36Sopenharmony_ci newLogSize = (newLogSize + t32) & ~t32; 13462306a36Sopenharmony_ci newLogSize = 13562306a36Sopenharmony_ci min(newLogSize, MEGABYTE32 >> sbi->l2bsize); 13662306a36Sopenharmony_ci } else { 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * convert the newLogSize to fs blocks. 13962306a36Sopenharmony_ci * 14062306a36Sopenharmony_ci * Since this is given in megabytes, it will always be 14162306a36Sopenharmony_ci * an even number of pages. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci newLogSize = (newLogSize * MEGABYTE) >> sbi->l2bsize; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci } else 14762306a36Sopenharmony_ci newLogSize = 0; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci newLogAddress = newLVSize - newLogSize; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * reconfigure fsck work space: 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * configure it to the end of the logical volume regardless of 15562306a36Sopenharmony_ci * whether file system extends to the end of the aggregate; 15662306a36Sopenharmony_ci * Need enough 4k pages to cover: 15762306a36Sopenharmony_ci * - 1 bit per block in aggregate rounded up to BPERDMAP boundary 15862306a36Sopenharmony_ci * - 1 extra page to handle control page and intermediate level pages 15962306a36Sopenharmony_ci * - 50 extra pages for the chkdsk service log 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci t64 = ((newLVSize - newLogSize + BPERDMAP - 1) >> L2BPERDMAP) 16262306a36Sopenharmony_ci << L2BPERDMAP; 16362306a36Sopenharmony_ci t32 = DIV_ROUND_UP(t64, BITSPERPAGE) + 1 + 50; 16462306a36Sopenharmony_ci newFSCKSize = t32 << sbi->l2nbperpage; 16562306a36Sopenharmony_ci newFSCKAddress = newLogAddress - newFSCKSize; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* 16862306a36Sopenharmony_ci * compute new file system space; 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci newFSSize = newLVSize - newLogSize - newFSCKSize; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* file system cannot be shrunk */ 17362306a36Sopenharmony_ci if (newFSSize < bmp->db_mapsize) { 17462306a36Sopenharmony_ci rc = -EINVAL; 17562306a36Sopenharmony_ci goto out; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * If we're expanding enough that the inline log does not overlap 18062306a36Sopenharmony_ci * the old one, we can format the new log before we quiesce the 18162306a36Sopenharmony_ci * filesystem. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci if ((sbi->mntflag & JFS_INLINELOG) && (newLogAddress > oldLVSize)) { 18462306a36Sopenharmony_ci if ((rc = lmLogFormat(log, newLogAddress, newLogSize))) 18562306a36Sopenharmony_ci goto out; 18662306a36Sopenharmony_ci log_formatted = 1; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci /* 18962306a36Sopenharmony_ci * quiesce file system 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * (prepare to move the inline log and to prevent map update) 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * block any new transactions and wait for completion of 19462306a36Sopenharmony_ci * all wip transactions and flush modified pages s.t. 19562306a36Sopenharmony_ci * on-disk file system is in consistent state and 19662306a36Sopenharmony_ci * log is not required for recovery. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci txQuiesce(sb); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Reset size of direct inode */ 20162306a36Sopenharmony_ci sbi->direct_inode->i_size = bdev_nr_bytes(sb->s_bdev); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (sbi->mntflag & JFS_INLINELOG) { 20462306a36Sopenharmony_ci /* 20562306a36Sopenharmony_ci * deactivate old inline log 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ci lmLogShutdown(log); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* 21062306a36Sopenharmony_ci * mark on-disk super block for fs in transition; 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * update on-disk superblock for the new space configuration 21362306a36Sopenharmony_ci * of inline log space and fsck work space descriptors: 21462306a36Sopenharmony_ci * N.B. FS descriptor is NOT updated; 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * crash recovery: 21762306a36Sopenharmony_ci * logredo(): if FM_EXTENDFS, return to fsck() for cleanup; 21862306a36Sopenharmony_ci * fsck(): if FM_EXTENDFS, reformat inline log and fsck 21962306a36Sopenharmony_ci * workspace from superblock inline log descriptor and fsck 22062306a36Sopenharmony_ci * workspace descriptor; 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* read in superblock */ 22462306a36Sopenharmony_ci if ((rc = readSuper(sb, &bh))) 22562306a36Sopenharmony_ci goto error_out; 22662306a36Sopenharmony_ci j_sb = (struct jfs_superblock *)bh->b_data; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* mark extendfs() in progress */ 22962306a36Sopenharmony_ci j_sb->s_state |= cpu_to_le32(FM_EXTENDFS); 23062306a36Sopenharmony_ci j_sb->s_xsize = cpu_to_le64(newFSSize); 23162306a36Sopenharmony_ci PXDaddress(&j_sb->s_xfsckpxd, newFSCKAddress); 23262306a36Sopenharmony_ci PXDlength(&j_sb->s_xfsckpxd, newFSCKSize); 23362306a36Sopenharmony_ci PXDaddress(&j_sb->s_xlogpxd, newLogAddress); 23462306a36Sopenharmony_ci PXDlength(&j_sb->s_xlogpxd, newLogSize); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* synchronously update superblock */ 23762306a36Sopenharmony_ci mark_buffer_dirty(bh); 23862306a36Sopenharmony_ci sync_dirty_buffer(bh); 23962306a36Sopenharmony_ci brelse(bh); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* 24262306a36Sopenharmony_ci * format new inline log synchronously; 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci * crash recovery: if log move in progress, 24562306a36Sopenharmony_ci * reformat log and exit success; 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci if (!log_formatted) 24862306a36Sopenharmony_ci if ((rc = lmLogFormat(log, newLogAddress, newLogSize))) 24962306a36Sopenharmony_ci goto error_out; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* 25262306a36Sopenharmony_ci * activate new log 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci log->base = newLogAddress; 25562306a36Sopenharmony_ci log->size = newLogSize >> (L2LOGPSIZE - sb->s_blocksize_bits); 25662306a36Sopenharmony_ci if ((rc = lmLogInit(log))) 25762306a36Sopenharmony_ci goto error_out; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* 26162306a36Sopenharmony_ci * extend block allocation map 26262306a36Sopenharmony_ci * --------------------------- 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * extendfs() for new extension, retry after crash recovery; 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * note: both logredo() and fsck() rebuild map from 26762306a36Sopenharmony_ci * the bitmap and configuration parameter from superblock 26862306a36Sopenharmony_ci * (disregarding all other control information in the map); 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * superblock: 27162306a36Sopenharmony_ci * s_size: aggregate size in physical blocks; 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci /* 27462306a36Sopenharmony_ci * compute the new block allocation map configuration 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * map dinode: 27762306a36Sopenharmony_ci * di_size: map file size in byte; 27862306a36Sopenharmony_ci * di_nblocks: number of blocks allocated for map file; 27962306a36Sopenharmony_ci * di_mapsize: number of blocks in aggregate (covered by map); 28062306a36Sopenharmony_ci * map control page: 28162306a36Sopenharmony_ci * db_mapsize: number of blocks in aggregate (covered by map); 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ci newMapSize = newFSSize; 28462306a36Sopenharmony_ci /* number of data pages of new bmap file: 28562306a36Sopenharmony_ci * roundup new size to full dmap page boundary and 28662306a36Sopenharmony_ci * add 1 extra dmap page for next extendfs() 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci t64 = (newMapSize - 1) + BPERDMAP; 28962306a36Sopenharmony_ci newNpages = BLKTODMAPN(t64) + 1; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* 29262306a36Sopenharmony_ci * extend map from current map (WITHOUT growing mapfile) 29362306a36Sopenharmony_ci * 29462306a36Sopenharmony_ci * map new extension with unmapped part of the last partial 29562306a36Sopenharmony_ci * dmap page, if applicable, and extra page(s) allocated 29662306a36Sopenharmony_ci * at end of bmap by mkfs() or previous extendfs(); 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci extendBmap: 29962306a36Sopenharmony_ci /* compute number of blocks requested to extend */ 30062306a36Sopenharmony_ci mapSize = bmp->db_mapsize; 30162306a36Sopenharmony_ci XAddress = mapSize; /* eXtension Address */ 30262306a36Sopenharmony_ci XSize = newMapSize - mapSize; /* eXtension Size */ 30362306a36Sopenharmony_ci old_agsize = bmp->db_agsize; /* We need to know if this changes */ 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* compute number of blocks that can be extended by current mapfile */ 30662306a36Sopenharmony_ci t64 = dbMapFileSizeToMapSize(ipbmap); 30762306a36Sopenharmony_ci if (mapSize > t64) { 30862306a36Sopenharmony_ci printk(KERN_ERR "jfs_extendfs: mapSize (0x%Lx) > t64 (0x%Lx)\n", 30962306a36Sopenharmony_ci (long long) mapSize, (long long) t64); 31062306a36Sopenharmony_ci rc = -EIO; 31162306a36Sopenharmony_ci goto error_out; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci nblocks = min(t64 - mapSize, XSize); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* 31662306a36Sopenharmony_ci * update map pages for new extension: 31762306a36Sopenharmony_ci * 31862306a36Sopenharmony_ci * update/init dmap and bubble up the control hierarchy 31962306a36Sopenharmony_ci * incrementally fold up dmaps into upper levels; 32062306a36Sopenharmony_ci * update bmap control page; 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci if ((rc = dbExtendFS(ipbmap, XAddress, nblocks))) 32362306a36Sopenharmony_ci goto error_out; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci agsizechanged |= (bmp->db_agsize != old_agsize); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* 32862306a36Sopenharmony_ci * the map now has extended to cover additional nblocks: 32962306a36Sopenharmony_ci * dn_mapsize = oldMapsize + nblocks; 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_ci /* ipbmap->i_mapsize += nblocks; */ 33262306a36Sopenharmony_ci XSize -= nblocks; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* 33562306a36Sopenharmony_ci * grow map file to cover remaining extension 33662306a36Sopenharmony_ci * and/or one extra dmap page for next extendfs(); 33762306a36Sopenharmony_ci * 33862306a36Sopenharmony_ci * allocate new map pages and its backing blocks, and 33962306a36Sopenharmony_ci * update map file xtree 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci /* compute number of data pages of current bmap file */ 34262306a36Sopenharmony_ci nPages = ipbmap->i_size >> L2PSIZE; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* need to grow map file ? */ 34562306a36Sopenharmony_ci if (nPages == newNpages) 34662306a36Sopenharmony_ci goto finalizeBmap; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* 34962306a36Sopenharmony_ci * grow bmap file for the new map pages required: 35062306a36Sopenharmony_ci * 35162306a36Sopenharmony_ci * allocate growth at the start of newly extended region; 35262306a36Sopenharmony_ci * bmap file only grows sequentially, i.e., both data pages 35362306a36Sopenharmony_ci * and possibly xtree index pages may grow in append mode, 35462306a36Sopenharmony_ci * s.t. logredo() can reconstruct pre-extension state 35562306a36Sopenharmony_ci * by washing away bmap file of pages outside s_size boundary; 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ci /* 35862306a36Sopenharmony_ci * journal map file growth as if a regular file growth: 35962306a36Sopenharmony_ci * (note: bmap is created with di_mode = IFJOURNAL|IFREG); 36062306a36Sopenharmony_ci * 36162306a36Sopenharmony_ci * journaling of bmap file growth is not required since 36262306a36Sopenharmony_ci * logredo() do/can not use log records of bmap file growth 36362306a36Sopenharmony_ci * but it provides careful write semantics, pmap update, etc.; 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_ci /* synchronous write of data pages: bmap data pages are 36662306a36Sopenharmony_ci * cached in meta-data cache, and not written out 36762306a36Sopenharmony_ci * by txCommit(); 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci rc = filemap_fdatawait(ipbmap->i_mapping); 37062306a36Sopenharmony_ci if (rc) 37162306a36Sopenharmony_ci goto error_out; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci rc = filemap_write_and_wait(ipbmap->i_mapping); 37462306a36Sopenharmony_ci if (rc) 37562306a36Sopenharmony_ci goto error_out; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci diWriteSpecial(ipbmap, 0); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci newPage = nPages; /* first new page number */ 38062306a36Sopenharmony_ci xoff = newPage << sbi->l2nbperpage; 38162306a36Sopenharmony_ci xlen = (newNpages - nPages) << sbi->l2nbperpage; 38262306a36Sopenharmony_ci xlen = min(xlen, (int) nblocks) & ~(sbi->nbperpage - 1); 38362306a36Sopenharmony_ci xaddr = XAddress; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci tid = txBegin(sb, COMMIT_FORCE); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if ((rc = xtAppend(tid, ipbmap, 0, xoff, nblocks, &xlen, &xaddr, 0))) { 38862306a36Sopenharmony_ci txEnd(tid); 38962306a36Sopenharmony_ci goto error_out; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci /* update bmap file size */ 39262306a36Sopenharmony_ci ipbmap->i_size += xlen << sbi->l2bsize; 39362306a36Sopenharmony_ci inode_add_bytes(ipbmap, xlen << sbi->l2bsize); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci iplist[0] = ipbmap; 39662306a36Sopenharmony_ci rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci txEnd(tid); 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (rc) 40162306a36Sopenharmony_ci goto error_out; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* 40462306a36Sopenharmony_ci * map file has been grown now to cover extension to further out; 40562306a36Sopenharmony_ci * di_size = new map file size; 40662306a36Sopenharmony_ci * 40762306a36Sopenharmony_ci * if huge extension, the previous extension based on previous 40862306a36Sopenharmony_ci * map file size may not have been sufficient to cover whole extension 40962306a36Sopenharmony_ci * (it could have been used up for new map pages), 41062306a36Sopenharmony_ci * but the newly grown map file now covers lot bigger new free space 41162306a36Sopenharmony_ci * available for further extension of map; 41262306a36Sopenharmony_ci */ 41362306a36Sopenharmony_ci /* any more blocks to extend ? */ 41462306a36Sopenharmony_ci if (XSize) 41562306a36Sopenharmony_ci goto extendBmap; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci finalizeBmap: 41862306a36Sopenharmony_ci /* finalize bmap */ 41962306a36Sopenharmony_ci dbFinalizeBmap(ipbmap); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* 42262306a36Sopenharmony_ci * update inode allocation map 42362306a36Sopenharmony_ci * --------------------------- 42462306a36Sopenharmony_ci * 42562306a36Sopenharmony_ci * move iag lists from old to new iag; 42662306a36Sopenharmony_ci * agstart field is not updated for logredo() to reconstruct 42762306a36Sopenharmony_ci * iag lists if system crash occurs. 42862306a36Sopenharmony_ci * (computation of ag number from agstart based on agsize 42962306a36Sopenharmony_ci * will correctly identify the new ag); 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci /* if new AG size the same as old AG size, done! */ 43262306a36Sopenharmony_ci if (agsizechanged) { 43362306a36Sopenharmony_ci if ((rc = diExtendFS(ipimap, ipbmap))) 43462306a36Sopenharmony_ci goto error_out; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* finalize imap */ 43762306a36Sopenharmony_ci if ((rc = diSync(ipimap))) 43862306a36Sopenharmony_ci goto error_out; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* 44262306a36Sopenharmony_ci * finalize 44362306a36Sopenharmony_ci * -------- 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * extension is committed when on-disk super block is 44662306a36Sopenharmony_ci * updated with new descriptors: logredo will recover 44762306a36Sopenharmony_ci * crash before it to pre-extension state; 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* sync log to skip log replay of bmap file growth transaction; */ 45162306a36Sopenharmony_ci /* lmLogSync(log, 1); */ 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* 45462306a36Sopenharmony_ci * synchronous write bmap global control page; 45562306a36Sopenharmony_ci * for crash before completion of write 45662306a36Sopenharmony_ci * logredo() will recover to pre-extendfs state; 45762306a36Sopenharmony_ci * for crash after completion of write, 45862306a36Sopenharmony_ci * logredo() will recover post-extendfs state; 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci if ((rc = dbSync(ipbmap))) 46162306a36Sopenharmony_ci goto error_out; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* 46462306a36Sopenharmony_ci * copy primary bmap inode to secondary bmap inode 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci ipbmap2 = diReadSpecial(sb, BMAP_I, 1); 46862306a36Sopenharmony_ci if (ipbmap2 == NULL) { 46962306a36Sopenharmony_ci printk(KERN_ERR "jfs_extendfs: diReadSpecial(bmap) failed\n"); 47062306a36Sopenharmony_ci goto error_out; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci memcpy(&JFS_IP(ipbmap2)->i_xtroot, &JFS_IP(ipbmap)->i_xtroot, 288); 47362306a36Sopenharmony_ci ipbmap2->i_size = ipbmap->i_size; 47462306a36Sopenharmony_ci ipbmap2->i_blocks = ipbmap->i_blocks; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci diWriteSpecial(ipbmap2, 1); 47762306a36Sopenharmony_ci diFreeSpecial(ipbmap2); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* 48062306a36Sopenharmony_ci * update superblock 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_ci if ((rc = readSuper(sb, &bh))) 48362306a36Sopenharmony_ci goto error_out; 48462306a36Sopenharmony_ci j_sb = (struct jfs_superblock *)bh->b_data; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* mark extendfs() completion */ 48762306a36Sopenharmony_ci j_sb->s_state &= cpu_to_le32(~FM_EXTENDFS); 48862306a36Sopenharmony_ci j_sb->s_size = cpu_to_le64(bmp->db_mapsize << 48962306a36Sopenharmony_ci le16_to_cpu(j_sb->s_l2bfactor)); 49062306a36Sopenharmony_ci j_sb->s_agsize = cpu_to_le32(bmp->db_agsize); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* update inline log space descriptor */ 49362306a36Sopenharmony_ci if (sbi->mntflag & JFS_INLINELOG) { 49462306a36Sopenharmony_ci PXDaddress(&(j_sb->s_logpxd), newLogAddress); 49562306a36Sopenharmony_ci PXDlength(&(j_sb->s_logpxd), newLogSize); 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* record log's mount serial number */ 49962306a36Sopenharmony_ci j_sb->s_logserial = cpu_to_le32(log->serial); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci /* update fsck work space descriptor */ 50262306a36Sopenharmony_ci PXDaddress(&(j_sb->s_fsckpxd), newFSCKAddress); 50362306a36Sopenharmony_ci PXDlength(&(j_sb->s_fsckpxd), newFSCKSize); 50462306a36Sopenharmony_ci j_sb->s_fscklog = 1; 50562306a36Sopenharmony_ci /* sb->s_fsckloglen remains the same */ 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* Update secondary superblock */ 50862306a36Sopenharmony_ci bh2 = sb_bread(sb, SUPER2_OFF >> sb->s_blocksize_bits); 50962306a36Sopenharmony_ci if (bh2) { 51062306a36Sopenharmony_ci j_sb2 = (struct jfs_superblock *)bh2->b_data; 51162306a36Sopenharmony_ci memcpy(j_sb2, j_sb, sizeof (struct jfs_superblock)); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci mark_buffer_dirty(bh); 51462306a36Sopenharmony_ci sync_dirty_buffer(bh2); 51562306a36Sopenharmony_ci brelse(bh2); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* write primary superblock */ 51962306a36Sopenharmony_ci mark_buffer_dirty(bh); 52062306a36Sopenharmony_ci sync_dirty_buffer(bh); 52162306a36Sopenharmony_ci brelse(bh); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci goto resume; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci error_out: 52662306a36Sopenharmony_ci jfs_error(sb, "\n"); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci resume: 52962306a36Sopenharmony_ci /* 53062306a36Sopenharmony_ci * resume file system transactions 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_ci txResume(sb); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci out: 53562306a36Sopenharmony_ci return rc; 53662306a36Sopenharmony_ci} 537