#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;
        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;
                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,
                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;
                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;
        }
        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:
        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
  *========================================================================*/
 
 {
        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;
+}