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@xxxxxxxxxx> --- 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