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

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
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "xfs_trans_space.h" #include "xfs_trans_space.h"
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_attr_item.h" #include "xfs_attr_item.h"
#include "xfs_log.h"
struct kmem_cache *xfs_attri_cache; struct kmem_cache *xfs_attri_cache;
struct kmem_cache *xfs_attrd_cache; struct kmem_cache *xfs_attrd_cache;
...@@ -729,6 +730,7 @@ xfs_attr_set( ...@@ -729,6 +730,7 @@ xfs_attr_set(
int error, local; int error, local;
int rmt_blks = 0; int rmt_blks = 0;
unsigned int total; unsigned int total;
int delayed = xfs_has_larp(mp);
if (xfs_is_shutdown(dp->i_mount)) if (xfs_is_shutdown(dp->i_mount))
return -EIO; return -EIO;
...@@ -785,13 +787,19 @@ xfs_attr_set( ...@@ -785,13 +787,19 @@ xfs_attr_set(
rmt_blks = xfs_attr3_rmt_blocks(mp, XFS_XATTR_SIZE_MAX); 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 * Root fork attributes can use reserved data blocks for this
* operation if necessary * operation if necessary
*/ */
error = xfs_trans_alloc_inode(dp, &tres, total, 0, rsvd, &args->trans); error = xfs_trans_alloc_inode(dp, &tres, total, 0, rsvd, &args->trans);
if (error) if (error)
return error; goto drop_incompat;
if (args->value || xfs_inode_hasattr(dp)) { if (args->value || xfs_inode_hasattr(dp)) {
error = xfs_iext_count_may_overflow(dp, XFS_ATTR_FORK, error = xfs_iext_count_may_overflow(dp, XFS_ATTR_FORK,
...@@ -812,9 +820,10 @@ xfs_attr_set( ...@@ -812,9 +820,10 @@ xfs_attr_set(
if (error != -ENOATTR && error != -EEXIST) if (error != -ENOATTR && error != -EEXIST)
goto out_trans_cancel; goto out_trans_cancel;
error = xfs_attr_set_args(args); error = xfs_attr_set_deferred(args);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
/* shortform attribute has already been committed */ /* shortform attribute has already been committed */
if (!args->trans) if (!args->trans)
goto out_unlock; goto out_unlock;
...@@ -822,7 +831,7 @@ xfs_attr_set( ...@@ -822,7 +831,7 @@ xfs_attr_set(
if (error != -EEXIST) if (error != -EEXIST)
goto out_trans_cancel; goto out_trans_cancel;
error = xfs_attr_remove_args(args); error = xfs_attr_remove_deferred(args);
if (error) if (error)
goto out_trans_cancel; goto out_trans_cancel;
} }
...@@ -844,6 +853,9 @@ xfs_attr_set( ...@@ -844,6 +853,9 @@ xfs_attr_set(
error = xfs_trans_commit(args->trans); error = xfs_trans_commit(args->trans);
out_unlock: out_unlock:
xfs_iunlock(dp, XFS_ILOCK_EXCL); xfs_iunlock(dp, XFS_ILOCK_EXCL);
drop_incompat:
if (delayed)
xlog_drop_incompat_feat(mp->m_log);
return error; return error;
out_trans_cancel: out_trans_cancel:
...@@ -886,6 +898,58 @@ xfs_attrd_destroy_cache(void) ...@@ -886,6 +898,58 @@ xfs_attrd_destroy_cache(void)
xfs_attrd_cache = NULL; 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 * External routines when attribute list is inside the inode
*========================================================================*/ *========================================================================*/
......
...@@ -525,6 +525,8 @@ bool xfs_attr_namecheck(const void *name, size_t length); ...@@ -525,6 +525,8 @@ bool xfs_attr_namecheck(const void *name, size_t length);
void xfs_delattr_context_init(struct xfs_delattr_context *dac, void xfs_delattr_context_init(struct xfs_delattr_context *dac,
struct xfs_da_args *args); struct xfs_da_args *args);
int xfs_attr_calc_size(struct xfs_da_args *args, int *local); 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_attri_cache;
extern struct kmem_cache *xfs_attrd_cache; extern struct kmem_cache *xfs_attrd_cache;
......
...@@ -3877,3 +3877,44 @@ xlog_drop_incompat_feat( ...@@ -3877,3 +3877,44 @@ xlog_drop_incompat_feat(
{ {
up_read(&log->l_incompat_users); 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;
}
...@@ -153,5 +153,6 @@ bool xlog_force_shutdown(struct xlog *log, uint32_t shutdown_flags); ...@@ -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_use_incompat_feat(struct xlog *log);
void xlog_drop_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__ */ #endif /* __XFS_LOG_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment