Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+157 -17
+104 -10
fs/xfs/libxfs/xfs_attr.c
··· 350 350 */ 351 351 STATIC int 352 352 xfs_attr_try_sf_addname( 353 - struct xfs_inode *dp, 354 353 struct xfs_da_args *args) 355 354 { 356 - 357 355 int error; 358 356 359 357 /* 360 358 * Build initial attribute list (if required). 361 359 */ 362 - if (dp->i_af.if_format == XFS_DINODE_FMT_EXTENTS) 360 + if (args->dp->i_af.if_format == XFS_DINODE_FMT_EXTENTS) 363 361 xfs_attr_shortform_create(args); 364 362 365 363 error = xfs_attr_shortform_addname(args); ··· 369 371 * NOTE: this is also the error path (EEXIST, etc). 370 372 */ 371 373 if (!error) 372 - xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG); 374 + xfs_trans_ichgtime(args->trans, args->dp, XFS_ICHGTIME_CHG); 373 375 374 - if (xfs_has_wsync(dp->i_mount)) 376 + if (xfs_has_wsync(args->dp->i_mount)) 375 377 xfs_trans_set_sync(args->trans); 376 378 377 379 return error; ··· 382 384 struct xfs_attr_intent *attr) 383 385 { 384 386 struct xfs_da_args *args = attr->xattri_da_args; 385 - struct xfs_inode *dp = args->dp; 386 387 int error = 0; 387 388 388 - error = xfs_attr_try_sf_addname(dp, args); 389 + error = xfs_attr_try_sf_addname(args); 389 390 if (error != -ENOSPC) { 390 391 ASSERT(!error || error == -EEXIST); 391 392 attr->xattri_dela_state = XFS_DAS_DONE; ··· 1029 1032 } 1030 1033 1031 1034 /* 1035 + * Decide if it is theoretically possible to try to bypass the attr intent 1036 + * mechanism for better performance. Other constraints (e.g. available space 1037 + * in the existing structure) are not considered here. 1038 + */ 1039 + static inline bool 1040 + xfs_attr_can_shortcut( 1041 + const struct xfs_inode *ip) 1042 + { 1043 + return xfs_inode_has_attr_fork(ip) && xfs_attr_is_shortform(ip); 1044 + } 1045 + 1046 + /* Try to set an attr in one transaction or fall back to attr intents. */ 1047 + int 1048 + xfs_attr_setname( 1049 + struct xfs_da_args *args, 1050 + int rmt_blks) 1051 + { 1052 + int error; 1053 + 1054 + if (!rmt_blks && xfs_attr_can_shortcut(args->dp)) { 1055 + args->op_flags |= XFS_DA_OP_ADDNAME; 1056 + 1057 + error = xfs_attr_try_sf_addname(args); 1058 + if (error != -ENOSPC) 1059 + return error; 1060 + } 1061 + 1062 + xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET); 1063 + return 0; 1064 + } 1065 + 1066 + /* Try to remove an attr in one transaction or fall back to attr intents. */ 1067 + int 1068 + xfs_attr_removename( 1069 + struct xfs_da_args *args) 1070 + { 1071 + if (xfs_attr_can_shortcut(args->dp)) 1072 + return xfs_attr_sf_removename(args); 1073 + 1074 + xfs_attr_defer_add(args, XFS_ATTR_DEFER_REMOVE); 1075 + return 0; 1076 + } 1077 + 1078 + /* Try to replace an attr in one transaction or fall back to attr intents. */ 1079 + int 1080 + xfs_attr_replacename( 1081 + struct xfs_da_args *args, 1082 + int rmt_blks) 1083 + { 1084 + int error; 1085 + 1086 + if (rmt_blks || !xfs_attr_can_shortcut(args->dp)) { 1087 + xfs_attr_defer_add(args, XFS_ATTR_DEFER_REPLACE); 1088 + return 0; 1089 + } 1090 + 1091 + error = xfs_attr_shortform_replace(args); 1092 + if (error != -ENOSPC) 1093 + return error; 1094 + 1095 + args->op_flags |= XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE; 1096 + 1097 + error = xfs_attr_sf_removename(args); 1098 + if (error) 1099 + return error; 1100 + 1101 + if (args->attr_filter & XFS_ATTR_PARENT) { 1102 + /* 1103 + * Move the new name/value to the regular name/value slots and 1104 + * zero out the new name/value slots because we don't need to 1105 + * log them for a PPTR_SET operation. 1106 + */ 1107 + xfs_attr_update_pptr_replace_args(args); 1108 + args->new_name = NULL; 1109 + args->new_namelen = 0; 1110 + args->new_value = NULL; 1111 + args->new_valuelen = 0; 1112 + } 1113 + args->op_flags &= ~XFS_DA_OP_REPLACE; 1114 + 1115 + error = xfs_attr_try_sf_addname(args); 1116 + if (error != -ENOSPC) 1117 + return error; 1118 + 1119 + xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET); 1120 + return 0; 1121 + } 1122 + 1123 + /* 1032 1124 * Make a change to the xattr structure. 1033 1125 * 1034 1126 * The caller must have initialized @args, attached dquots, and must not hold ··· 1197 1111 case -EEXIST: 1198 1112 if (op == XFS_ATTRUPDATE_REMOVE) { 1199 1113 /* if no value, we are performing a remove operation */ 1200 - xfs_attr_defer_add(args, XFS_ATTR_DEFER_REMOVE); 1114 + error = xfs_attr_removename(args); 1115 + if (error) 1116 + goto out_trans_cancel; 1201 1117 break; 1202 1118 } 1203 1119 1204 1120 /* Pure create fails if the attr already exists */ 1205 1121 if (op == XFS_ATTRUPDATE_CREATE) 1206 1122 goto out_trans_cancel; 1207 - xfs_attr_defer_add(args, XFS_ATTR_DEFER_REPLACE); 1123 + 1124 + error = xfs_attr_replacename(args, rmt_blks); 1125 + if (error) 1126 + goto out_trans_cancel; 1208 1127 break; 1209 1128 case -ENOATTR: 1210 1129 /* Can't remove what isn't there. */ ··· 1219 1128 /* Pure replace fails if no existing attr to replace. */ 1220 1129 if (op == XFS_ATTRUPDATE_REPLACE) 1221 1130 goto out_trans_cancel; 1222 - xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET); 1131 + 1132 + error = xfs_attr_setname(args, rmt_blks); 1133 + if (error) 1134 + goto out_trans_cancel; 1223 1135 break; 1224 1136 default: 1225 1137 goto out_trans_cancel;
+5 -1
fs/xfs/libxfs/xfs_attr.h
··· 573 573 */ 574 574 static inline bool 575 575 xfs_attr_is_shortform( 576 - struct xfs_inode *ip) 576 + const struct xfs_inode *ip) 577 577 { 578 578 return ip->i_af.if_format == XFS_DINODE_FMT_LOCAL || 579 579 (ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS && ··· 648 648 649 649 int xfs_attr_sf_totsize(struct xfs_inode *dp); 650 650 int xfs_attr_add_fork(struct xfs_inode *ip, int size, int rsvd); 651 + 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); 651 655 652 656 #endif /* __XFS_ATTR_H__ */
+38
fs/xfs/libxfs/xfs_attr_leaf.c
··· 843 843 } 844 844 845 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 + 883 + /* 846 884 * Add a name/value pair to the shortform attribute list. 847 885 * Overflow from the inode has already been checked for. 848 886 */
+1
fs/xfs/libxfs/xfs_attr_leaf.h
··· 46 46 * Internal routines when attribute fork size < XFS_LITINO(mp). 47 47 */ 48 48 void xfs_attr_shortform_create(struct xfs_da_args *args); 49 + int xfs_attr_shortform_replace(struct xfs_da_args *args); 49 50 void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff); 50 51 int xfs_attr_shortform_getvalue(struct xfs_da_args *args); 51 52 int xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
+8 -6
fs/xfs/libxfs/xfs_parent.c
··· 29 29 #include "xfs_trans_space.h" 30 30 #include "xfs_attr_item.h" 31 31 #include "xfs_health.h" 32 + #include "xfs_attr_leaf.h" 32 33 33 34 struct kmem_cache *xfs_parent_args_cache; 34 35 ··· 203 202 xfs_inode_to_parent_rec(&ppargs->rec, dp); 204 203 xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child, 205 204 child->i_ino, parent_name); 206 - xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_SET); 207 - return 0; 205 + 206 + return xfs_attr_setname(&ppargs->args, 0); 208 207 } 209 208 210 209 /* Remove a parent pointer to reflect a dirent removal. */ ··· 225 224 xfs_inode_to_parent_rec(&ppargs->rec, dp); 226 225 xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child, 227 226 child->i_ino, parent_name); 228 - xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REMOVE); 229 - return 0; 227 + 228 + return xfs_attr_removename(&ppargs->args); 230 229 } 231 230 232 231 /* Replace one parent pointer with another to reflect a rename. */ ··· 251 250 child->i_ino, old_name); 252 251 253 252 xfs_inode_to_parent_rec(&ppargs->new_rec, new_dp); 253 + 254 254 ppargs->args.new_name = new_name->name; 255 255 ppargs->args.new_namelen = new_name->len; 256 256 ppargs->args.new_value = &ppargs->new_rec; 257 257 ppargs->args.new_valuelen = sizeof(struct xfs_parent_rec); 258 - xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REPLACE); 259 - return 0; 258 + 259 + return xfs_attr_replacename(&ppargs->args, 0); 260 260 } 261 261 262 262 /*
+1
fs/xfs/xfs_trace.h
··· 2413 2413 DEFINE_ATTR_EVENT(xfs_attr_sf_create); 2414 2414 DEFINE_ATTR_EVENT(xfs_attr_sf_lookup); 2415 2415 DEFINE_ATTR_EVENT(xfs_attr_sf_remove); 2416 + DEFINE_ATTR_EVENT(xfs_attr_sf_replace); 2416 2417 DEFINE_ATTR_EVENT(xfs_attr_sf_to_leaf); 2417 2418 2418 2419 DEFINE_ATTR_EVENT(xfs_attr_leaf_add);