]> git-server-git.apps.pok.os.sepia.ceph.com Git - xfsprogs-dev.git/commitdiff
xfs: add a method to replace shortform attrs
authorDarrick J. Wong <djwong@kernel.org>
Sun, 22 Feb 2026 22:41:09 +0000 (14:41 -0800)
committerAndrey Albershteyn <aalbersh@kernel.org>
Wed, 8 Apr 2026 19:39:56 +0000 (21:39 +0200)
Source kernel commit: eaec8aeff31d0679eadb27a13a62942ddbfd7b87

If we're trying to replace an xattr in a shortform attr structure and
the old entry fits the new entry, we can just memcpy and exit without
having to delete, compact, and re-add the entry (or worse use the attr
intent machinery).  For parent pointers this only advantages renaming
where the filename length stays the same (e.g. mv autoexec.bat
scandisk.exe) but for regular xattrs it might be useful for updating
security labels and the like.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
include/xfs_trace.h
libxfs/xfs_attr.c
libxfs/xfs_attr_leaf.c
libxfs/xfs_attr_leaf.h

index 6bbf4007cbbbd9fd3f05a4612968718db207bb71..be9183fc33ad900509b60eaaccb40337e3af3d35 100644 (file)
@@ -57,6 +57,7 @@
 #define trace_xfs_attr_defer_replace(...)      ((void) 0)
 #define trace_xfs_attr_defer_remove(...)       ((void) 0)
 #define trace_xfs_attr_sf_addname_return(...)  ((void) 0)
+#define trace_xfs_attr_sf_replace(...)         ((void) 0)
 #define trace_xfs_attr_set_iter_return(...)    ((void) 0)
 #define trace_xfs_attr_leaf_addname_return(...)        ((void) 0)
 #define trace_xfs_attr_node_addname_return(...)        ((void) 0)
index 0b45e72b5478b486317dc932d115c5c1e866d560..a2611aace8190f9f02b669bc1d191c2d84c19b74 100644 (file)
@@ -1084,6 +1084,10 @@ xfs_attr_replacename(
                return 0;
        }
 
+       error = xfs_attr_shortform_replace(args);
+       if (error != -ENOSPC)
+               return error;
+
        args->op_flags |= XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE;
 
        error = xfs_attr_sf_removename(args);
index f591984c3748ff8d27e12ebf7e293db4867bf8b3..90be21a3887642335eb937f148bd1b8e54979ad0 100644 (file)
@@ -839,6 +839,44 @@ xfs_attr_sf_findname(
        return NULL;
 }
 
+/*
+ * Replace a shortform xattr if it's the right length.  Returns 0 on success,
+ * -ENOSPC if the length is wrong, or -ENOATTR if the attr was not found.
+ */
+int
+xfs_attr_shortform_replace(
+       struct xfs_da_args              *args)
+{
+       struct xfs_attr_sf_entry        *sfe;
+
+       ASSERT(args->dp->i_af.if_format == XFS_DINODE_FMT_LOCAL);
+
+       trace_xfs_attr_sf_replace(args);
+
+       sfe = xfs_attr_sf_findname(args);
+       if (!sfe)
+               return -ENOATTR;
+
+       if (args->attr_filter & XFS_ATTR_PARENT) {
+               if (sfe->namelen != args->new_namelen ||
+                   sfe->valuelen != args->new_valuelen)
+                       return -ENOSPC;
+
+               memcpy(sfe->nameval, args->new_name, sfe->namelen);
+               memcpy(&sfe->nameval[sfe->namelen], args->new_value,
+                               sfe->valuelen);
+       } else {
+               if (sfe->valuelen != args->valuelen)
+                       return -ENOSPC;
+               memcpy(&sfe->nameval[sfe->namelen], args->value,
+                               sfe->valuelen);
+       }
+
+       xfs_trans_log_inode(args->trans, args->dp,
+                       XFS_ILOG_CORE | XFS_ILOG_ADATA);
+       return 0;
+}
+
 /*
  * Add a name/value pair to the shortform attribute list.
  * Overflow from the inode has already been checked for.
index 589f810eedc0d846fa56e1d72c8b69dba03969a7..aca46da2bc502ee672008bce8adf0152c3e0424f 100644 (file)
@@ -46,6 +46,7 @@ struct xfs_attr3_icleaf_hdr {
  * Internal routines when attribute fork size < XFS_LITINO(mp).
  */
 void   xfs_attr_shortform_create(struct xfs_da_args *args);
+int    xfs_attr_shortform_replace(struct xfs_da_args *args);
 void   xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
 int    xfs_attr_shortform_getvalue(struct xfs_da_args *args);
 int    xfs_attr_shortform_to_leaf(struct xfs_da_args *args);