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

📄 jfs_dmap.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *   Copyright (C) International Business Machines Corp., 2000-2004 * *   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 "jfs_incore.h"#include "jfs_superblock.h"#include "jfs_dmap.h"#include "jfs_imap.h"#include "jfs_lock.h"#include "jfs_metapage.h"#include "jfs_debug.h"/* *	SERIALIZATION of the Block Allocation Map. * *	the working state of the block allocation map is accessed in *	two directions: * *	1) allocation and free requests that start at the dmap *	   level and move up through the dmap control pages (i.e. *	   the vast majority of requests). * *	2) allocation requests that start at dmap control page *	   level and work down towards the dmaps. * *	the serialization scheme used here is as follows. * *	requests which start at the bottom are serialized against each *	other through buffers and each requests holds onto its buffers *	as it works it way up from a single dmap to the required level *	of dmap control page. *	requests that start at the top are serialized against each other *	and request that start from the bottom by the multiple read/single *	write inode lock of the bmap inode. requests starting at the top *	take this lock in write mode while request starting at the bottom *	take the lock in read mode.  a single top-down request may proceed *	exclusively while multiple bottoms-up requests may proceed *	simultaneously (under the protection of busy buffers). * *	in addition to information found in dmaps and dmap control pages, *	the working state of the block allocation map also includes read/ *	write information maintained in the bmap descriptor (i.e. total *	free block count, allocation group level free block counts). *	a single exclusive lock (BMAP_LOCK) is used to guard this information *	in the face of multiple-bottoms up requests. *	(lock ordering: IREAD_LOCK, BMAP_LOCK); * *	accesses to the persistent state of the block allocation map (limited *	to the persistent bitmaps in dmaps) is guarded by (busy) buffers. */#define BMAP_LOCK_INIT(bmp)	mutex_init(&bmp->db_bmaplock)#define BMAP_LOCK(bmp)		mutex_lock(&bmp->db_bmaplock)#define BMAP_UNLOCK(bmp)	mutex_unlock(&bmp->db_bmaplock)/* * forward references */static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,			int nblocks);static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval);static int dbBackSplit(dmtree_t * tp, int leafno);static int dbJoin(dmtree_t * tp, int leafno, int newval);static void dbAdjTree(dmtree_t * tp, int leafno, int newval);static int dbAdjCtl(struct bmap * bmp, s64 blkno, int newval, int alloc,		    int level);static int dbAllocAny(struct bmap * bmp, s64 nblocks, int l2nb, s64 * results);static int dbAllocNext(struct bmap * bmp, struct dmap * dp, s64 blkno,		       int nblocks);static int dbAllocNear(struct bmap * bmp, struct dmap * dp, s64 blkno,		       int nblocks,		       int l2nb, s64 * results);static int dbAllocDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,		       int nblocks);static int dbAllocDmapLev(struct bmap * bmp, struct dmap * dp, int nblocks,			  int l2nb,			  s64 * results);static int dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb,		     s64 * results);static int dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno,		      s64 * results);static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks);static int dbFindBits(u32 word, int l2nb);static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno);static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx);static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,		      int nblocks);static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,		      int nblocks);static int dbMaxBud(u8 * cp);s64 dbMapFileSizeToMapSize(struct inode *ipbmap);static int blkstol2(s64 nb);static int cntlz(u32 value);static int cnttz(u32 word);static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,			 int nblocks);static int dbInitDmap(struct dmap * dp, s64 blkno, int nblocks);static int dbInitDmapTree(struct dmap * dp);static int dbInitTree(struct dmaptree * dtp);static int dbInitDmapCtl(struct dmapctl * dcp, int level, int i);static int dbGetL2AGSize(s64 nblocks);/* *	buddy table * * table used for determining buddy sizes within characters of * dmap bitmap words.  the characters themselves serve as indexes * into the table, with the table elements yielding the maximum * binary buddy of free bits within the character. */static const s8 budtab[256] = {	3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1};/* * NAME:	dbMount() * * FUNCTION:	initializate the block allocation map. * *		memory is allocated for the in-core bmap descriptor and *		the in-core descriptor is initialized from disk. * * PARAMETERS: *	ipbmap	- pointer to in-core inode for the block map. * * RETURN VALUES: *	0	- success *	-ENOMEM	- insufficient memory *	-EIO	- i/o error */int dbMount(struct inode *ipbmap){	struct bmap *bmp;	struct dbmap_disk *dbmp_le;	struct metapage *mp;	int i;	/*	 * allocate/initialize the in-memory bmap descriptor	 */	/* allocate memory for the in-memory bmap descriptor */	bmp = kmalloc(sizeof(struct bmap), GFP_KERNEL);	if (bmp == NULL)		return -ENOMEM;	/* read the on-disk bmap descriptor. */	mp = read_metapage(ipbmap,			   BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage,			   PSIZE, 0);	if (mp == NULL) {		kfree(bmp);		return -EIO;	}	/* copy the on-disk bmap descriptor to its in-memory version. */	dbmp_le = (struct dbmap_disk *) mp->data;	bmp->db_mapsize = le64_to_cpu(dbmp_le->dn_mapsize);	bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree);	bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage);	bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag);	bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel);	bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag);	bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref);	bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel);	bmp->db_agheigth = le32_to_cpu(dbmp_le->dn_agheigth);	bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);	bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart);	bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size);	for (i = 0; i < MAXAG; i++)		bmp->db_agfree[i] = le64_to_cpu(dbmp_le->dn_agfree[i]);	bmp->db_agsize = le64_to_cpu(dbmp_le->dn_agsize);	bmp->db_maxfreebud = dbmp_le->dn_maxfreebud;	/* release the buffer. */	release_metapage(mp);	/* bind the bmap inode and the bmap descriptor to each other. */	bmp->db_ipbmap = ipbmap;	JFS_SBI(ipbmap->i_sb)->bmap = bmp;	memset(bmp->db_active, 0, sizeof(bmp->db_active));	/*	 * allocate/initialize the bmap lock	 */	BMAP_LOCK_INIT(bmp);	return (0);}/* * NAME:	dbUnmount() * * FUNCTION:	terminate the block allocation map in preparation for *		file system unmount. * *		the in-core bmap descriptor is written to disk and *		the memory for this descriptor is freed. * * PARAMETERS: *	ipbmap	- pointer to in-core inode for the block map. * * RETURN VALUES: *	0	- success *	-EIO	- i/o error */int dbUnmount(struct inode *ipbmap, int mounterror){	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;	if (!(mounterror || isReadOnly(ipbmap)))		dbSync(ipbmap);	/*	 * Invalidate the page cache buffers	 */	truncate_inode_pages(ipbmap->i_mapping, 0);	/* free the memory for the in-memory bmap. */	kfree(bmp);	return (0);}/* *	dbSync() */int dbSync(struct inode *ipbmap){	struct dbmap_disk *dbmp_le;	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;	struct metapage *mp;	int i;	/*	 * write bmap global control page	 */	/* get the buffer for the on-disk bmap descriptor. */	mp = read_metapage(ipbmap,			   BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage,			   PSIZE, 0);	if (mp == NULL) {		jfs_err("dbSync: read_metapage failed!");		return -EIO;	}	/* copy the in-memory version of the bmap to the on-disk version */	dbmp_le = (struct dbmap_disk *) mp->data;	dbmp_le->dn_mapsize = cpu_to_le64(bmp->db_mapsize);	dbmp_le->dn_nfree = cpu_to_le64(bmp->db_nfree);	dbmp_le->dn_l2nbperpage = cpu_to_le32(bmp->db_l2nbperpage);	dbmp_le->dn_numag = cpu_to_le32(bmp->db_numag);	dbmp_le->dn_maxlevel = cpu_to_le32(bmp->db_maxlevel);	dbmp_le->dn_maxag = cpu_to_le32(bmp->db_maxag);	dbmp_le->dn_agpref = cpu_to_le32(bmp->db_agpref);	dbmp_le->dn_aglevel = cpu_to_le32(bmp->db_aglevel);	dbmp_le->dn_agheigth = cpu_to_le32(bmp->db_agheigth);	dbmp_le->dn_agwidth = cpu_to_le32(bmp->db_agwidth);	dbmp_le->dn_agstart = cpu_to_le32(bmp->db_agstart);	dbmp_le->dn_agl2size = cpu_to_le32(bmp->db_agl2size);	for (i = 0; i < MAXAG; i++)		dbmp_le->dn_agfree[i] = cpu_to_le64(bmp->db_agfree[i]);	dbmp_le->dn_agsize = cpu_to_le64(bmp->db_agsize);	dbmp_le->dn_maxfreebud = bmp->db_maxfreebud;	/* write the buffer */	write_metapage(mp);	/*	 * write out dirty pages of bmap	 */	filemap_write_and_wait(ipbmap->i_mapping);	diWriteSpecial(ipbmap, 0);	return (0);}/* * NAME:	dbFree() * * FUNCTION:	free the specified block range from the working block *		allocation map. * *		the blocks will be free from the working map one dmap *		at a time. * * PARAMETERS: *	ip	- pointer to in-core inode; *	blkno	- starting block number to be freed. *	nblocks	- number of blocks to be freed. * * RETURN VALUES: *	0	- success *	-EIO	- i/o error */int dbFree(struct inode *ip, s64 blkno, s64 nblocks){	struct metapage *mp;	struct dmap *dp;	int nb, rc;	s64 lblkno, rem;	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;	struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;	IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);	/* block to be freed better be within the mapsize. */	if (unlikely((blkno == 0) || (blkno + nblocks > bmp->db_mapsize))) {		IREAD_UNLOCK(ipbmap);		printk(KERN_ERR "blkno = %Lx, nblocks = %Lx\n",		       (unsigned long long) blkno,		       (unsigned long long) nblocks);		jfs_error(ip->i_sb,			  "dbFree: block to be freed is outside the map");		return -EIO;	}	/*	 * free the blocks a dmap at a time.	 */	mp = NULL;	for (rem = nblocks; rem > 0; rem -= nb, blkno += nb) {		/* release previous dmap if any */		if (mp) {			write_metapage(mp);		}		/* get the buffer for the current dmap. */		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);		if (mp == NULL) {			IREAD_UNLOCK(ipbmap);			return -EIO;		}		dp = (struct dmap *) mp->data;		/* determine the number of blocks to be freed from		 * this dmap.		 */		nb = min(rem, BPERDMAP - (blkno & (BPERDMAP - 1)));		/* free the blocks. */		if ((rc = dbFreeDmap(bmp, dp, blkno, nb))) {			jfs_error(ip->i_sb, "dbFree: error in block map\n");			release_metapage(mp);			IREAD_UNLOCK(ipbmap);			return (rc);		}	}	/* write the last buffer. */	write_metapage(mp);	IREAD_UNLOCK(ipbmap);	return (0);}/* * NAME:	dbUpdatePMap() * * FUNCTION:	update the allocation state (free or allocate) of the *		specified block range in the persistent block allocation map. * *		the blocks will be updated in the persistent map one *		dmap at a time. * * PARAMETERS: *	ipbmap	- pointer to in-core inode for the block map. *	free	- 'true' if block range is to be freed from the persistent *		  map; 'false' if it is to be allocated. *	blkno	- starting block number of the range. *	nblocks	- number of contiguous blocks in the range. *	tblk	- transaction block; * * RETURN VALUES: *	0	- success *	-EIO	- i/o error */intdbUpdatePMap(struct inode *ipbmap,	     int free, s64 blkno, s64 nblocks, struct tblock * tblk){	int nblks, dbitno, wbitno, rbits;	int word, nbits, nwords;	struct bmap *bmp = JFS_SBI(ipbmap->i_sb)->bmap;	s64 lblkno, rem, lastlblkno;	u32 mask;	struct dmap *dp;	struct metapage *mp;	struct jfs_log *log;	int lsn, difft, diffp;	unsigned long flags;	/* the blocks better be within the mapsize. */	if (blkno + nblocks > bmp->db_mapsize) {		printk(KERN_ERR "blkno = %Lx, nblocks = %Lx\n",		       (unsigned long long) blkno,		       (unsigned long long) nblocks);		jfs_error(ipbmap->i_sb,			  "dbUpdatePMap: blocks are outside the map");		return -EIO;	}	/* compute delta of transaction lsn from log syncpt */	lsn = tblk->lsn;	log = (struct jfs_log *) JFS_SBI(tblk->sb)->log;	logdiff(difft, lsn, log);	/*	 * update the block state a dmap at a time.	 */

⌨️ 快捷键说明

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