Commit f3f36c89 authored by Allison Henderson's avatar Allison Henderson Committed by Dave Chinner
Browse files

xfs: Add xfs_attr_set_deferred and xfs_attr_remove_deferred



These routines set up and queue a new deferred attribute operations.
These functions are meant to be called by any routine needing to
initiate a deferred attribute operation as opposed to the existing
inline operations. New helper function xfs_attr_item_init also added.

Finally enable delayed attributes in xfs_attr_set and xfs_attr_remove.

Signed-off-by: default avatarAllison Henderson <allison.henderson@oracle.com>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChandan Babu R <chandanrlinux@gmail.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent f38dc503
Loading
Loading
Loading
Loading
+67 −3
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "xfs_trans_space.h"
#include "xfs_trace.h"
#include "xfs_attr_item.h"
#include "xfs_log.h"

struct kmem_cache		*xfs_attri_cache;
struct kmem_cache		*xfs_attrd_cache;
@@ -729,6 +730,7 @@ xfs_attr_set(
	int			error, local;
	int			rmt_blks = 0;
	unsigned int		total;
	int			delayed = xfs_has_larp(mp);

	if (xfs_is_shutdown(dp->i_mount))
		return -EIO;
@@ -785,13 +787,19 @@ xfs_attr_set(
		rmt_blks = xfs_attr3_rmt_blocks(mp, XFS_XATTR_SIZE_MAX);
	}

	if (delayed) {
		error = xfs_attr_use_log_assist(mp);
		if (error)
			return error;
	}

	/*
	 * Root fork attributes can use reserved data blocks for this
	 * operation if necessary
	 */
	error = xfs_trans_alloc_inode(dp, &tres, total, 0, rsvd, &args->trans);
	if (error)
		return error;
		goto drop_incompat;

	if (args->value || xfs_inode_hasattr(dp)) {
		error = xfs_iext_count_may_overflow(dp, XFS_ATTR_FORK,
@@ -812,9 +820,10 @@ xfs_attr_set(
		if (error != -ENOATTR && error != -EEXIST)
			goto out_trans_cancel;

		error = xfs_attr_set_args(args);
		error = xfs_attr_set_deferred(args);
		if (error)
			goto out_trans_cancel;

		/* shortform attribute has already been committed */
		if (!args->trans)
			goto out_unlock;
@@ -822,7 +831,7 @@ xfs_attr_set(
		if (error != -EEXIST)
			goto out_trans_cancel;

		error = xfs_attr_remove_args(args);
		error = xfs_attr_remove_deferred(args);
		if (error)
			goto out_trans_cancel;
	}
@@ -844,6 +853,9 @@ xfs_attr_set(
	error = xfs_trans_commit(args->trans);
out_unlock:
	xfs_iunlock(dp, XFS_ILOCK_EXCL);
drop_incompat:
	if (delayed)
		xlog_drop_incompat_feat(mp->m_log);
	return error;

out_trans_cancel:
@@ -886,6 +898,58 @@ xfs_attrd_destroy_cache(void)
	xfs_attrd_cache = NULL;
}

STATIC int
xfs_attr_item_init(
	struct xfs_da_args	*args,
	unsigned int		op_flags,	/* op flag (set or remove) */
	struct xfs_attr_item	**attr)		/* new xfs_attr_item */
{

	struct xfs_attr_item	*new;

	new = kmem_zalloc(sizeof(struct xfs_attr_item), KM_NOFS);
	new->xattri_op_flags = op_flags;
	new->xattri_dac.da_args = args;

	*attr = new;
	return 0;
}

/* Sets an attribute for an inode as a deferred operation */
int
xfs_attr_set_deferred(
	struct xfs_da_args	*args)
{
	struct xfs_attr_item	*new;
	int			error = 0;

	error = xfs_attr_item_init(args, XFS_ATTR_OP_FLAGS_SET, &new);
	if (error)
		return error;

	xfs_defer_add(args->trans, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);

	return 0;
}

/* Removes an attribute for an inode as a deferred operation */
int
xfs_attr_remove_deferred(
	struct xfs_da_args	*args)
{

	struct xfs_attr_item	*new;
	int			error;

	error  = xfs_attr_item_init(args, XFS_ATTR_OP_FLAGS_REMOVE, &new);
	if (error)
		return error;

	xfs_defer_add(args->trans, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);

	return 0;
}

/*========================================================================
 * External routines when attribute list is inside the inode
 *========================================================================*/
+2 −0
Original line number Diff line number Diff line
@@ -525,6 +525,8 @@ bool xfs_attr_namecheck(const void *name, size_t length);
void xfs_delattr_context_init(struct xfs_delattr_context *dac,
			      struct xfs_da_args *args);
int xfs_attr_calc_size(struct xfs_da_args *args, int *local);
int xfs_attr_set_deferred(struct xfs_da_args *args);
int xfs_attr_remove_deferred(struct xfs_da_args *args);

extern struct kmem_cache	*xfs_attri_cache;
extern struct kmem_cache	*xfs_attrd_cache;
+41 −0
Original line number Diff line number Diff line
@@ -3877,3 +3877,44 @@ xlog_drop_incompat_feat(
{
	up_read(&log->l_incompat_users);
}

/*
 * Get permission to use log-assisted atomic exchange of file extents.
 *
 * Callers must not be running any transactions or hold any inode locks, and
 * they must release the permission by calling xlog_drop_incompat_feat
 * when they're done.
 */
int
xfs_attr_use_log_assist(
	struct xfs_mount	*mp)
{
	int			error = 0;

	/*
	 * Protect ourselves from an idle log clearing the logged xattrs log
	 * incompat feature bit.
	 */
	xlog_use_incompat_feat(mp->m_log);

	/*
	 * If log-assisted xattrs are already enabled, the caller can use the
	 * log assisted swap functions with the log-incompat reference we got.
	 */
	if (xfs_sb_version_haslogxattrs(&mp->m_sb))
		return 0;

	/* Enable log-assisted xattrs. */
	error = xfs_add_incompat_log_feature(mp,
			XFS_SB_FEAT_INCOMPAT_LOG_XATTRS);
	if (error)
		goto drop_incompat;

	xfs_warn_once(mp,
"EXPERIMENTAL logged extended attributes feature added. Use at your own risk!");

	return 0;
drop_incompat:
	xlog_drop_incompat_feat(mp->m_log);
	return error;
}
+1 −0
Original line number Diff line number Diff line
@@ -153,5 +153,6 @@ bool xlog_force_shutdown(struct xlog *log, uint32_t shutdown_flags);

void xlog_use_incompat_feat(struct xlog *log);
void xlog_drop_incompat_feat(struct xlog *log);
int xfs_attr_use_log_assist(struct xfs_mount *mp);

#endif	/* __XFS_LOG_H__ */