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

📄 xfs_attr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		 * a new one.  We need the inode to be in all transactions.		 */		if (committed) {			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);			xfs_trans_ihold(args->trans, dp);		}		/*		 * Commit the current trans (including the inode) and start		 * a new one.		 */		if ((error = xfs_attr_rolltrans(&args->trans, dp)))			return (error);		/*		 * Fob the whole rest of the problem off on the Btree code.		 */		error = xfs_attr_node_addname(args);		return(error);	}	/*	 * Commit the transaction that added the attr name so that	 * later routines can manage their own transactions.	 */	if ((error = xfs_attr_rolltrans(&args->trans, dp)))		return (error);	/*	 * If there was an out-of-line value, allocate the blocks we	 * identified for its storage and copy the value.  This is done	 * after we create the attribute so that we don't overflow the	 * maximum size of a transaction and/or hit a deadlock.	 */	if (args->rmtblkno > 0) {		error = xfs_attr_rmtval_set(args);		if (error)			return(error);	}	/*	 * If this is an atomic rename operation, we must "flip" the	 * incomplete flags on the "new" and "old" attribute/value pairs	 * so that one disappears and one appears atomically.  Then we	 * must remove the "old" attribute/value pair.	 */	if (args->rename) {		/*		 * In a separate transaction, set the incomplete flag on the		 * "old" attr and clear the incomplete flag on the "new" attr.		 */		error = xfs_attr_leaf_flipflags(args);		if (error)			return(error);		/*		 * Dismantle the "old" attribute/value pair by removing		 * a "remote" value (if it exists).		 */		args->index = args->index2;		args->blkno = args->blkno2;		args->rmtblkno = args->rmtblkno2;		args->rmtblkcnt = args->rmtblkcnt2;		if (args->rmtblkno) {			error = xfs_attr_rmtval_remove(args);			if (error)				return(error);		}		/*		 * Read in the block containing the "old" attr, then		 * remove the "old" attr from that block (neat, huh!)		 */		error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1,						     &bp, XFS_ATTR_FORK);		if (error)			return(error);		ASSERT(bp != NULL);		(void)xfs_attr_leaf_remove(bp, args);		/*		 * If the result is small enough, shrink it all into the inode.		 */		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {			XFS_BMAP_INIT(args->flist, args->firstblock);			error = xfs_attr_leaf_to_shortform(bp, args, forkoff);			/* bp is gone due to xfs_da_shrink_inode */			if (!error) {				error = xfs_bmap_finish(&args->trans,							args->flist,							&committed);			}			if (error) {				ASSERT(committed);				args->trans = NULL;				xfs_bmap_cancel(args->flist);				return(error);			}			/*			 * bmap_finish() may have committed the last trans			 * and started a new one.  We need the inode to be			 * in all transactions.			 */			if (committed) {				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);				xfs_trans_ihold(args->trans, dp);			}		} else			xfs_da_buf_done(bp);		/*		 * Commit the remove and start the next trans in series.		 */		error = xfs_attr_rolltrans(&args->trans, dp);	} else if (args->rmtblkno > 0) {		/*		 * Added a "remote" value, just clear the incomplete flag.		 */		error = xfs_attr_leaf_clearflag(args);	}	return(error);}/* * Remove a name from the leaf attribute list structure * * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */STATIC intxfs_attr_leaf_removename(xfs_da_args_t *args){	xfs_inode_t *dp;	xfs_dabuf_t *bp;	int error, committed, forkoff;	/*	 * Remove the attribute.	 */	dp = args->dp;	args->blkno = 0;	error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,					     XFS_ATTR_FORK);	if (error) {		return(error);	}	ASSERT(bp != NULL);	error = xfs_attr_leaf_lookup_int(bp, args);	if (error == ENOATTR) {		xfs_da_brelse(args->trans, bp);		return(error);	}	(void)xfs_attr_leaf_remove(bp, args);	/*	 * If the result is small enough, shrink it all into the inode.	 */	if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {		XFS_BMAP_INIT(args->flist, args->firstblock);		error = xfs_attr_leaf_to_shortform(bp, args, forkoff);		/* bp is gone due to xfs_da_shrink_inode */		if (!error) {			error = xfs_bmap_finish(&args->trans, args->flist,						&committed);		}		if (error) {			ASSERT(committed);			args->trans = NULL;			xfs_bmap_cancel(args->flist);			return(error);		}		/*		 * bmap_finish() may have committed the last trans and started		 * a new one.  We need the inode to be in all transactions.		 */		if (committed) {			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);			xfs_trans_ihold(args->trans, dp);		}	} else		xfs_da_buf_done(bp);	return(0);}/* * Look up a name in a leaf attribute list structure. * * This leaf block cannot have a "remote" value, we only call this routine * if bmap_one_block() says there is only one block (ie: no remote blks). */STATIC intxfs_attr_leaf_get(xfs_da_args_t *args){	xfs_dabuf_t *bp;	int error;	args->blkno = 0;	error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,					     XFS_ATTR_FORK);	if (error)		return(error);	ASSERT(bp != NULL);	error = xfs_attr_leaf_lookup_int(bp, args);	if (error != EEXIST)  {		xfs_da_brelse(args->trans, bp);		return(error);	}	error = xfs_attr_leaf_getvalue(bp, args);	xfs_da_brelse(args->trans, bp);	if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {		error = xfs_attr_rmtval_get(args);	}	return(error);}/* * Copy out attribute entries for attr_list(), for leaf attribute lists. */STATIC intxfs_attr_leaf_list(xfs_attr_list_context_t *context){	xfs_attr_leafblock_t *leaf;	int error;	xfs_dabuf_t *bp;	context->cursor->blkno = 0;	error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);	if (error)		return XFS_ERROR(error);	ASSERT(bp != NULL);	leaf = bp->data;	if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) {		XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,				     context->dp->i_mount, leaf);		xfs_da_brelse(NULL, bp);		return XFS_ERROR(EFSCORRUPTED);	}	error = xfs_attr_leaf_list_int(bp, context);	xfs_da_brelse(NULL, bp);	return XFS_ERROR(error);}/*======================================================================== * External routines when attribute list size > XFS_LBSIZE(mp). *========================================================================*//* * Add a name to a Btree-format attribute list. * * This will involve walking down the Btree, and may involve splitting * leaf nodes and even splitting intermediate nodes up to and including * the root node (a special case of an intermediate node). * * "Remote" attribute values confuse the issue and atomic rename operations * add a whole extra layer of confusion on top of that. */STATIC intxfs_attr_node_addname(xfs_da_args_t *args){	xfs_da_state_t *state;	xfs_da_state_blk_t *blk;	xfs_inode_t *dp;	xfs_mount_t *mp;	int committed, retval, error;	/*	 * Fill in bucket of arguments/results/context to carry around.	 */	dp = args->dp;	mp = dp->i_mount;restart:	state = xfs_da_state_alloc();	state->args = args;	state->mp = mp;	state->blocksize = state->mp->m_sb.sb_blocksize;	state->node_ents = state->mp->m_attr_node_ents;	/*	 * Search to see if name already exists, and get back a pointer	 * to where it should go.	 */	error = xfs_da_node_lookup_int(state, &retval);	if (error)		goto out;	blk = &state->path.blk[ state->path.active-1 ];	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);	if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {		goto out;	} else if (retval == EEXIST) {		if (args->flags & ATTR_CREATE)			goto out;		args->rename = 1;			/* atomic rename op */		args->blkno2 = args->blkno;		/* set 2nd entry info*/		args->index2 = args->index;		args->rmtblkno2 = args->rmtblkno;		args->rmtblkcnt2 = args->rmtblkcnt;		args->rmtblkno = 0;		args->rmtblkcnt = 0;	}	retval = xfs_attr_leaf_add(blk->bp, state->args);	if (retval == ENOSPC) {		if (state->path.active == 1) {			/*			 * Its really a single leaf node, but it had			 * out-of-line values so it looked like it *might*			 * have been a b-tree.			 */			xfs_da_state_free(state);			XFS_BMAP_INIT(args->flist, args->firstblock);			error = xfs_attr_leaf_to_node(args);			if (!error) {				error = xfs_bmap_finish(&args->trans,							args->flist,							&committed);			}			if (error) {				ASSERT(committed);				args->trans = NULL;				xfs_bmap_cancel(args->flist);				goto out;			}			/*			 * bmap_finish() may have committed the last trans			 * and started a new one.  We need the inode to be			 * in all transactions.			 */			if (committed) {				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);				xfs_trans_ihold(args->trans, dp);			}			/*			 * Commit the node conversion and start the next			 * trans in the chain.			 */			if ((error = xfs_attr_rolltrans(&args->trans, dp)))				goto out;			goto restart;		}		/*		 * Split as many Btree elements as required.		 * This code tracks the new and old attr's location		 * in the index/blkno/rmtblkno/rmtblkcnt fields and		 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.		 */		XFS_BMAP_INIT(args->flist, args->firstblock);		error = xfs_da_split(state);		if (!error) {			error = xfs_bmap_finish(&args->trans, args->flist,						&committed);		}		if (error) {			ASSERT(committed);			args->trans = NULL;			xfs_bmap_cancel(args->flist);			goto out;		}		/*		 * bmap_finish() may have committed the last trans and started		 * a new one.  We need the inode to be in all transactions.		 */		if (committed) {			xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);			xfs_trans_ihold(args->trans, dp);		}	} else {		/*		 * Addition succeeded, update Btree hashvals.		 */		xfs_da_fixhashpath(state, &state->path);	}	/*	 * Kill the state structure, we're done with it and need to	 * allow the buffers to come back later.	 */	xfs_da_state_free(state);	state = NULL;	/*	 * Commit the leaf addition or btree split and start the next	 * trans in the chain.	 */	if ((error = xfs_attr_rolltrans(&args->trans, dp)))		goto out;	/*	 * If there was an out-of-line value, allocate the blocks we	 * identified for its storage and copy the value.  This is done	 * after we create the attribute so that we don't overflow the	 * maximum size of a transaction and/or hit a deadlock.	 */	if (args->rmtblkno > 0) {		error = xfs_attr_rmtval_set(args);		if (error)			return(error);	}	/*	 * If this is an atomic rename operation, we must "flip" the	 * incomplete flags on the "new" and "old" attribute/value pairs	 * so that one disappears and one appears atomically.  Then we	 * must remove the "old" attribute/value pair.	 */	if (args->rename) {		/*		 * In a separate transaction, set the incomplete flag on the		 * "old" attr and clear the incomplete flag on the "new" attr.		 */		error = xfs_attr_leaf_flipflags(args);		if (error)			goto out;		/*		 * Dismantle the "old" attribute/value pair by removing		 * a "remote" value (if it exists).		 */		args->index = args->index2;		args->blkno = args->blkno2;		args->rmtblkno = args->rmtblkno2;		args->rmtblkcnt = args->rmtblkcnt2;		if (args->rmtblkno) {			error = xfs_attr_rmtval_remove(args);			if (error)				return(error);		}		/*		 * Re-find the "old" attribute entry after any split ops.		 * The INCOMPLETE flag means that we will find the "old"		 * attr, not the "new" one.		 */		args->flags |= XFS_ATTR_INCOMPLETE;		state = xfs_da_state_alloc();		state->args = args;		state->mp = mp;		state->blocksize = state->mp->m_sb.sb_blocksize;		state->node_ents = state->mp->m_attr_node_ents;		state->inleaf = 0;		error = xfs_da_node_lookup_int(state, &retval);		if (error)			goto out;		/*		 * Remove the name and update the hashvals in the tree.		 */		blk = &state->path.blk[ state->path.active-1 ];		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);		error = xfs_attr_leaf_remove(blk->bp, args);		xfs_da_fixhashpath(state, &state->path);		/*		 * Check to see if the tree needs to be collapsed.		 */		if (retval && (state->path.active > 1)) {			XFS_BMAP_INIT(args->flist, args->firstblock);			error = xfs_da_join(state);			if (!error) {				error = xfs_bmap_finish(&args->trans,							args->flist,							&committed);			}			if (error) {				ASSERT(committed);				args->trans = NULL;				xfs_bmap_cancel(args->flist);				goto out;			}			/*			 * bmap_finish() may have committed the last trans			 * and started a new one.  We need the inode to be			 * in all transactions.			 */			if (committed) {				xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL);				xfs_trans_ihold(args->trans, dp);			}		}		/*		 * Commit and start the next trans in the chain.		 */		if ((error = xfs_attr_rolltrans(&args->trans, dp)))			goto out;

⌨️ 快捷键说明

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