⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 resize.c

📁 jfs-2.4-1.1.7.tar.gz jfs 2.4-1.1.7 源码
💻 C
字号:
/* *   Copyright (C) International Business Machines  Corp., 2000-2003 * *   This program is free software;  you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or  *   (at your option) any later version. *  *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY;  without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See *   the GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program;  if not, write to the Free Software  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include <linux/fs.h>#include <linux/locks.h>#include "jfs_incore.h"#include "jfs_filsys.h"#include "jfs_metapage.h"#include "jfs_dinode.h"#include "jfs_imap.h"#include "jfs_dmap.h"#include "jfs_superblock.h"#include "jfs_txnmgr.h"#include "jfs_debug.h"extern s64 jfs_get_volume_size(struct super_block *);#define BITSPERPAGE     (PSIZE << 3)#define L2MEGABYTE      20#define MEGABYTE        (1 << L2MEGABYTE)#define MEGABYTE32     (MEGABYTE << 5)/* convert block number to bmap file page number */#define BLKTODMAPN(b)\        (((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1)/* *      jfs_extendfs() * * function: extend file system; * *   |-------------------------------|----------|----------| *   file system space               fsck       inline log *                                   workspace  space * * input: *      new LVSize: in LV blocks (required) *      new LogSize: in LV blocks (optional) *      new FSSize: in LV blocks (optional) * * new configuration: * 1. set new LogSize as specified or default from new LVSize; * 2. compute new FSCKSize from new LVSize; * 3. set new FSSize as MIN(FSSize, LVSize-(LogSize+FSCKSize)) where *    assert(new FSSize >= old FSSize), *    i.e., file system must not be shrinked; */int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize){	int rc = 0;	struct jfs_sb_info *sbi = JFS_SBI(sb);	struct inode *ipbmap = sbi->ipbmap;	struct inode *ipbmap2;	struct inode *ipimap = sbi->ipimap;	struct jfs_log *log = sbi->log;	struct bmap *bmp = sbi->bmap;	s64 newLogAddress, newFSCKAddress;	int newFSCKSize;	s64 newMapSize = 0, mapSize;	s64 XAddress, XSize, nblocks, xoff, xaddr, t64;	s64 oldLVSize;	s64 newFSSize;	s64 VolumeSize;	int newNpages = 0, nPages, newPage, xlen, t32;	int tid;	int log_formatted = 0;	struct inode *iplist[1];	struct jfs_superblock *j_sb, *j_sb2;	uint old_agsize;	struct buffer_head *bh, *bh2;	/* If the volume hasn't grown, get out now */	if (sbi->mntflag & JFS_INLINELOG)		oldLVSize = addressPXD(&sbi->logpxd) + lengthPXD(&sbi->logpxd);	else		oldLVSize = addressPXD(&sbi->fsckpxd) +		    lengthPXD(&sbi->fsckpxd);	if (oldLVSize >= newLVSize) {		printk(KERN_WARNING		       "jfs_extendfs: volume hasn't grown, returning\n");		goto out;	}	VolumeSize = jfs_get_volume_size(sb);	if (VolumeSize) {		if (newLVSize > VolumeSize) {			printk(KERN_WARNING "jfs_extendfs: invalid size\n");			rc = -EINVAL;			goto out;		}	} else {		/* check the device */		bh = sb_bread(sb, newLVSize - 1);		if (!bh) {			printk(KERN_WARNING "jfs_extendfs: invalid size\n");			rc = -EINVAL;			goto out;		}		bforget(bh);	}	/* Can't extend write-protected drive */	if (isReadOnly(ipbmap)) {		printk(KERN_WARNING "jfs_extendfs: read-only file system\n");		rc = -EROFS;		goto out;	}	/*	 *      reconfigure LV spaces	 *      ---------------------	 *	 * validate new size, or, if not specified, determine new size	 */	/*	 * reconfigure inline log space:	 */	if ((sbi->mntflag & JFS_INLINELOG)) {		if (newLogSize == 0) {			/*			 * no size specified: default to 1/256 of aggregate			 * size; rounded up to a megabyte boundary;			 */			newLogSize = newLVSize >> 8;			t32 = (1 << (20 - sbi->l2bsize)) - 1;			newLogSize = (newLogSize + t32) & ~t32;			newLogSize =			    min(newLogSize, MEGABYTE32 >> sbi->l2bsize);		} else {			/*			 * convert the newLogSize to fs blocks.			 *			 * Since this is given in megabytes, it will always be			 * an even number of pages.			 */			newLogSize = (newLogSize * MEGABYTE) >> sbi->l2bsize;		}	} else		newLogSize = 0;	newLogAddress = newLVSize - newLogSize;	/*	 * reconfigure fsck work space:	 *	 * configure it to the end of the logical volume regardless of	 * whether file system extends to the end of the aggregate;	 * Need enough 4k pages to cover:	 *  - 1 bit per block in aggregate rounded up to BPERDMAP boundary	 *  - 1 extra page to handle control page and intermediate level pages	 *  - 50 extra pages for the chkdsk service log	 */	t64 = ((newLVSize - newLogSize + BPERDMAP - 1) >> L2BPERDMAP)	    << L2BPERDMAP;	t32 = ((t64 + (BITSPERPAGE - 1)) / BITSPERPAGE) + 1 + 50;	newFSCKSize = t32 << sbi->l2nbperpage;	newFSCKAddress = newLogAddress - newFSCKSize;	/*	 * compute new file system space;	 */	newFSSize = newLVSize - newLogSize - newFSCKSize;	/* file system cannot be shrinked */	if (newFSSize < bmp->db_mapsize) {		rc = -EINVAL;		goto out;	}	/*	 * If we're expanding enough that the inline log does not overlap	 * the old one, we can format the new log before we quiesce the	 * filesystem.	 */	if ((sbi->mntflag & JFS_INLINELOG) && (newLogAddress > oldLVSize)) {		if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))			goto out;		log_formatted = 1;	}	/*	 *      quiesce file system	 *	 * (prepare to move the inline log and to prevent map update)	 *	 * block any new transactions and wait for completion of	 * all wip transactions and flush modified pages s.t.	 * on-disk file system is in consistent state and	 * log is not required for recovery.	 */	txQuiesce(sb);	if (sbi->mntflag & JFS_INLINELOG) {		/*		 * deactivate old inline log		 */		lmLogShutdown(log);		/*		 * mark on-disk super block for fs in transition;		 *		 * update on-disk superblock for the new space configuration		 * of inline log space and fsck work space descriptors:		 * N.B. FS descriptor is NOT updated;		 *		 * crash recovery:		 * logredo(): if FM_EXTENDFS, return to fsck() for cleanup;		 * fsck(): if FM_EXTENDFS, reformat inline log and fsck		 * workspace from superblock inline log descriptor and fsck		 * workspace descriptor;		 */		/* read in superblock */		if ((rc = readSuper(sb, &bh)))			goto error_out;		j_sb = (struct jfs_superblock *)bh->b_data;		/* mark extendfs() in progress */		j_sb->s_state |= cpu_to_le32(FM_EXTENDFS);		j_sb->s_xsize = cpu_to_le64(newFSSize);		PXDaddress(&j_sb->s_xfsckpxd, newFSCKAddress);		PXDlength(&j_sb->s_xfsckpxd, newFSCKSize);		PXDaddress(&j_sb->s_xlogpxd, newLogAddress);		PXDlength(&j_sb->s_xlogpxd, newLogSize);		/* synchronously update superblock */		mark_buffer_dirty(bh);		ll_rw_block(WRITE, 1, &bh);		wait_on_buffer(bh);		brelse(bh);		/*		 * format new inline log synchronously;		 *		 * crash recovery: if log move in progress,		 * reformat log and exit success;		 */		if (!log_formatted)			if ((rc = lmLogFormat(log, newLogAddress, newLogSize)))				goto error_out;		/*		 * activate new log		 */		log->base = newLogAddress;		log->size = newLogSize >> (L2LOGPSIZE - sb->s_blocksize_bits);		if ((rc = lmLogInit(log)))			goto error_out;	}	/*	 *      extend block allocation map	 *      ---------------------------	 *	 * extendfs() for new extension, retry after crash recovery;	 *	 * note: both logredo() and fsck() rebuild map from	 * the bitmap and configuration parameter from superblock	 * (disregarding all other control information in the map);	 *	 * superblock:	 *  s_size: aggregate size in physical blocks;	 */	/*	 *      compute the new block allocation map configuration	 *	 * map dinode:	 *  di_size: map file size in byte;	 *  di_nblocks: number of blocks allocated for map file;	 *  di_mapsize: number of blocks in aggregate (covered by map);	 * map control page:	 *  db_mapsize: number of blocks in aggregate (covered by map);	 */	newMapSize = newFSSize;	/* number of data pages of new bmap file:	 * roundup new size to full dmap page boundary and	 * add 1 extra dmap page for next extendfs()	 */	t64 = (newMapSize - 1) + BPERDMAP;	newNpages = BLKTODMAPN(t64) + 1;	/*	 *      extend map from current map (WITHOUT growing mapfile)	 *	 * map new extension with unmapped part of the last partial	 * dmap page, if applicable, and extra page(s) allocated	 * at end of bmap by mkfs() or previous extendfs();	 */      extendBmap:	/* compute number of blocks requested to extend */	mapSize = bmp->db_mapsize;	XAddress = mapSize;	/* eXtension Address */	XSize = newMapSize - mapSize;	/* eXtension Size */	old_agsize = bmp->db_agsize;	/* We need to know if this changes */	/* compute number of blocks that can be extended by current mapfile */	t64 = dbMapFileSizeToMapSize(ipbmap);	if (mapSize > t64) {		printk(KERN_ERR "jfs_extendfs: mapSize (0x%Lx) > t64 (0x%Lx)\n",		       (long long) mapSize, (long long) t64);		rc = -EIO;		goto error_out;	}	nblocks = min(t64 - mapSize, XSize);	/*	 * update map pages for new extension:	 *	 * update/init dmap and bubble up the control hierarchy	 * incrementally fold up dmaps into upper levels;	 * update bmap control page;	 */	if ((rc = dbExtendFS(ipbmap, XAddress, nblocks)))		goto error_out;	/*	 * the map now has extended to cover additional nblocks:	 * dn_mapsize = oldMapsize + nblocks;	 */	/* ipbmap->i_mapsize += nblocks; */	XSize -= nblocks;	/*	 *      grow map file to cover remaining extension	 *      and/or one extra dmap page for next extendfs();	 *	 * allocate new map pages and its backing blocks, and	 * update map file xtree	 */	/* compute number of data pages of current bmap file */	nPages = ipbmap->i_size >> L2PSIZE;	/* need to grow map file ? */	if (nPages == newNpages)		goto finalizeBmap;	/*	 * grow bmap file for the new map pages required:	 *	 * allocate growth at the start of newly extended region;	 * bmap file only grows sequentially, i.e., both data pages	 * and possibly xtree index pages may grow in append mode,	 * s.t. logredo() can reconstruct pre-extension state	 * by washing away bmap file of pages outside s_size boundary;	 */	/*	 * journal map file growth as if a regular file growth:	 * (note: bmap is created with di_mode = IFJOURNAL|IFREG);	 *	 * journaling of bmap file growth is not required since	 * logredo() do/can not use log records of bmap file growth	 * but it provides careful write semantics, pmap update, etc.;	 */	/* synchronous write of data pages: bmap data pages are	 * cached in meta-data cache, and not written out	 * by txCommit();	 */	fsync_inode_data_buffers(ipbmap);	diWriteSpecial(ipbmap, 0);	newPage = nPages;	/* first new page number */	xoff = newPage << sbi->l2nbperpage;	xlen = (newNpages - nPages) << sbi->l2nbperpage;	xlen = min(xlen, (int) nblocks) & ~(sbi->nbperpage - 1);	xaddr = XAddress;	tid = txBegin(sb, COMMIT_FORCE);	if ((rc = xtAppend(tid, ipbmap, 0, xoff, nblocks, &xlen, &xaddr, 0))) {		txEnd(tid);		goto error_out;	}	/* update bmap file size */	ipbmap->i_size += xlen << sbi->l2bsize;	ipbmap->i_blocks += LBLK2PBLK(sb, xlen);	iplist[0] = ipbmap;	rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);	txEnd(tid);	if (rc)		goto error_out;	/*	 * map file has been grown now to cover extension to further out;	 * di_size = new map file size;	 *	 * if huge extension, the previous extension based on previous	 * map file size may not have been sufficient to cover whole extension	 * (it could have been used up for new map pages),	 * but the newly grown map file now covers lot bigger new free space	 * available for further extension of map;	 */	/* any more blocks to extend ? */	if (XSize)		goto extendBmap;      finalizeBmap:	/* finalize bmap */	dbFinalizeBmap(ipbmap);	/*	 *      update inode allocation map	 *      ---------------------------	 *	 * move iag lists from old to new iag;	 * agstart field is not updated for logredo() to reconstruct	 * iag lists if system crash occurs.	 * (computation of ag number from agstart based on agsize	 * will correctly identify the new ag);	 */	/* if new AG size the same as old AG size, done! */	if (bmp->db_agsize != old_agsize) {		if ((rc = diExtendFS(ipimap, ipbmap)))			goto error_out;		/* finalize imap */		if ((rc = diSync(ipimap)))			goto error_out;	}	/*	 *      finalize	 *      --------	 *	 * extension is committed when on-disk super block is	 * updated with new descriptors: logredo will recover	 * crash before it to pre-extension state;	 */	/* sync log to skip log replay of bmap file growth transaction; */	/* lmLogSync(log, 1); */	/*	 * synchronous write bmap global control page;	 * for crash before completion of write	 * logredo() will recover to pre-extendfs state;	 * for crash after completion of write,	 * logredo() will recover post-extendfs state;	 */	if ((rc = dbSync(ipbmap)))		goto error_out;	/*	 * copy primary bmap inode to secondary bmap inode	 */	ipbmap2 = diReadSpecial(sb, BMAP_I, 1);	if (ipbmap2 == NULL) {		printk(KERN_ERR "jfs_extendfs: diReadSpecial(bmap) failed\n");		goto error_out;	}	memcpy(&JFS_IP(ipbmap2)->i_xtroot, &JFS_IP(ipbmap)->i_xtroot, 288);	ipbmap2->i_size = ipbmap->i_size;	ipbmap2->i_blocks = ipbmap->i_blocks;	diWriteSpecial(ipbmap2, 1);	diFreeSpecial(ipbmap2);	/*	 *      update superblock	 */	if ((rc = readSuper(sb, &bh)))		goto error_out;	j_sb = (struct jfs_superblock *)bh->b_data;	/* mark extendfs() completion */	j_sb->s_state &= cpu_to_le32(~FM_EXTENDFS);	j_sb->s_size = cpu_to_le64(bmp->db_mapsize <<				   le16_to_cpu(j_sb->s_l2bfactor));	j_sb->s_agsize = cpu_to_le32(bmp->db_agsize);	/* update inline log space descriptor */	if (sbi->mntflag & JFS_INLINELOG) {		PXDaddress(&(j_sb->s_logpxd), newLogAddress);		PXDlength(&(j_sb->s_logpxd), newLogSize);	}	/* record log's mount serial number */	j_sb->s_logserial = cpu_to_le32(log->serial);	/* update fsck work space descriptor */	PXDaddress(&(j_sb->s_fsckpxd), newFSCKAddress);	PXDlength(&(j_sb->s_fsckpxd), newFSCKSize);	j_sb->s_fscklog = 1;	/* sb->s_fsckloglen remains the same */	/* Update secondary superblock */	bh2 = sb_bread(sb, SUPER2_OFF >> sb->s_blocksize_bits);	if (bh2) {		j_sb2 = (struct jfs_superblock *)bh2->b_data;		memcpy(j_sb2, j_sb, sizeof (struct jfs_superblock));		mark_buffer_dirty(bh);		ll_rw_block(WRITE, 1, &bh2);		wait_on_buffer(bh2);		brelse(bh2);	}	/* write primary superblock */	mark_buffer_dirty(bh);	ll_rw_block(WRITE, 1, &bh);	wait_on_buffer(bh);	brelse(bh);	goto resume;      error_out:	jfs_error(sb, "jfs_extendfs");      resume:	/*	 *      resume file system transactions	 */	txResume(sb);      out:	return rc;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -