@@ -855,6 +855,13 @@ xfs_attr_set_iter(
attr->xattri_dela_state++;
break;
+ case XFS_DAS_LEAF_FLAGS_UPDATE:
+ error = xfs_attr3_leaf_setcrc(args);
+ if (error)
+ return error;
+ attr->xattri_dela_state = XFS_DAS_DONE;
+ break;
+
case XFS_DAS_LEAF_SET_RMT:
case XFS_DAS_NODE_SET_RMT:
error = xfs_attr_rmtval_find_space(attr);
@@ -1093,6 +1100,11 @@ xfs_attr_set(
tres = M_RES(mp)->tr_attrrm;
total = XFS_ATTRRM_SPACE_RES(mp);
break;
+ case XFS_ATTRUPDATE_FLAGS:
+ XFS_STATS_INC(mp, xs_attr_flags);
+ tres = M_RES(mp)->tr_attrrm;
+ total = XFS_ATTRRM_SPACE_RES(mp);
+ break;
}
/*
@@ -1119,6 +1131,11 @@ xfs_attr_set(
break;
}
+ if (op == XFS_ATTRUPDATE_FLAGS) {
+ xfs_attr_defer_add(args, XFS_ATTR_DEFER_FLAGS);
+ break;
+ }
+
/* Pure create fails if the attr already exists */
if (op == XFS_ATTRUPDATE_CREATE)
goto out_trans_cancel;
@@ -1126,7 +1143,7 @@ xfs_attr_set(
break;
case -ENOATTR:
/* Can't remove what isn't there. */
- if (op == XFS_ATTRUPDATE_REMOVE)
+ if (op == XFS_ATTRUPDATE_REMOVE || op == XFS_ATTRUPDATE_FLAGS)
goto out_trans_cancel;
/* Pure replace fails if no existing attr to replace. */
@@ -448,6 +448,7 @@ enum xfs_delattr_state {
XFS_DAS_LEAF_ADD, /* Initial leaf add state */
XFS_DAS_LEAF_REMOVE, /* Initial leaf replace/remove state */
+ XFS_DAS_LEAF_FLAGS_UPDATE, /* Update leaf XFS_ATTR_* flags and CRC */
XFS_DAS_NODE_ADD, /* Initial node add state */
XFS_DAS_NODE_REMOVE, /* Initial node replace/remove state */
@@ -477,6 +478,7 @@ enum xfs_delattr_state {
{ XFS_DAS_SF_REMOVE, "XFS_DAS_SF_REMOVE" }, \
{ XFS_DAS_LEAF_ADD, "XFS_DAS_LEAF_ADD" }, \
{ XFS_DAS_LEAF_REMOVE, "XFS_DAS_LEAF_REMOVE" }, \
+ { XFS_DAS_LEAF_FLAGS_UPDATE, "XFS_DAS_LEAF_FLAGS_UPDATE" }, \
{ XFS_DAS_NODE_ADD, "XFS_DAS_NODE_ADD" }, \
{ XFS_DAS_NODE_REMOVE, "XFS_DAS_NODE_REMOVE" }, \
{ XFS_DAS_LEAF_SET_RMT, "XFS_DAS_LEAF_SET_RMT" }, \
@@ -556,6 +558,7 @@ enum xfs_attr_update {
XFS_ATTRUPDATE_UPSERT, /* set value, replace any existing attr */
XFS_ATTRUPDATE_CREATE, /* set value, fail if attr already exists */
XFS_ATTRUPDATE_REPLACE, /* set value, fail if attr does not exist */
+ XFS_ATTRUPDATE_FLAGS, /* update attribute flags and metadata */
};
int xfs_attr_set(struct xfs_da_args *args, enum xfs_attr_update op, bool rsvd);
@@ -1035,6 +1035,7 @@ struct xfs_icreate_log {
#define XFS_ATTRI_OP_FLAGS_PPTR_SET 4 /* Set parent pointer */
#define XFS_ATTRI_OP_FLAGS_PPTR_REMOVE 5 /* Remove parent pointer */
#define XFS_ATTRI_OP_FLAGS_PPTR_REPLACE 6 /* Replace parent pointer */
+#define XFS_ATTRI_OP_FLAGS_FLAGS_UPDATE 7 /* Update attribute flags */
#define XFS_ATTRI_OP_FLAGS_TYPE_MASK 0xFF /* Flags type mask */
/*
@@ -908,6 +908,9 @@ xfs_attr_defer_add(
else
log_op = XFS_ATTRI_OP_FLAGS_REMOVE;
break;
+ case XFS_ATTR_DEFER_FLAGS:
+ log_op = XFS_ATTRI_OP_FLAGS_FLAGS_UPDATE;
+ break;
default:
ASSERT(0);
break;
@@ -931,6 +934,9 @@ xfs_attr_defer_add(
case XFS_ATTRI_OP_FLAGS_REMOVE:
new->xattri_dela_state = xfs_attr_init_remove_state(args);
break;
+ case XFS_ATTRI_OP_FLAGS_FLAGS_UPDATE:
+ new->xattri_dela_state = XFS_DAS_LEAF_FLAGS_UPDATE;
+ break;
}
xfs_defer_add(args->trans, &new->xattri_list, &xfs_attr_defer_type);
@@ -57,6 +57,7 @@ enum xfs_attr_defer_op {
XFS_ATTR_DEFER_SET,
XFS_ATTR_DEFER_REMOVE,
XFS_ATTR_DEFER_REPLACE,
+ XFS_ATTR_DEFER_FLAGS,
};
void xfs_attr_defer_add(struct xfs_da_args *args, enum xfs_attr_defer_op op);
@@ -96,6 +96,7 @@ struct __xfsstats {
uint32_t xs_attr_get;
uint32_t xs_attr_set;
uint32_t xs_attr_remove;
+ uint32_t xs_attr_flags;
uint32_t xs_attr_list;
uint32_t xs_iflush_count;
uint32_t xs_icluster_flushcnt;
The extended attributes mapped through page cache need a way to reset XFS_ATTR_INCOMPLETE flag and set data CRC when data IO is complete. Introduce this new operation which now applies only to leaf attributes. Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org> --- fs/xfs/libxfs/xfs_attr.c | 19 ++++++++++++++++++- fs/xfs/libxfs/xfs_attr.h | 3 +++ fs/xfs/libxfs/xfs_log_format.h | 1 + fs/xfs/xfs_attr_item.c | 6 ++++++ fs/xfs/xfs_attr_item.h | 1 + fs/xfs/xfs_stats.h | 1 + 6 files changed, 30 insertions(+), 1 deletion(-)