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

📄 jfs_dmap.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		}		/* determine how many blocks to allocate from this dmap.		 */		nb = min(n, (s64)BPERDMAP);		/* allocate the blocks from the dmap.		 */		if ((rc = dbAllocDmap(bmp, dp, b, nb))) {			release_metapage(mp);			goto backout;		}		/* write the buffer.		 */		write_metapage(mp);	}	/* set the results (starting block number) and return.	 */	*results = blkno;	return (0);	/* something failed in handling an allocation request involving	 * multiple dmaps.  we'll try to clean up by backing out any	 * allocation that has already happened for this request.  if	 * we fail in backing out the allocation, we'll mark the file	 * system to indicate that blocks have been leaked.	 */      backout:	/* try to backout the allocations dmap by dmap.	 */	for (n = nblocks - n, b = blkno; n > 0;	     n -= BPERDMAP, b += BPERDMAP) {		/* get the buffer for this dmap.		 */		lblkno = BLKTODMAP(b, bmp->db_l2nbperpage);		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);		if (mp == NULL) {			/* could not back out.  mark the file system			 * to indicate that we have leaked blocks.			 */			jfs_error(bmp->db_ipbmap->i_sb,				  "dbAllocCtl: I/O Error: Block Leakage.");			continue;		}		dp = (struct dmap *) mp->data;		/* free the blocks is this dmap.		 */		if (dbFreeDmap(bmp, dp, b, BPERDMAP)) {			/* could not back out.  mark the file system			 * to indicate that we have leaked blocks.			 */			release_metapage(mp);			jfs_error(bmp->db_ipbmap->i_sb,				  "dbAllocCtl: Block Leakage.");			continue;		}		/* write the buffer.		 */		write_metapage(mp);	}	return (rc);}/* * NAME:	dbAllocDmapLev() * * FUNCTION:	attempt to allocate a specified number of contiguous blocks *		from a specified dmap. * *		this routine checks if the contiguous blocks are available. *		if so, nblocks of blocks are allocated; otherwise, ENOSPC is *		returned. * * PARAMETERS: *	mp	-  pointer to bmap descriptor *	dp	-  pointer to dmap to attempt to allocate blocks from. *	l2nb	-  log2 number of contiguous block desired. *	nblocks	-  actual number of contiguous block desired. *	results	-  on successful return, set to the starting block number *		   of the newly allocated range. * * RETURN VALUES: *	0	- success *	-ENOSPC	- insufficient disk resources *	-EIO	- i/o error * * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or *	IWRITE_LOCK(ipbmap), e.g., dbAllocCtl(), held on entry/exit; */static intdbAllocDmapLev(struct bmap * bmp,	       struct dmap * dp, int nblocks, int l2nb, s64 * results){	s64 blkno;	int leafidx, rc;	/* can't be more than a dmaps worth of blocks */	assert(l2nb <= L2BPERDMAP);	/* search the tree within the dmap page for sufficient	 * free space.  if sufficient free space is found, dbFindLeaf()	 * returns the index of the leaf at which free space was found.	 */	if (dbFindLeaf((dmtree_t *) & dp->tree, l2nb, &leafidx))		return -ENOSPC;	/* determine the block number within the file system corresponding	 * to the leaf at which free space was found.	 */	blkno = le64_to_cpu(dp->start) + (leafidx << L2DBWORD);	/* if not all bits of the dmap word are free, get the starting	 * bit number within the dmap word of the required string of free	 * bits and adjust the block number with this value.	 */	if (dp->tree.stree[leafidx + LEAFIND] < BUDMIN)		blkno += dbFindBits(le32_to_cpu(dp->wmap[leafidx]), l2nb);	/* allocate the blocks */	if ((rc = dbAllocDmap(bmp, dp, blkno, nblocks)) == 0)		*results = blkno;	return (rc);}/* * NAME:	dbAllocDmap() * * FUNCTION:	adjust the disk allocation map to reflect the allocation *		of a specified block range within a dmap. * *		this routine allocates the specified blocks from the dmap *		through a call to dbAllocBits(). if the allocation of the *		block range causes the maximum string of free blocks within *		the dmap to change (i.e. the value of the root of the dmap's *		dmtree), this routine will cause this change to be reflected *		up through the appropriate levels of the dmap control pages *		by a call to dbAdjCtl() for the L0 dmap control page that *		covers this dmap. * * PARAMETERS: *	bmp	-  pointer to bmap descriptor *	dp	-  pointer to dmap to allocate the block range from. *	blkno	-  starting block number of the block to be allocated. *	nblocks	-  number of blocks to be allocated. * * RETURN VALUES: *	0	- success *	-EIO	- i/o error * * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; */static int dbAllocDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,		       int nblocks){	s8 oldroot;	int rc;	/* save the current value of the root (i.e. maximum free string)	 * of the dmap tree.	 */	oldroot = dp->tree.stree[ROOT];	/* allocate the specified (blocks) bits */	dbAllocBits(bmp, dp, blkno, nblocks);	/* if the root has not changed, done. */	if (dp->tree.stree[ROOT] == oldroot)		return (0);	/* root changed. bubble the change up to the dmap control pages.	 * if the adjustment of the upper level control pages fails,	 * backout the bit allocation (thus making everything consistent).	 */	if ((rc = dbAdjCtl(bmp, blkno, dp->tree.stree[ROOT], 1, 0)))		dbFreeBits(bmp, dp, blkno, nblocks);	return (rc);}/* * NAME:	dbFreeDmap() * * FUNCTION:	adjust the disk allocation map to reflect the allocation *		of a specified block range within a dmap. * *		this routine frees the specified blocks from the dmap through *		a call to dbFreeBits(). if the deallocation of the block range *		causes the maximum string of free blocks within the dmap to *		change (i.e. the value of the root of the dmap's dmtree), this *		routine will cause this change to be reflected up through the *		appropriate levels of the dmap control pages by a call to *		dbAdjCtl() for the L0 dmap control page that covers this dmap. * * PARAMETERS: *	bmp	-  pointer to bmap descriptor *	dp	-  pointer to dmap to free the block range from. *	blkno	-  starting block number of the block to be freed. *	nblocks	-  number of blocks to be freed. * * RETURN VALUES: *	0	- success *	-EIO	- i/o error * * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; */static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,		      int nblocks){	s8 oldroot;	int rc = 0, word;	/* save the current value of the root (i.e. maximum free string)	 * of the dmap tree.	 */	oldroot = dp->tree.stree[ROOT];	/* free the specified (blocks) bits */	rc = dbFreeBits(bmp, dp, blkno, nblocks);	/* if error or the root has not changed, done. */	if (rc || (dp->tree.stree[ROOT] == oldroot))		return (rc);	/* root changed. bubble the change up to the dmap control pages.	 * if the adjustment of the upper level control pages fails,	 * backout the deallocation.	 */	if ((rc = dbAdjCtl(bmp, blkno, dp->tree.stree[ROOT], 0, 0))) {		word = (blkno & (BPERDMAP - 1)) >> L2DBWORD;		/* as part of backing out the deallocation, we will have		 * to back split the dmap tree if the deallocation caused		 * the freed blocks to become part of a larger binary buddy		 * system.		 */		if (dp->tree.stree[word] == NOFREE)			dbBackSplit((dmtree_t *) & dp->tree, word);		dbAllocBits(bmp, dp, blkno, nblocks);	}	return (rc);}/* * NAME:	dbAllocBits() * * FUNCTION:	allocate a specified block range from a dmap. * *		this routine updates the dmap to reflect the working *		state allocation of the specified block range. it directly *		updates the bits of the working map and causes the adjustment *		of the binary buddy system described by the dmap's dmtree *		leaves to reflect the bits allocated.  it also causes the *		dmap's dmtree, as a whole, to reflect the allocated range. * * PARAMETERS: *	bmp	-  pointer to bmap descriptor *	dp	-  pointer to dmap to allocate bits from. *	blkno	-  starting block number of the bits to be allocated. *	nblocks	-  number of bits to be allocated. * * RETURN VALUES: none * * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; */static void dbAllocBits(struct bmap * bmp, struct dmap * dp, s64 blkno,			int nblocks){	int dbitno, word, rembits, nb, nwords, wbitno, nw, agno;	dmtree_t *tp = (dmtree_t *) & dp->tree;	int size;	s8 *leaf;	/* pick up a pointer to the leaves of the dmap tree */	leaf = dp->tree.stree + LEAFIND;	/* determine the bit number and word within the dmap of the	 * starting block.	 */	dbitno = blkno & (BPERDMAP - 1);	word = dbitno >> L2DBWORD;	/* block range better be within the dmap */	assert(dbitno + nblocks <= BPERDMAP);	/* allocate the bits of the dmap's words corresponding to the block	 * range. not all bits of the first and last words may be contained	 * within the block range.  if this is the case, we'll work against	 * those words (i.e. partial first and/or last) on an individual basis	 * (a single pass), allocating the bits of interest by hand and	 * updating the leaf corresponding to the dmap word. a single pass	 * will be used for all dmap words fully contained within the	 * specified range.  within this pass, the bits of all fully contained	 * dmap words will be marked as free in a single shot and the leaves	 * will be updated. a single leaf may describe the free space of	 * multiple dmap words, so we may update only a subset of the actual	 * leaves corresponding to the dmap words of the block range.	 */	for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) {		/* determine the bit number within the word and		 * the number of bits within the word.		 */		wbitno = dbitno & (DBWORD - 1);		nb = min(rembits, DBWORD - wbitno);		/* check if only part of a word is to be allocated.		 */		if (nb < DBWORD) {			/* allocate (set to 1) the appropriate bits within			 * this dmap word.			 */			dp->wmap[word] |= cpu_to_le32(ONES << (DBWORD - nb)						      >> wbitno);			/* update the leaf for this dmap word. in addition			 * to setting the leaf value to the binary buddy max			 * of the updated dmap word, dbSplit() will split			 * the binary system of the leaves if need be.			 */			dbSplit(tp, word, BUDMIN,				dbMaxBud((u8 *) & dp->wmap[word]));			word += 1;		} else {			/* one or more dmap words are fully contained			 * within the block range.  determine how many			 * words and allocate (set to 1) the bits of these			 * words.			 */			nwords = rembits >> L2DBWORD;			memset(&dp->wmap[word], (int) ONES, nwords * 4);			/* determine how many bits.			 */			nb = nwords << L2DBWORD;			/* now update the appropriate leaves to reflect			 * the allocated words.			 */			for (; nwords > 0; nwords -= nw) {				if (leaf[word] < BUDMIN) {					jfs_error(bmp->db_ipbmap->i_sb,						  "dbAllocBits: leaf page "						  "corrupt");					break;				}				/* determine what the leaf value should be				 * updated to as the minimum of the l2 number				 * of bits being allocated and the l2 number				 * of bits currently described by this leaf.				 */				size = min((int)leaf[word], NLSTOL2BSZ(nwords));				/* update the leaf to reflect the allocation.				 * in addition to setting the leaf value to				 * NOFREE, dbSplit() will split the binary				 * system of the leaves to reflect the current				 * allocation (size).				 */				dbSplit(tp, word, size, NOFREE);				/* get the number of dmap words handled */				nw = BUDSIZE(size, BUDMIN);				word += nw;			}		}	}	/* update the free count for this dmap */	dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) - nblocks);	BMAP_LOCK(bmp);	/* if this allocation group is completely free,	 * update the maximum allocation group number if this allocation	 * group is the new max.	 */	agno = blkno >> bmp->db_agl2size;	if (agno > bmp->db_maxag)		bmp->db_maxag = agno;	/* update the free count for the allocation group and map */	bmp->db_agfree[agno] -= nblocks;	bmp->db_nfree -= nblocks;	BMAP_UNLOCK(bmp);}/* * NAME:	dbFreeBits() * * FUNCTION:	free a specified block range from a dmap. * *		this routine updates the dmap to reflect the working *		state allocation of the specified block range. it directly *		updates the bits of the working map and causes the adjustment *		of the binary buddy system described by the dmap's dmtree *		leaves to reflect the bits freed.  it also causes the dmap's *		dmtree, as a whole, to reflect the deallocated range. * * PARAMETERS: *	bmp	-  pointer to bmap descriptor *	dp	-  pointer to dmap to free bits from. *	blkno	-  starting block number of the bits to be freed. *	nblocks	-  number of bits to be freed. * * RETURN VALUES: 0 for success * * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit; */static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,		       int nblocks){	int dbitno, word, rembits, nb, nwords, wbitno, nw, agno;	dmtree_t *tp = (dmtree_t *) & dp->tree;	int rc = 0;	int size;	/* determine the bit number and word within the dmap of the	 * starting block.	 */	dbitno = blkno & (BPERDMAP - 1);	word = dbitno >> L2DBWORD;	/* block range better be within the dmap.	 */	assert(dbitno + nblocks <= BPERDMAP);	/* free the bits of the dmaps words corresponding to the block range.	 * not all bits of the first and last words may be contained within	 * the block range.  if this is the case, we'll work against those	 * words (i.e. partial first and/or last) on an individual basis	 * (a single pass), freeing the bits of int

⌨️ 快捷键说明

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