On Tue, May 17, 2022 at 05:12:17PM -0700, Allison Henderson wrote: > Source kernel commit: 1d08e11d04d293cb7006d1c8641be1fdd8a8e397 > > This patch adds the needed routines to create, log and recover logged > extended attribute intents. > > Signed-off-by: Allison Henderson <allison.henderson@xxxxxxxxxx> > Reviewed-by: Chandan Babu R <chandanrlinux@xxxxxxxxx> > Reviewed-by: Darrick J. Wong <djwong@xxxxxxxxxx> > Signed-off-by: Dave Chinner <david@xxxxxxxxxxxxx> > Signed-off-by: Allison Henderson <allison.henderson@xxxxxxxxxx> > --- > libxfs/defer_item.c | 119 ++++++++++++++++++++++++++++++++++++++++++++ > libxfs/xfs_defer.c | 1 + > libxfs/xfs_defer.h | 1 + > libxfs/xfs_format.h | 9 +++- > 4 files changed, 129 insertions(+), 1 deletion(-) > > diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c > index 1337fa5fa457..d2d12b50cce4 100644 > --- a/libxfs/defer_item.c > +++ b/libxfs/defer_item.c > @@ -120,6 +120,125 @@ const struct xfs_defer_op_type xfs_extent_free_defer_type = { > .cancel_item = xfs_extent_free_cancel_item, > }; > > +/* > + * Performs one step of an attribute update intent and marks the attrd item > + * dirty.. An attr operation may be a set or a remove. Note that the > + * transaction is marked dirty regardless of whether the operation succeeds or > + * fails to support the ATTRI/ATTRD lifecycle rules. > + */ > +STATIC int > +xfs_trans_attr_finish_update( This ought to have a name indicating that it's an xattr operation, since defer_item.c contains stubs for what in the kernel are real logged operations. --D > + struct xfs_delattr_context *dac, > + struct xfs_buf **leaf_bp, > + uint32_t op_flags) > +{ > + struct xfs_da_args *args = dac->da_args; > + unsigned int op = op_flags & > + XFS_ATTR_OP_FLAGS_TYPE_MASK; > + int error; > + > + switch (op) { > + case XFS_ATTR_OP_FLAGS_SET: > + error = xfs_attr_set_iter(dac, leaf_bp); > + break; > + case XFS_ATTR_OP_FLAGS_REMOVE: > + ASSERT(XFS_IFORK_Q(args->dp)); > + error = xfs_attr_remove_iter(dac); > + break; > + default: > + error = -EFSCORRUPTED; > + break; > + } > + > + /* > + * Mark the transaction dirty, even on error. This ensures the > + * transaction is aborted, which: > + * > + * 1.) releases the ATTRI and frees the ATTRD > + * 2.) shuts down the filesystem > + */ > + args->trans->t_flags |= XFS_TRANS_DIRTY | XFS_TRANS_HAS_INTENT_DONE; > + > + return error; > +} > + > +/* Get an ATTRI. */ > +static struct xfs_log_item * > +xfs_attr_create_intent( > + struct xfs_trans *tp, > + struct list_head *items, > + unsigned int count, > + bool sort) > +{ > + return NULL; > +} > + > +/* Abort all pending ATTRs. */ > +STATIC void > +xfs_attr_abort_intent( > + struct xfs_log_item *intent) > +{ > +} > + > +/* Get an ATTRD so we can process all the attrs. */ > +static struct xfs_log_item * > +xfs_attr_create_done( > + struct xfs_trans *tp, > + struct xfs_log_item *intent, > + unsigned int count) > +{ > + return NULL; > +} > + > +/* Process an attr. */ > +STATIC int > +xfs_attr_finish_item( > + struct xfs_trans *tp, > + struct xfs_log_item *done, > + struct list_head *item, > + struct xfs_btree_cur **state) > +{ > + struct xfs_attr_item *attr; > + int error; > + struct xfs_delattr_context *dac; > + > + attr = container_of(item, struct xfs_attr_item, xattri_list); > + dac = &attr->xattri_dac; > + > + /* > + * Always reset trans after EAGAIN cycle > + * since the transaction is new > + */ > + dac->da_args->trans = tp; > + > + error = xfs_trans_attr_finish_update(dac, &dac->leaf_bp, > + attr->xattri_op_flags); > + if (error != -EAGAIN) > + kmem_free(attr); > + > + return error; > +} > + > +/* Cancel an attr */ > +STATIC void > +xfs_attr_cancel_item( > + struct list_head *item) > +{ > + struct xfs_attr_item *attr; > + > + attr = container_of(item, struct xfs_attr_item, xattri_list); > + kmem_free(attr); > +} > + > +const struct xfs_defer_op_type xfs_attr_defer_type = { > + .max_items = 1, > + .create_intent = xfs_attr_create_intent, > + .abort_intent = xfs_attr_abort_intent, > + .create_done = xfs_attr_create_done, > + .finish_item = xfs_attr_finish_item, > + .cancel_item = xfs_attr_cancel_item, > +}; > + > /* > * AGFL blocks are accounted differently in the reserve pools and are not > * inserted into the busy extent list. > diff --git a/libxfs/xfs_defer.c b/libxfs/xfs_defer.c > index 3a2576c14ee9..259ae39f90b5 100644 > --- a/libxfs/xfs_defer.c > +++ b/libxfs/xfs_defer.c > @@ -180,6 +180,7 @@ static const struct xfs_defer_op_type *defer_op_types[] = { > [XFS_DEFER_OPS_TYPE_RMAP] = &xfs_rmap_update_defer_type, > [XFS_DEFER_OPS_TYPE_FREE] = &xfs_extent_free_defer_type, > [XFS_DEFER_OPS_TYPE_AGFL_FREE] = &xfs_agfl_free_defer_type, > + [XFS_DEFER_OPS_TYPE_ATTR] = &xfs_attr_defer_type, > }; > > static bool > diff --git a/libxfs/xfs_defer.h b/libxfs/xfs_defer.h > index c3a540345fae..f18494c0d791 100644 > --- a/libxfs/xfs_defer.h > +++ b/libxfs/xfs_defer.h > @@ -19,6 +19,7 @@ enum xfs_defer_ops_type { > XFS_DEFER_OPS_TYPE_RMAP, > XFS_DEFER_OPS_TYPE_FREE, > XFS_DEFER_OPS_TYPE_AGFL_FREE, > + XFS_DEFER_OPS_TYPE_ATTR, > XFS_DEFER_OPS_TYPE_MAX, > }; > > diff --git a/libxfs/xfs_format.h b/libxfs/xfs_format.h > index d665c04e69dd..302b50bc5830 100644 > --- a/libxfs/xfs_format.h > +++ b/libxfs/xfs_format.h > @@ -388,7 +388,9 @@ xfs_sb_has_incompat_feature( > return (sbp->sb_features_incompat & feature) != 0; > } > > -#define XFS_SB_FEAT_INCOMPAT_LOG_ALL 0 > +#define XFS_SB_FEAT_INCOMPAT_LOG_XATTRS (1 << 0) /* Delayed Attributes */ > +#define XFS_SB_FEAT_INCOMPAT_LOG_ALL \ > + (XFS_SB_FEAT_INCOMPAT_LOG_XATTRS) > #define XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_LOG_ALL > static inline bool > xfs_sb_has_incompat_log_feature( > @@ -413,6 +415,11 @@ xfs_sb_add_incompat_log_features( > sbp->sb_features_log_incompat |= features; > } > > +static inline bool xfs_sb_version_haslogxattrs(struct xfs_sb *sbp) > +{ > + return xfs_sb_is_v5(sbp) && (sbp->sb_features_log_incompat & > + XFS_SB_FEAT_INCOMPAT_LOG_XATTRS); > +} > > static inline bool > xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino) > -- > 2.25.1 >