Skip to content

Commit c04ed39

Browse files
committed
Merge tag 'attr-pptr-speedup-7.0_2026-01-25' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-7.0-merge
xfs: improve shortform attr performance [2/3] Improve performance of the xattr (and parent pointer) code when the attr structure is in short format and we can therefore perform all updates in a single transaction. Avoiding the attr intent code brings a very nice speedup in those operations. With a bit of luck, this should all go splendidly. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> Signed-off-by: Carlos Maiolino <cem@kernel.org>
2 parents 2744d7a + eaec8ae commit c04ed39

6 files changed

Lines changed: 157 additions & 17 deletions

File tree

fs/xfs/libxfs/xfs_attr.c

Lines changed: 104 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -350,16 +350,14 @@ xfs_attr_set_resv(
350350
*/
351351
STATIC int
352352
xfs_attr_try_sf_addname(
353-
struct xfs_inode *dp,
354353
struct xfs_da_args *args)
355354
{
356-
357355
int error;
358356

359357
/*
360358
* Build initial attribute list (if required).
361359
*/
362-
if (dp->i_af.if_format == XFS_DINODE_FMT_EXTENTS)
360+
if (args->dp->i_af.if_format == XFS_DINODE_FMT_EXTENTS)
363361
xfs_attr_shortform_create(args);
364362

365363
error = xfs_attr_shortform_addname(args);
@@ -371,9 +369,9 @@ xfs_attr_try_sf_addname(
371369
* NOTE: this is also the error path (EEXIST, etc).
372370
*/
373371
if (!error)
374-
xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
372+
xfs_trans_ichgtime(args->trans, args->dp, XFS_ICHGTIME_CHG);
375373

376-
if (xfs_has_wsync(dp->i_mount))
374+
if (xfs_has_wsync(args->dp->i_mount))
377375
xfs_trans_set_sync(args->trans);
378376

379377
return error;
@@ -384,10 +382,9 @@ xfs_attr_sf_addname(
384382
struct xfs_attr_intent *attr)
385383
{
386384
struct xfs_da_args *args = attr->xattri_da_args;
387-
struct xfs_inode *dp = args->dp;
388385
int error = 0;
389386

390-
error = xfs_attr_try_sf_addname(dp, args);
387+
error = xfs_attr_try_sf_addname(args);
391388
if (error != -ENOSPC) {
392389
ASSERT(!error || error == -EEXIST);
393390
attr->xattri_dela_state = XFS_DAS_DONE;
@@ -1031,6 +1028,95 @@ xfs_attr_add_fork(
10311028
return error;
10321029
}
10331030

1031+
/*
1032+
* Decide if it is theoretically possible to try to bypass the attr intent
1033+
* mechanism for better performance. Other constraints (e.g. available space
1034+
* in the existing structure) are not considered here.
1035+
*/
1036+
static inline bool
1037+
xfs_attr_can_shortcut(
1038+
const struct xfs_inode *ip)
1039+
{
1040+
return xfs_inode_has_attr_fork(ip) && xfs_attr_is_shortform(ip);
1041+
}
1042+
1043+
/* Try to set an attr in one transaction or fall back to attr intents. */
1044+
int
1045+
xfs_attr_setname(
1046+
struct xfs_da_args *args,
1047+
int rmt_blks)
1048+
{
1049+
int error;
1050+
1051+
if (!rmt_blks && xfs_attr_can_shortcut(args->dp)) {
1052+
args->op_flags |= XFS_DA_OP_ADDNAME;
1053+
1054+
error = xfs_attr_try_sf_addname(args);
1055+
if (error != -ENOSPC)
1056+
return error;
1057+
}
1058+
1059+
xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET);
1060+
return 0;
1061+
}
1062+
1063+
/* Try to remove an attr in one transaction or fall back to attr intents. */
1064+
int
1065+
xfs_attr_removename(
1066+
struct xfs_da_args *args)
1067+
{
1068+
if (xfs_attr_can_shortcut(args->dp))
1069+
return xfs_attr_sf_removename(args);
1070+
1071+
xfs_attr_defer_add(args, XFS_ATTR_DEFER_REMOVE);
1072+
return 0;
1073+
}
1074+
1075+
/* Try to replace an attr in one transaction or fall back to attr intents. */
1076+
int
1077+
xfs_attr_replacename(
1078+
struct xfs_da_args *args,
1079+
int rmt_blks)
1080+
{
1081+
int error;
1082+
1083+
if (rmt_blks || !xfs_attr_can_shortcut(args->dp)) {
1084+
xfs_attr_defer_add(args, XFS_ATTR_DEFER_REPLACE);
1085+
return 0;
1086+
}
1087+
1088+
error = xfs_attr_shortform_replace(args);
1089+
if (error != -ENOSPC)
1090+
return error;
1091+
1092+
args->op_flags |= XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE;
1093+
1094+
error = xfs_attr_sf_removename(args);
1095+
if (error)
1096+
return error;
1097+
1098+
if (args->attr_filter & XFS_ATTR_PARENT) {
1099+
/*
1100+
* Move the new name/value to the regular name/value slots and
1101+
* zero out the new name/value slots because we don't need to
1102+
* log them for a PPTR_SET operation.
1103+
*/
1104+
xfs_attr_update_pptr_replace_args(args);
1105+
args->new_name = NULL;
1106+
args->new_namelen = 0;
1107+
args->new_value = NULL;
1108+
args->new_valuelen = 0;
1109+
}
1110+
args->op_flags &= ~XFS_DA_OP_REPLACE;
1111+
1112+
error = xfs_attr_try_sf_addname(args);
1113+
if (error != -ENOSPC)
1114+
return error;
1115+
1116+
xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET);
1117+
return 0;
1118+
}
1119+
10341120
/*
10351121
* Make a change to the xattr structure.
10361122
*
@@ -1111,14 +1197,19 @@ xfs_attr_set(
11111197
case -EEXIST:
11121198
if (op == XFS_ATTRUPDATE_REMOVE) {
11131199
/* if no value, we are performing a remove operation */
1114-
xfs_attr_defer_add(args, XFS_ATTR_DEFER_REMOVE);
1200+
error = xfs_attr_removename(args);
1201+
if (error)
1202+
goto out_trans_cancel;
11151203
break;
11161204
}
11171205

11181206
/* Pure create fails if the attr already exists */
11191207
if (op == XFS_ATTRUPDATE_CREATE)
11201208
goto out_trans_cancel;
1121-
xfs_attr_defer_add(args, XFS_ATTR_DEFER_REPLACE);
1209+
1210+
error = xfs_attr_replacename(args, rmt_blks);
1211+
if (error)
1212+
goto out_trans_cancel;
11221213
break;
11231214
case -ENOATTR:
11241215
/* Can't remove what isn't there. */
@@ -1128,7 +1219,10 @@ xfs_attr_set(
11281219
/* Pure replace fails if no existing attr to replace. */
11291220
if (op == XFS_ATTRUPDATE_REPLACE)
11301221
goto out_trans_cancel;
1131-
xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET);
1222+
1223+
error = xfs_attr_setname(args, rmt_blks);
1224+
if (error)
1225+
goto out_trans_cancel;
11321226
break;
11331227
default:
11341228
goto out_trans_cancel;

fs/xfs/libxfs/xfs_attr.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ struct xfs_trans_res xfs_attr_set_resv(const struct xfs_da_args *args);
573573
*/
574574
static inline bool
575575
xfs_attr_is_shortform(
576-
struct xfs_inode *ip)
576+
const struct xfs_inode *ip)
577577
{
578578
return ip->i_af.if_format == XFS_DINODE_FMT_LOCAL ||
579579
(ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS &&
@@ -649,4 +649,8 @@ void xfs_attr_intent_destroy_cache(void);
649649
int xfs_attr_sf_totsize(struct xfs_inode *dp);
650650
int xfs_attr_add_fork(struct xfs_inode *ip, int size, int rsvd);
651651

652+
int xfs_attr_setname(struct xfs_da_args *args, int rmt_blks);
653+
int xfs_attr_removename(struct xfs_da_args *args);
654+
int xfs_attr_replacename(struct xfs_da_args *args, int rmt_blks);
655+
652656
#endif /* __XFS_ATTR_H__ */

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/libxfs/xfs_parent.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "xfs_trans_space.h"
3030
#include "xfs_attr_item.h"
3131
#include "xfs_health.h"
32+
#include "xfs_attr_leaf.h"
3233

3334
struct kmem_cache *xfs_parent_args_cache;
3435

@@ -202,8 +203,8 @@ xfs_parent_addname(
202203
xfs_inode_to_parent_rec(&ppargs->rec, dp);
203204
xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
204205
child->i_ino, parent_name);
205-
xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_SET);
206-
return 0;
206+
207+
return xfs_attr_setname(&ppargs->args, 0);
207208
}
208209

209210
/* Remove a parent pointer to reflect a dirent removal. */
@@ -224,8 +225,8 @@ xfs_parent_removename(
224225
xfs_inode_to_parent_rec(&ppargs->rec, dp);
225226
xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child,
226227
child->i_ino, parent_name);
227-
xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REMOVE);
228-
return 0;
228+
229+
return xfs_attr_removename(&ppargs->args);
229230
}
230231

