Skip to content

Commit eaec8ae

Browse files
author
Darrick J. Wong
committed
xfs: add a method to replace shortform attrs
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>
1 parent d693534 commit eaec8ae

4 files changed

Lines changed: 44 additions & 0 deletions

File tree

fs/xfs/libxfs/xfs_attr.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,6 +1085,10 @@ xfs_attr_replacename(
10851085
return 0;
10861086
}
10871087

1088+
error = xfs_attr_shortform_replace(args);
1089+
if (error != -ENOSPC)
1090+
return error;
1091+
10881092
args->op_flags |= XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE;
10891093

10901094
error = xfs_attr_sf_removename(args);

fs/xfs/libxfs/xfs_attr_leaf.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,44 @@ xfs_attr_sf_findname(
842842
return NULL;
843843
}
844844

845+
/*
846+
* Replace a shortform xattr if it's the right length. Returns 0 on success,
847+
* -ENOSPC if the length is wrong, or -ENOATTR if the attr was not found.
848+
*/
849+
int
850+
xfs_attr_shortform_replace(
851+
struct xfs_da_args *args)
852+
{
853+
struct xfs_attr_sf_entry *sfe;
854+
855+
ASSERT(args->dp->i_af.if_format == XFS_DINODE_FMT_LOCAL);
856+
857+
trace_xfs_attr_sf_replace(args);
858+
859+
sfe = xfs_attr_sf_findname(args);
860+
if (!sfe)
861+
return -ENOATTR;
862+
863+
if (args->attr_filter & XFS_ATTR_PARENT) {
864+
if (sfe->namelen != args->new_namelen ||
865+
sfe->valuelen != args->new_valuelen)
866+
return -ENOSPC;
867+
868+
memcpy(sfe->nameval, args->new_name, sfe->namelen);
869+
memcpy(&sfe->nameval[sfe->namelen], args->new_value,
870+
sfe->valuelen);
871+
} else {
872+
if (sfe->valuelen != args->valuelen)
873+
return -ENOSPC;
874+
memcpy(&sfe->nameval[sfe->namelen], args->value,
875+
sfe->valuelen);
876+
}
877+
878+
xfs_trans_log_inode(args->trans, args->dp,
879+
XFS_ILOG_CORE | XFS_ILOG_ADATA);
880+
return 0;
881+
}
882+
845883
/*
846884
* Add a name/value pair to the shortform attribute list.
847885
* Overflow from the inode has already been checked for.

fs/xfs/libxfs/xfs_attr_leaf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ struct xfs_attr3_icleaf_hdr {
4646
* Internal routines when attribute fork size < XFS_LITINO(mp).
4747
*/
4848
void xfs_attr_shortform_create(struct xfs_da_args *args);
49+
int xfs_attr_shortform_replace(struct xfs_da_args *args);
4950
void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff);
5051
int xfs_attr_shortform_getvalue(struct xfs_da_args *args);
5152
int xfs_attr_shortform_to_leaf(struct xfs_da_args *args);

fs/xfs/xfs_trace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,6 +2410,7 @@ DEFINE_ATTR_EVENT(xfs_attr_sf_addname);
24102410
DEFINE_ATTR_EVENT(xfs_attr_sf_create);
24112411
DEFINE_ATTR_EVENT(xfs_attr_sf_lookup);
24122412
DEFINE_ATTR_EVENT(xfs_attr_sf_remove);
2413+
DEFINE_ATTR_EVENT(xfs_attr_sf_replace);
24132414
DEFINE_ATTR_EVENT(xfs_attr_sf_to_leaf);
24142415

24152416
DEFINE_ATTR_EVENT(xfs_attr_leaf_add);

0 commit comments

Comments
 (0)