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

📄 xfs_attr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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);	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);}intxfs_attr_remove(	xfs_inode_t	*dp,	const char	*name,	int		flags){	int		namelen;	namelen = strlen(name);	if (namelen >= MAXNAMELEN)		return EFAULT;		/* match IRIX behaviour */	XFS_STATS_INC(xs_attr_remove);	if (XFS_FORCED_SHUTDOWN(dp->i_mount))		return (EIO);	xfs_ilock(dp, XFS_ILOCK_SHARED);	if (XFS_IFORK_Q(dp) == 0 ||		   (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&		    dp->i_d.di_anextents == 0)) {		xfs_iunlock(dp, XFS_ILOCK_SHARED);		return(XFS_ERROR(ENOATTR));	}	xfs_iunlock(dp, XFS_ILOCK_SHARED);	return xfs_attr_remove_int(dp, name, namelen, flags);}int								/* error */xfs_attr_list_int(xfs_attr_list_context_t *context){	int error;	xfs_inode_t *dp = context->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 = 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);	}	return error;}#define	ATTR_ENTBASESIZE		/* minimum bytes used by an attr */ \	(((struct attrlist_ent *) 0)->a_name - (char *) 0)#define	ATTR_ENTSIZE(namelen)		/* actual bytes used by an attr */ \	((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \	 & ~(sizeof(u_int32_t)-1))/* * Format an attribute and copy it out to the user's buffer. * Take care to check values and protect against them changing later, * we may be reading them directly out of a user buffer. *//*ARGSUSED*/STATIC intxfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp,		     char *name, int namelen,		     int valuelen, char *value){	attrlist_ent_t *aep;	int arraytop;	ASSERT(!(context->flags & ATTR_KERNOVAL));	ASSERT(context->count >= 0);	ASSERT(context->count < (ATTR_MAX_VALUELEN/8));	ASSERT(context->firstu >= sizeof(*context->alist));	ASSERT(context->firstu <= context->bufsize);	arraytop = sizeof(*context->alist) +			context->count * sizeof(context->alist->al_offset[0]);	context->firstu -= ATTR_ENTSIZE(namelen);	if (context->firstu < arraytop) {		xfs_attr_trace_l_c("buffer full", context);		context->alist->al_more = 1;		context->seen_enough = 1;		return 1;	}	aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);	aep->a_valuelen = valuelen;	memcpy(aep->a_name, name, namelen);	aep->a_name[ namelen ] = 0;	context->alist->al_offset[ context->count++ ] = context->firstu;	context->alist->al_count = context->count;	xfs_attr_trace_l_c("add", context);	return 0;}STATIC intxfs_attr_kern_list(xfs_attr_list_context_t *context, attrnames_t *namesp,		     char *name, int namelen,		     int valuelen, char *value){	char *offset;	int arraytop;	ASSERT(context->count >= 0);	arraytop = context->count + namesp->attr_namelen + namelen + 1;	if (arraytop > context->firstu) {		context->count = -1;	/* insufficient space */		return 1;	}	offset = (char *)context->alist + context->count;	strncpy(offset, namesp->attr_name, namesp->attr_namelen);	offset += namesp->attr_namelen;	strncpy(offset, name, namelen);			/* real name */	offset += namelen;	*offset = '\0';	context->count += namesp->attr_namelen + namelen + 1;	return 0;}/*ARGSUSED*/STATIC intxfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp,		     char *name, int namelen,		     int valuelen, char *value){	context->count += namesp->attr_namelen + namelen + 1;	return 0;}/* * 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(	xfs_inode_t	*dp,	char		*buffer,	int		bufsize,	int		flags,	attrlist_cursor_kern_t *cursor){	xfs_attr_list_context_t context;	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;	context.cursor = cursor;	context.count = 0;	context.dupcnt = 0;	context.resynch = 1;	context.flags = flags;	context.seen_enough = 0;	context.alist = (attrlist_t *)buffer;	context.put_value = 0;	if (flags & ATTR_KERNAMELS) {		context.bufsize = bufsize;		context.firstu = context.bufsize;		if (flags & ATTR_KERNOVAL)			context.put_listent = xfs_attr_kern_list_sizes;		else			context.put_listent = xfs_attr_kern_list;	} else {		context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */		context.firstu = context.bufsize;		context.alist->al_count = 0;		context.alist->al_more = 0;		context.alist->al_offset[0] = context.bufsize;		context.put_listent = xfs_attr_put_listent;	}	if (XFS_FORCED_SHUTDOWN(dp->i_mount))		return EIO;	xfs_ilock(dp, XFS_ILOCK_SHARED);	xfs_attr_trace_l_c("syscall start", &context);	error = xfs_attr_list_int(&context);	xfs_iunlock(dp, XFS_ILOCK_SHARED);	xfs_attr_trace_l_c("syscall end", &context);	if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) {		/* must return negated buffer size or the error */		if (context.count < 0)			error = XFS_ERROR(ERANGE);		else			error = -context.count;	} else		ASSERT(error >= 0);	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);	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, forkoff, 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);	}	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||	    args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)		return(XFS_ERROR(ENOSPC));	newsize = XFS_ATTR_SF_TOTSIZE(args->dp);	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);	forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);	if (!forkoff)		return(XFS_ERROR(ENOSPC));	xfs_attr_shortform_add(args, forkoff);	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, forkoff;	/*	 * 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,						&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

⌨️ 快捷键说明

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