231232
/* Replace one parent pointer with another to reflect a rename. */
@@ -250,12 +251,13 @@ xfs_parent_replacename(
250251
child->i_ino, old_name);
251252

252253
xfs_inode_to_parent_rec(&ppargs->new_rec, new_dp);
254+
253255
ppargs->args.new_name = new_name->name;
254256
ppargs->args.new_namelen = new_name->len;
255257
ppargs->args.new_value = &ppargs->new_rec;
256258
ppargs->args.new_valuelen = sizeof(struct xfs_parent_rec);
257-
xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REPLACE);
258-
return 0;
259+
260+
return xfs_attr_replacename(&ppargs->args, 0);
259261
}
260262

261263
/*

fs/xfs/xfs_trace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,6 +2413,7 @@ DEFINE_ATTR_EVENT(xfs_attr_sf_addname);
24132413
DEFINE_ATTR_EVENT(xfs_attr_sf_create);
24142414
DEFINE_ATTR_EVENT(xfs_attr_sf_lookup);
24152415
DEFINE_ATTR_EVENT(xfs_attr_sf_remove);
2416+
DEFINE_ATTR_EVENT(xfs_attr_sf_replace);
24162417
DEFINE_ATTR_EVENT(xfs_attr_sf_to_leaf);
24172418

24182419
DEFINE_ATTR_EVENT(xfs_attr_leaf_add);

0 commit comments

Comments
 (0)