xfs_attr.c

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

C
2,474
字号
	memset((char *)&args, 0, sizeof(args));	args.name = name;	args.namelen = namelen;	args.flags = flags;	args.hashval = xfs_da_hashname(args.name, args.namelen);	args.dp = dp;	args.firstblock = &firstblock;	args.flist = &flist;	args.total = 0;	args.whichfork = XFS_ATTR_FORK;	/*	 * Attach the dquots to the inode.	 */	if ((error = XFS_QM_DQATTACH(mp, dp, 0)))		return (error);	/*	 * Start our first transaction of the day.	 *	 * All future transactions during this code must be "chained" off	 * this one via the trans_dup() call.  All transactions will contain	 * the inode, and the inode will always be marked with trans_ihold().	 * Since the inode will be locked in all transactions, we must log	 * the inode in every transaction to let it float upward through	 * the log.	 */	args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM);	/*	 * Root fork attributes can use reserved data blocks for this	 * operation if necessary	 */	if (flags & ATTR_ROOT)		args.trans->t_flags |= XFS_TRANS_RESERVE;	if ((error = xfs_trans_reserve(args.trans,				      XFS_ATTRRM_SPACE_RES(mp),				      XFS_ATTRRM_LOG_RES(mp),				      0, XFS_TRANS_PERM_LOG_RES,				      XFS_ATTRRM_LOG_COUNT))) {		xfs_trans_cancel(args.trans, 0);		return(error);	}	xfs_ilock(dp, XFS_ILOCK_EXCL);	/*	 * No need to make quota reservations here. We expect to release some	 * blocks not allocate in the common case.	 */	xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL);	xfs_trans_ihold(args.trans, dp);	/*	 * Decide on what work routines to call based on the inode size.	 */	if (XFS_IFORK_Q(dp) == 0 ||	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&	     dp->i_d.di_anextents == 0)) {		error = XFS_ERROR(ENOATTR);		goto out;	}	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);		error = xfs_attr_shortform_remove(&args);		if (error) {			goto out;		}	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {		error = xfs_attr_leaf_removename(&args);	} else {		error = xfs_attr_node_removename(&args);	}	if (error) {		goto out;	}	/*	 * If this is a synchronous mount, make sure that the	 * transaction goes to disk before returning to the user.	 */	if (mp->m_flags & XFS_MOUNT_WSYNC) {		xfs_trans_set_sync(args.trans);	}	/*	 * Commit the last in the sequence of transactions.	 */	xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);	error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,				 NULL);	xfs_iunlock(dp, XFS_ILOCK_EXCL);	/*	 * Hit the inode change time.	 */	if (!error && (flags & ATTR_KERNOTIME) == 0) {		xfs_ichgtime(dp, XFS_ICHGTIME_CHG);	}	return(error);out:	if (args.trans)		xfs_trans_cancel(args.trans,			XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);	xfs_iunlock(dp, XFS_ILOCK_EXCL);	return(error);}/* * Generate a list of extended attribute names and optionally * also value lengths.  Positive return value follows the XFS * convention of being an error, zero or negative return code * is the length of the buffer returned (negated), indicating * success. */intxfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,		      attrlist_cursor_kern_t *cursor, struct cred *cred){	xfs_attr_list_context_t context;	xfs_inode_t *dp;	int error;	XFS_STATS_INC(xs_attr_list);	/*	 * Validate the cursor.	 */	if (cursor->pad1 || cursor->pad2)		return(XFS_ERROR(EINVAL));	if ((cursor->initted == 0) &&	    (cursor->hashval || cursor->blkno || cursor->offset))		return(XFS_ERROR(EINVAL));	/*	 * Check for a properly aligned buffer.	 */	if (((long)buffer) & (sizeof(int)-1))		return(XFS_ERROR(EFAULT));	if (flags & ATTR_KERNOVAL)		bufsize = 0;	/*	 * Initialize the output buffer.	 */	context.dp = dp = XFS_BHVTOI(bdp);	context.cursor = cursor;	context.count = 0;	context.dupcnt = 0;	context.resynch = 1;	context.flags = flags;	if (!(flags & ATTR_KERNAMELS)) {		context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */		context.firstu = context.bufsize;		context.alist = (attrlist_t *)buffer;		context.alist->al_count = 0;		context.alist->al_more = 0;		context.alist->al_offset[0] = context.bufsize;	}	else {		context.bufsize = bufsize;		context.firstu = context.bufsize;		context.alist = (attrlist_t *)buffer;	}	if (XFS_FORCED_SHUTDOWN(dp->i_mount))		return (EIO);	xfs_ilock(dp, XFS_ILOCK_SHARED);	if (!(flags & ATTR_SECURE) &&	     (error = xfs_iaccess(dp, S_IRUSR, cred))) {		xfs_iunlock(dp, XFS_ILOCK_SHARED);		return(XFS_ERROR(error));	}	/*	 * Decide on what work routines to call based on the inode size.	 */	xfs_attr_trace_l_c("syscall start", &context);	if (XFS_IFORK_Q(dp) == 0 ||	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&	     dp->i_d.di_anextents == 0)) {		error = 0;	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {		error = xfs_attr_shortform_list(&context);	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {		error = xfs_attr_leaf_list(&context);	} else {		error = xfs_attr_node_list(&context);	}	xfs_iunlock(dp, XFS_ILOCK_SHARED);	xfs_attr_trace_l_c("syscall end", &context);	if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) {		ASSERT(error >= 0);	}	else {	/* must return negated buffer size or the error */		if (context.count < 0)			error = XFS_ERROR(ERANGE);		else			error = -context.count;	}	return(error);}int								/* error */xfs_attr_inactive(xfs_inode_t *dp){	xfs_trans_t *trans;	xfs_mount_t *mp;	int error;	mp = dp->i_mount;	ASSERT(! XFS_NOT_DQATTACHED(mp, dp));	xfs_ilock(dp, XFS_ILOCK_SHARED);	if ((XFS_IFORK_Q(dp) == 0) ||	    (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&	     dp->i_d.di_anextents == 0)) {		xfs_iunlock(dp, XFS_ILOCK_SHARED);		return(0);	}	xfs_iunlock(dp, XFS_ILOCK_SHARED);	/*	 * Start our first transaction of the day.	 *	 * All future transactions during this code must be "chained" off	 * this one via the trans_dup() call.  All transactions will contain	 * the inode, and the inode will always be marked with trans_ihold().	 * Since the inode will be locked in all transactions, we must log	 * the inode in every transaction to let it float upward through	 * the log.	 */	trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL);	if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0,				      XFS_TRANS_PERM_LOG_RES,				      XFS_ATTRINVAL_LOG_COUNT))) {		xfs_trans_cancel(trans, 0);		return(error);	}	xfs_ilock(dp, XFS_ILOCK_EXCL);	/*	 * No need to make quota reservations here. We expect to release some	 * blocks, not allocate, in the common case.	 */	xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL);	xfs_trans_ihold(trans, dp);	/*	 * Decide on what work routines to call based on the inode size.	 */	if ((XFS_IFORK_Q(dp) == 0) ||	    (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&	     dp->i_d.di_anextents == 0)) {		error = 0;		goto out;	}	error = xfs_attr_root_inactive(&trans, dp);	if (error)		goto out;	/*	 * signal synchronous inactive transactions unless this	 * is a synchronous mount filesystem in which case we	 * know that we're here because we've been called out of	 * xfs_inactive which means that the last reference is gone	 * and the unlink transaction has already hit the disk so	 * async inactive transactions are safe.	 */	if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK,				(!(mp->m_flags & XFS_MOUNT_WSYNC)				 ? 1 : 0))))		goto out;	/*	 * Commit the last in the sequence of transactions.	 */	xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE);	error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES,				 NULL);	xfs_iunlock(dp, XFS_ILOCK_EXCL);	return(error);out:	xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);	xfs_iunlock(dp, XFS_ILOCK_EXCL);	return(error);}/*======================================================================== * External routines when attribute list is inside the inode *========================================================================*//* * Add a name to the shortform attribute list structure * This is the external routine. */STATIC intxfs_attr_shortform_addname(xfs_da_args_t *args){	int newsize, retval;	retval = xfs_attr_shortform_lookup(args);	if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {		return(retval);	} else if (retval == EEXIST) {		if (args->flags & ATTR_CREATE)			return(retval);		retval = xfs_attr_shortform_remove(args);		ASSERT(retval == 0);	}	newsize = XFS_ATTR_SF_TOTSIZE(args->dp);	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);	if ((newsize <= XFS_IFORK_ASIZE(args->dp)) &&	    (args->namelen < XFS_ATTR_SF_ENTSIZE_MAX) &&	    (args->valuelen < XFS_ATTR_SF_ENTSIZE_MAX)) {		retval = xfs_attr_shortform_add(args);		ASSERT(retval == 0);	} else {		return(XFS_ERROR(ENOSPC));	}	return(0);}/*======================================================================== * External routines when attribute list is one block *========================================================================*//* * Add a name to 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). */intxfs_attr_leaf_addname(xfs_da_args_t *args){	xfs_inode_t *dp;	xfs_dabuf_t *bp;	int retval, error, committed;	/*	 * Read the (only) block in the attribute list in.	 */	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);	/*	 * Look up the given attribute in the leaf block.  Figure out if	 * the given flags produce an error or call for an atomic rename.	 */	retval = xfs_attr_leaf_lookup_int(bp, args);	if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {		xfs_da_brelse(args->trans, bp);		return(retval);	} else if (retval == EEXIST) {		if (args->flags & ATTR_CREATE) {	/* pure create op */			xfs_da_brelse(args->trans, bp);			return(retval);		}		args->rename = 1;			/* an atomic rename */		args->blkno2 = args->blkno;		/* set 2nd entry info*/		args->index2 = args->index;		args->rmtblkno2 = args->rmtblkno;		args->rmtblkcnt2 = args->rmtblkcnt;	}	/*	 * Add the attribute to the leaf block, transitioning to a Btree	 * if required.	 */	retval = xfs_attr_leaf_add(bp, args);	xfs_da_buf_done(bp);	if (retval == ENOSPC) {		/*		 * Promote the attribute list to the Btree format, then		 * Commit that transaction so that the node_addname() call		 * can manage its own transactions.		 */		XFS_BMAP_INIT(args->flist, args->firstblock);		error = xfs_attr_leaf_to_node(args);		if (!error) {			error = xfs_bmap_finish(&args->trans, args->flist,						*args->firstblock, &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);		}		/*		 * 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.		 */

⌨️ 快捷键说明

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