[PATCH 10/14] xfs: introduce XFS_ATTRUPDATE_FLAGS operation

Andrey Albershteyn
2024-12-29T13:39:08Z

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(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 5060c266f776..55b18ec8bc10 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -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. */
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 0e51d0723f9a..b851e2e4b63c 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -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);
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index 15dec19b6c32..9f1b02a599d2 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -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 */

/*
diff --git a/fs/xfs/xfs_attr_item.c b/fs/xfs/xfs_attr_item.c
index f683b7a9323f..f392c95905b5 100644
--- a/fs/xfs/xfs_attr_item.c
+++ b/fs/xfs/xfs_attr_item.c
@@ -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);
diff --git a/fs/xfs/xfs_attr_item.h b/fs/xfs/xfs_attr_item.h
index e74128cbb722..f6f169631eb7 100644
--- a/fs/xfs/xfs_attr_item.h
+++ b/fs/xfs/xfs_attr_item.h
@@ -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);
diff --git a/fs/xfs/xfs_stats.h b/fs/xfs/xfs_stats.h
index a61fb56ed2e6..007c22e2cad2 100644
--- a/fs/xfs/xfs_stats.h
+++ b/fs/xfs/xfs_stats.h
@@ -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;
--
2.47.0