xfs_dir2_leaf.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,897 行 · 第 1/4 页

C
1,897
字号
		 */		dep = (xfs_dir2_data_entry_t *)		      ((char *)dbp->data +		       XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT)));		/*		 * If it matches then return it.		 */		if (dep->namelen == args->namelen &&		    dep->name[0] == args->name[0] &&		    memcmp(dep->name, args->name, args->namelen) == 0) {			*dbpp = dbp;			*indexp = index;			return 0;		}	}	/*	 * No match found, return ENOENT.	 */	ASSERT(args->oknoent);	if (dbp)		xfs_da_brelse(tp, dbp);	xfs_da_brelse(tp, lbp);	return XFS_ERROR(ENOENT);}/* * Remove an entry from a leaf format directory. */int						/* error */xfs_dir2_leaf_removename(	xfs_da_args_t		*args)		/* operation arguments */{	xfs_dir2_data_off_t	*bestsp;	/* leaf block best freespace */	xfs_dir2_data_t		*data;		/* data block structure */	xfs_dir2_db_t		db;		/* data block number */	xfs_dabuf_t		*dbp;		/* data block buffer */	xfs_dir2_data_entry_t	*dep;		/* data entry structure */	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return code */	xfs_dir2_db_t		i;		/* temporary data block # */	int			index;		/* index into leaf entries */	xfs_dabuf_t		*lbp;		/* leaf buffer */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail structure */	xfs_mount_t		*mp;		/* filesystem mount point */	int			needlog;	/* need to log data header */	int			needscan;	/* need to rescan data frees */	xfs_dir2_data_off_t	oldbest;	/* old value of best free */	xfs_trans_t		*tp;		/* transaction pointer */	xfs_dir2_trace_args("leaf_removename", args);	/*	 * Lookup the leaf entry, get the leaf and data blocks read in.	 */	if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) {		return error;	}	dp = args->dp;	tp = args->trans;	mp = dp->i_mount;	leaf = lbp->data;	data = dbp->data;	xfs_dir2_data_check(dp, dbp);	/*	 * Point to the leaf entry, use that to point to the data entry.	 */	lep = &leaf->ents[index];	db = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT));	dep = (xfs_dir2_data_entry_t *)	      ((char *)data + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT)));	needscan = needlog = 0;	oldbest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT);	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);	bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);	ASSERT(INT_GET(bestsp[db], ARCH_CONVERT) == oldbest);	/*	 * Mark the former data entry unused.	 */	xfs_dir2_data_make_free(tp, dbp,		(xfs_dir2_data_aoff_t)((char *)dep - (char *)data),		XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan);	/*	 * We just mark the leaf entry stale by putting a null in it.	 */	INT_MOD(leaf->hdr.stale, ARCH_CONVERT, +1);	xfs_dir2_leaf_log_header(tp, lbp);	INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR);	xfs_dir2_leaf_log_ents(tp, lbp, index, index);	/*	 * Scan the freespace in the data block again if necessary,	 * log the data block header if necessary.	 */	if (needscan)		xfs_dir2_data_freescan(mp, data, &needlog, NULL);	if (needlog)		xfs_dir2_data_log_header(tp, dbp);	/*	 * If the longest freespace in the data block has changed,	 * put the new value in the bests table and log that.	 */	if (INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) != oldbest) {		INT_COPY(bestsp[db], data->hdr.bestfree[0].length, ARCH_CONVERT);		xfs_dir2_leaf_log_bests(tp, lbp, db, db);	}	xfs_dir2_data_check(dp, dbp);	/*	 * If the data block is now empty then get rid of the data block.	 */	if (INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) ==	    mp->m_dirblksize - (uint)sizeof(data->hdr)) {		ASSERT(db != mp->m_dirdatablk);		if ((error = xfs_dir2_shrink_inode(args, db, dbp))) {			/*			 * Nope, can't get rid of it because it caused			 * allocation of a bmap btree block to do so.			 * Just go on, returning success, leaving the			 * empty block in place.			 */			if (error == ENOSPC && args->total == 0) {				xfs_da_buf_done(dbp);				error = 0;			}			xfs_dir2_leaf_check(dp, lbp);			xfs_da_buf_done(lbp);			return error;		}		dbp = NULL;		/*		 * If this is the last data block then compact the		 * bests table by getting rid of entries.		 */		if (db == INT_GET(ltp->bestcount, ARCH_CONVERT) - 1) {			/*			 * Look for the last active entry (i).			 */			for (i = db - 1; i > 0; i--) {				if (INT_GET(bestsp[i], ARCH_CONVERT) != NULLDATAOFF)					break;			}			/*			 * Copy the table down so inactive entries at the			 * end are removed.			 */			memmove(&bestsp[db - i], bestsp,				(INT_GET(ltp->bestcount, ARCH_CONVERT) - (db - i)) * sizeof(*bestsp));			INT_MOD(ltp->bestcount, ARCH_CONVERT, -(db - i));			xfs_dir2_leaf_log_tail(tp, lbp);			xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);		} else			INT_SET(bestsp[db], ARCH_CONVERT, NULLDATAOFF);	}	/*	 * If the data block was not the first one, drop it.	 */	else if (db != mp->m_dirdatablk && dbp != NULL) {		xfs_da_buf_done(dbp);		dbp = NULL;	}	xfs_dir2_leaf_check(dp, lbp);	/*	 * See if we can convert to block form.	 */	return xfs_dir2_leaf_to_block(args, lbp, dbp);}/* * Replace the inode number in a leaf format directory entry. */int						/* error */xfs_dir2_leaf_replace(	xfs_da_args_t		*args)		/* operation arguments */{	xfs_dabuf_t		*dbp;		/* data block buffer */	xfs_dir2_data_entry_t	*dep;		/* data block entry */	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return code */	int			index;		/* index of leaf entry */	xfs_dabuf_t		*lbp;		/* leaf buffer */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */	xfs_trans_t		*tp;		/* transaction pointer */	xfs_dir2_trace_args("leaf_replace", args);	/*	 * Look up the entry.	 */	if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) {		return error;	}	dp = args->dp;	leaf = lbp->data;	/*	 * Point to the leaf entry, get data address from it.	 */	lep = &leaf->ents[index];	/*	 * Point to the data entry.	 */	dep = (xfs_dir2_data_entry_t *)	      ((char *)dbp->data +	       XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, INT_GET(lep->address, ARCH_CONVERT)));	ASSERT(args->inumber != INT_GET(dep->inumber, ARCH_CONVERT));	/*	 * Put the new inode number in, log it.	 */	INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);	tp = args->trans;	xfs_dir2_data_log_entry(tp, dbp, dep);	xfs_da_buf_done(dbp);	xfs_dir2_leaf_check(dp, lbp);	xfs_da_brelse(tp, lbp);	return 0;}/* * Return index in the leaf block (lbp) which is either the first * one with this hash value, or if there are none, the insert point * for that hash value. */int						/* index value */xfs_dir2_leaf_search_hash(	xfs_da_args_t		*args,		/* operation arguments */	xfs_dabuf_t		*lbp)		/* leaf buffer */{	xfs_dahash_t		hash=0;		/* hash from this entry */	xfs_dahash_t		hashwant;	/* hash value looking for */	int			high;		/* high leaf index */	int			low;		/* low leaf index */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */	int			mid=0;		/* current leaf index */	leaf = lbp->data;#ifndef __KERNEL__	if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT))		return 0;#endif	/*	 * Note, the table cannot be empty, so we have to go through the loop.	 * Binary search the leaf entries looking for our hash value.	 */	for (lep = leaf->ents, low = 0, high = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1,		hashwant = args->hashval;	     low <= high; ) {		mid = (low + high) >> 1;		if ((hash = INT_GET(lep[mid].hashval, ARCH_CONVERT)) == hashwant)			break;		if (hash < hashwant)			low = mid + 1;		else			high = mid - 1;	}	/*	 * Found one, back up through all the equal hash values.	 */	if (hash == hashwant) {		while (mid > 0 && INT_GET(lep[mid - 1].hashval, ARCH_CONVERT) == hashwant) {			mid--;		}	}	/*	 * Need to point to an entry higher than ours.	 */	else if (hash < hashwant)		mid++;	return mid;}/* * Trim off a trailing data block.  We know it's empty since the leaf * freespace table says so. */int						/* error */xfs_dir2_leaf_trim_data(	xfs_da_args_t		*args,		/* operation arguments */	xfs_dabuf_t		*lbp,		/* leaf buffer */	xfs_dir2_db_t		db)		/* data block number */{	xfs_dir2_data_off_t	*bestsp;	/* leaf bests table */#ifdef DEBUG	xfs_dir2_data_t		*data;		/* data block structure */#endif	xfs_dabuf_t		*dbp;		/* data block buffer */	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return value */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail structure */	xfs_mount_t		*mp;		/* filesystem mount point */	xfs_trans_t		*tp;		/* transaction pointer */	dp = args->dp;	mp = dp->i_mount;	tp = args->trans;	/*	 * Read the offending data block.  We need its buffer.	 */	if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, db), -1, &dbp,			XFS_DATA_FORK))) {		return error;	}#ifdef DEBUG	data = dbp->data;	ASSERT(INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC);#endif	/* this seems to be an error	 * data is only valid if DEBUG is defined?	 * RMC 09/08/1999	 */	leaf = lbp->data;	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);	ASSERT(INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) ==	       mp->m_dirblksize - (uint)sizeof(data->hdr));	ASSERT(db == INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);	/*	 * Get rid of the data block.	 */	if ((error = xfs_dir2_shrink_inode(args, db, dbp))) {		ASSERT(error != ENOSPC);		xfs_da_brelse(tp, dbp);		return error;	}	/*	 * Eliminate the last bests entry from the table.	 */	bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);	INT_MOD(ltp->bestcount, ARCH_CONVERT, -1);	memmove(&bestsp[1], &bestsp[0], INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(*bestsp));	xfs_dir2_leaf_log_tail(tp, lbp);	xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);	return 0;}/* * Convert node form directory to leaf form directory. * The root of the node form dir needs to already be a LEAFN block. * Just return if we can't do anything. */int						/* error */xfs_dir2_node_to_leaf(	xfs_da_state_t		*state)		/* directory operation state */{	xfs_da_args_t		*args;		/* operation arguments */	xfs_inode_t		*dp;		/* incore directory inode */	int			error;		/* error return code */	xfs_dabuf_t		*fbp;		/* buffer for freespace block */	xfs_fileoff_t		fo;		/* freespace file offset */	xfs_dir2_free_t		*free;		/* freespace structure */	xfs_dabuf_t		*lbp;		/* buffer for leaf block */	xfs_dir2_leaf_tail_t	*ltp;		/* tail of leaf structure */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_mount_t		*mp;		/* filesystem mount point */	int			rval;		/* successful free trim? */	xfs_trans_t		*tp;		/* transaction pointer */	/*	 * There's more than a leaf level in the btree, so there must	 * be multiple leafn blocks.  Give up.	 */	if (state->path.active > 1)		return 0;	args = state->args;	xfs_dir2_trace_args("node_to_leaf", args);	mp = state->mp;	dp = args->dp;	tp = args->trans;	/*	 * Get the last offset in the file.	 */	if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) {		return error;	}	fo -= mp->m_dirblkfsbs;	/*	 * If there are freespace blocks other than the first one,	 * take this opportunity to remove trailing empty freespace blocks	 * that may have been left behind during no-space-reservation	 * operations.	 */	while (fo > mp->m_dirfreeblk) {		if ((error = xfs_dir2_node_trim_free(args, fo, &rval))) {			return error;		}		if (rval)			fo -= mp->m_dirblkfsbs;		else			return 0;	}	/*	 * Now find the block just before the freespace block.	 */	if ((error = xfs_bmap_last_before(tp, dp, &fo, XFS_DATA_FORK))) {		return error;	}	/*	 * If it's not the single leaf block, give up.	 */	if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + mp->m_dirblksize)		return 0;	lbp = state->path.blk[0].bp;	leaf = lbp->data;	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC);	/*	 * Read the freespace block.	 */	if ((error = xfs_da_read_buf(tp, dp, mp->m_dirfreeblk, -1, &fbp,			XFS_DATA_FORK))) {		return error;	}	free = fbp->data;	ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC);	ASSERT(INT_ISZERO(free->hdr.firstdb, ARCH_CONVERT));	/*	 * Now see if the leafn and free data will fit in a leaf1.	 * If not, release the buffer and give up.	 */	if ((uint)sizeof(leaf->hdr) +	    (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)) * (uint)sizeof(leaf->ents[0]) +	    INT_GET(free->hdr.nvalid, ARCH_CONVERT) * (uint)sizeof(leaf->bests[0]) +	    (uint)sizeof(leaf->tail) >	    mp->m_dirblksize) {		xfs_da_brelse(tp, fbp);		return 0;	}	/*	 * If the leaf has any stale entries in it, compress them out.	 * The compact routine will log the header.	 */	if (INT_GET(leaf->hdr.stale, ARCH_CONVERT))		xfs_dir2_leaf_compact(args, lbp);	else		xfs_dir2_leaf_log_header(tp, lbp);	INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAF1_MAGIC);	/*	 * Set up the leaf tail from the freespace block.	 */	ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);	INT_COPY(ltp->bestcount, free->hdr.nvalid, ARCH_CONVERT);	/*	 * Set up the leaf bests table.	 */	memcpy(XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), free->bests,		INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(leaf->bests[0]));	xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);	xfs_dir2_leaf_log_tail(tp, lbp);	xfs_dir2_leaf_check(dp, lbp);	/*	 * Get rid of the freespace block.	 */	error = xfs_dir2_shrink_inode(args, XFS_DIR2_FREE_FIRSTDB(mp), fbp);	if (error) {		/*		 * This can't fail here because it can only happen when		 * punching out the middle of an extent, and this is an		 * isolated block.		 */		ASSERT(error != ENOSPC);		return error;	}	fbp = NULL;	/*	 * Now see if we can convert the single-leaf directory	 * down to a block form directory.	 * This routine always kills the dabuf for the leaf, so	 * eliminate it from the path.	 */	error = xfs_dir2_leaf_to_block(args, lbp, NULL);	state->path.blk[0].bp = NULL;	return error;}

⌨️ 快捷键说明

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