Skip to content

Commit 47d83c1

Browse files
author
Chandan Babu R
committed
Merge tag 'pptrs-6.10_2024-04-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.10-mergeC
xfs: Parent Pointers This is the latest parent pointer attributes for xfs. The goal of this patch set is to add a parent pointer attribute to each inode. The attribute name containing the parent inode, generation, and directory offset, while the attribute value contains the file name. This feature will enable future optimizations for online scrub, shrink, nfs handles, verity, or any other feature that could make use of quickly deriving an inodes path from the mount point. Directory parent pointers are stored as namespaced extended attributes of a file. Because parent pointers are an indivisible tuple of (dirent_name, parent_ino, parent_gen) we cannot use the usual attr name lookup functions to find a parent pointer. This is solvable by introducing a new lookup mode that checks both the name and the value of the xattr. Therefore, introduce this new name-value lookup mode that's gated on the XFS_ATTR_PARENT namespace. This requires the introduction of new opcodes for the extended attribute update log intent items, which actually means that parent pointers (itself an INCOMPAT feature) does not depend on the LOGGED_XATTRS log incompat feature bit. To reduce collisions on the dirent names of parent pointers, introduce a new attr hash mode that is the dir2 namehash of the dirent name xor'd with the parent inode number. Signed-off-by: Darrick J. Wong <[email protected]> Signed-off-by: Chandan Babu R <[email protected]> * tag 'pptrs-6.10_2024-04-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux: xfs: enable parent pointers xfs: drop compatibility minimum log size computations for reflink xfs: fix unit conversion error in xfs_log_calc_max_attrsetm_res xfs: add a incompat feature bit for parent pointers xfs: don't remove the attr fork when parent pointers are enabled xfs: add parent pointer ioctls xfs: split out handle management helpers a bit xfs: move handle ioctl code to xfs_handle.c xfs: pass the attr value to put_listent when possible xfs: don't return XFS_ATTR_PARENT attributes via listxattr xfs: Add parent pointers to xfs_cross_rename xfs: Add parent pointers to rename xfs: remove parent pointers in unlink xfs: add parent attributes to symlink xfs: add parent attributes to link xfs: parent pointer attribute creation xfs: create a hashname function for parent pointers xfs: extend transaction reservations for parent attributes xfs: add parent pointer validator functions xfs: Expose init_xattrs in xfs_create_tmpfile xfs: record inode generation in xattr update log intent items xfs: create attr log item opcodes and formats for parent pointers xfs: refactor xfs_is_using_logged_xattrs checks in attr item recovery xfs: allow xattr matching on name and value for parent pointers xfs: define parent pointer ondisk extended attribute format xfs: add parent pointer support to attribute code xfs: create a separate hashname function for extended attributes xfs: move xfs_attr_defer_add to xfs_attr_item.c xfs: check the flags earlier in xfs_attr_match xfs: rearrange xfs_attr_match parameters
2 parents d7d02f7 + 67ac709 commit 47d83c1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2807
-832
lines changed

fs/xfs/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ xfs-y += $(addprefix libxfs/, \
4242
xfs_inode_buf.o \
4343
xfs_log_rlimit.o \
4444
xfs_ag_resv.o \
45+
xfs_parent.o \
4546
xfs_rmap.o \
4647
xfs_rmap_btree.o \
4748
xfs_refcount.o \
@@ -50,6 +51,7 @@ xfs-y += $(addprefix libxfs/, \
5051
xfs_symlink_remote.o \
5152
xfs_trans_inode.o \
5253
xfs_trans_resv.o \
54+
xfs_trans_space.o \
5355
xfs_types.o \
5456
)
5557
# xfs_rtbitmap is shared with libxfs
@@ -76,6 +78,7 @@ xfs-y += xfs_aops.o \
7678
xfs_fsmap.o \
7779
xfs_fsops.o \
7880
xfs_globals.o \
81+
xfs_handle.o \
7982
xfs_health.o \
8083
xfs_icache.o \
8184
xfs_ioctl.o \

fs/xfs/libxfs/xfs_attr.c

Lines changed: 56 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "xfs_trace.h"
2727
#include "xfs_attr_item.h"
2828
#include "xfs_xattr.h"
29+
#include "xfs_parent.h"
2930

3031
struct kmem_cache *xfs_attr_intent_cache;
3132

@@ -280,7 +281,7 @@ xfs_attr_get(
280281
args->owner = args->dp->i_ino;
281282
args->geo = args->dp->i_mount->m_attr_geo;
282283
args->whichfork = XFS_ATTR_FORK;
283-
args->hashval = xfs_da_hashname(args->name, args->namelen);
284+
xfs_attr_sethash(args);
284285

285286
/* Entirely possible to look up a name which doesn't exist */
286287
args->op_flags = XFS_DA_OP_OKNOENT;
@@ -415,6 +416,50 @@ xfs_attr_sf_addname(
415416
return error;
416417
}
417418

419+
/* Compute the hash value for a user/root/secure extended attribute */
420+
xfs_dahash_t
421+
xfs_attr_hashname(
422+
const uint8_t *name,
423+
int namelen)
424+
{
425+
return xfs_da_hashname(name, namelen);
426+
}
427+
428+
/* Compute the hash value for any extended attribute from any namespace. */
429+
xfs_dahash_t
430+
xfs_attr_hashval(
431+
struct xfs_mount *mp,
432+
unsigned int attr_flags,
433+
const uint8_t *name,
434+
int namelen,
435+
const void *value,
436+
int valuelen)
437+
{
438+
ASSERT(xfs_attr_check_namespace(attr_flags));
439+
440+
if (attr_flags & XFS_ATTR_PARENT)
441+
return xfs_parent_hashattr(mp, name, namelen, value, valuelen);
442+
443+
return xfs_attr_hashname(name, namelen);
444+
}
445+
446+
/*
447+
* PPTR_REPLACE operations require the caller to set the old and new names and
448+
* values explicitly. Update the canonical fields to the new name and value
449+
* here now that the removal phase has finished.
450+
*/
451+
static void
452+
xfs_attr_update_pptr_replace_args(
453+
struct xfs_da_args *args)
454+
{
455+
ASSERT(args->new_namelen > 0);
456+
args->name = args->new_name;
457+
args->namelen = args->new_namelen;
458+
args->value = args->new_value;
459+
args->valuelen = args->new_valuelen;
460+
xfs_attr_sethash(args);
461+
}
462+
418463
/*
419464
* Handle the state change on completion of a multi-state attr operation.
420465
*
@@ -435,6 +480,8 @@ xfs_attr_complete_op(
435480

436481
if (!(args->op_flags & XFS_DA_OP_REPLACE))
437482
replace_state = XFS_DAS_DONE;
483+
else if (xfs_attr_intent_op(attr) == XFS_ATTRI_OP_FLAGS_PPTR_REPLACE)
484+
xfs_attr_update_pptr_replace_args(args);
438485

439486
args->op_flags &= ~XFS_DA_OP_REPLACE;
440487
args->attr_filter &= ~XFS_ATTR_INCOMPLETE;
@@ -901,37 +948,6 @@ xfs_attr_lookup(
901948
return error;
902949
}
903950

904-
static void
905-
xfs_attr_defer_add(
906-
struct xfs_da_args *args,
907-
unsigned int op_flags)
908-
{
909-
910-
struct xfs_attr_intent *new;
911-
912-
new = kmem_cache_zalloc(xfs_attr_intent_cache,
913-
GFP_KERNEL | __GFP_NOFAIL);
914-
new->xattri_op_flags = op_flags;
915-
new->xattri_da_args = args;
916-
917-
switch (op_flags) {
918-
case XFS_ATTRI_OP_FLAGS_SET:
919-
new->xattri_dela_state = xfs_attr_init_add_state(args);
920-
break;
921-
case XFS_ATTRI_OP_FLAGS_REPLACE:
922-
new->xattri_dela_state = xfs_attr_init_replace_state(args);
923-
break;
924-
case XFS_ATTRI_OP_FLAGS_REMOVE:
925-
new->xattri_dela_state = xfs_attr_init_remove_state(args);
926-
break;
927-
default:
928-
ASSERT(0);
929-
}
930-
931-
xfs_defer_add(args->trans, &new->xattri_list, &xfs_attr_defer_type);
932-
trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp);
933-
}
934-
935951
int
936952
xfs_attr_set(
937953
struct xfs_da_args *args,
@@ -956,7 +972,7 @@ xfs_attr_set(
956972
args->owner = args->dp->i_ino;
957973
args->geo = mp->m_attr_geo;
958974
args->whichfork = XFS_ATTR_FORK;
959-
args->hashval = xfs_da_hashname(args->name, args->namelen);
975+
xfs_attr_sethash(args);
960976

961977
/*
962978
* We have no control over the attribute names that userspace passes us
@@ -1021,14 +1037,14 @@ xfs_attr_set(
10211037
case -EEXIST:
10221038
if (op == XFS_ATTRUPDATE_REMOVE) {
10231039
/* if no value, we are performing a remove operation */
1024-
xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_REMOVE);
1040+
xfs_attr_defer_add(args, XFS_ATTR_DEFER_REMOVE);
10251041
break;
10261042
}
10271043

10281044
/* Pure create fails if the attr already exists */
10291045
if (op == XFS_ATTRUPDATE_CREATE)
10301046
goto out_trans_cancel;
1031-
xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_REPLACE);
1047+
xfs_attr_defer_add(args, XFS_ATTR_DEFER_REPLACE);
10321048
break;
10331049
case -ENOATTR:
10341050
/* Can't remove what isn't there. */
@@ -1038,7 +1054,7 @@ xfs_attr_set(
10381054
/* Pure replace fails if no existing attr to replace. */
10391055
if (op == XFS_ATTRUPDATE_REPLACE)
10401056
goto out_trans_cancel;
1041-
xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_SET);
1057+
xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET);
10421058
break;
10431059
default:
10441060
goto out_trans_cancel;
@@ -1556,6 +1572,10 @@ xfs_attr_namecheck(
15561572
if (length >= MAXNAMELEN)
15571573
return false;
15581574

1575+
/* Parent pointers have their own validation. */
1576+
if (attr_flags & XFS_ATTR_PARENT)
1577+
return xfs_parent_namecheck(attr_flags, name, length);
1578+
15591579
/* There shouldn't be any nulls here */
15601580
return !memchr(name, 0, length);
15611581
}

fs/xfs/libxfs/xfs_attr.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ struct xfs_attrlist_cursor_kern {
4747

4848

4949
/* void; state communicated via *context */
50-
typedef void (*put_listent_func_t)(struct xfs_attr_list_context *, int,
51-
unsigned char *, int, int);
50+
typedef void (*put_listent_func_t)(struct xfs_attr_list_context *context,
51+
int flags, unsigned char *name, int namelen, void *value,
52+
int valuelen);
5253

5354
struct xfs_attr_list_context {
5455
struct xfs_trans *tp;
@@ -510,8 +511,8 @@ struct xfs_attr_intent {
510511
struct xfs_da_args *xattri_da_args;
511512

512513
/*
513-
* Shared buffer containing the attr name and value so that the logging
514-
* code can share large memory buffers between log items.
514+
* Shared buffer containing the attr name, new name, and value so that
515+
* the logging code can share large memory buffers between log items.
515516
*/
516517
struct xfs_attri_log_nameval *xattri_nameval;
517518

@@ -628,6 +629,20 @@ xfs_attr_init_replace_state(struct xfs_da_args *args)
628629
return xfs_attr_init_add_state(args);
629630
}
630631

632+
xfs_dahash_t xfs_attr_hashname(const uint8_t *name, int namelen);
633+
634+
xfs_dahash_t xfs_attr_hashval(struct xfs_mount *mp, unsigned int attr_flags,
635+
const uint8_t *name, int namelen, const void *value,
636+
int valuelen);
637+
638+
/* Set the hash value for any extended attribute from any namespace. */
639+
static inline void xfs_attr_sethash(struct xfs_da_args *args)
640+
{
641+
args->hashval = xfs_attr_hashval(args->dp->i_mount, args->attr_filter,
642+
args->name, args->namelen,
643+
args->value, args->valuelen);
644+
}
645+
631646
extern struct kmem_cache *xfs_attr_intent_cache;
632647
int __init xfs_attr_intent_init_cache(void);
633648
void xfs_attr_intent_destroy_cache(void);

fs/xfs/libxfs/xfs_attr_leaf.c

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -507,28 +507,57 @@ xfs_attr3_leaf_read(
507507
* INCOMPLETE flag will not be set in attr->attr_filter, but rather
508508
* XFS_DA_OP_RECOVERY will be set in args->op_flags.
509509
*/
510+
static inline unsigned int xfs_attr_match_mask(const struct xfs_da_args *args)
511+
{
512+
if (args->op_flags & XFS_DA_OP_RECOVERY)
513+
return XFS_ATTR_NSP_ONDISK_MASK;
514+
return XFS_ATTR_NSP_ONDISK_MASK | XFS_ATTR_INCOMPLETE;
515+
}
516+
517+
static inline bool
518+
xfs_attr_parent_match(
519+
const struct xfs_da_args *args,
520+
const void *value,
521+
unsigned int valuelen)
522+
{
523+
ASSERT(args->value != NULL);
524+
525+
/* Parent pointers do not use remote values */
526+
if (!value)
527+
return false;
528+
529+
/*
530+
* The only value we support is a parent rec. However, we'll accept
531+
* any valuelen so that offline repair can delete ATTR_PARENT values
532+
* that are not parent pointers.
533+
*/
534+
if (valuelen != args->valuelen)
535+
return false;
536+
537+
return memcmp(args->value, value, valuelen) == 0;
538+
}
539+
510540
static bool
511541
xfs_attr_match(
512542
struct xfs_da_args *args,
513-
uint8_t namelen,
514-
unsigned char *name,
515-
int flags)
543+
unsigned int attr_flags,
544+
const unsigned char *name,
545+
unsigned int namelen,
546+
const void *value,
547+
unsigned int valuelen)
516548
{
549+
unsigned int mask = xfs_attr_match_mask(args);
517550

518551
if (args->namelen != namelen)
519552
return false;
553+
if ((args->attr_filter & mask) != (attr_flags & mask))
554+
return false;
520555
if (memcmp(args->name, name, namelen) != 0)
521556
return false;
522557

523-
/* Recovery ignores the INCOMPLETE flag. */
524-
if ((args->op_flags & XFS_DA_OP_RECOVERY) &&
525-
args->attr_filter == (flags & XFS_ATTR_NSP_ONDISK_MASK))
526-
return true;
558+
if (attr_flags & XFS_ATTR_PARENT)
559+
return xfs_attr_parent_match(args, value, valuelen);
527560

528-
/* All remaining matches need to be filtered by INCOMPLETE state. */
529-
if (args->attr_filter !=
530-
(flags & (XFS_ATTR_NSP_ONDISK_MASK | XFS_ATTR_INCOMPLETE)))
531-
return false;
532561
return true;
533562
}
534563

@@ -538,6 +567,13 @@ xfs_attr_copy_value(
538567
unsigned char *value,
539568
int valuelen)
540569
{
570+
/*
571+
* Parent pointer lookups require the caller to specify the name and
572+
* value, so don't copy anything.
573+
*/
574+
if (args->attr_filter & XFS_ATTR_PARENT)
575+
return 0;
576+
541577
/*
542578
* No copy if all we have to do is get the length
543579
*/
@@ -746,8 +782,9 @@ xfs_attr_sf_findname(
746782
for (sfe = xfs_attr_sf_firstentry(sf);
747783
sfe < xfs_attr_sf_endptr(sf);
748784
sfe = xfs_attr_sf_nextentry(sfe)) {
749-
if (xfs_attr_match(args, sfe->namelen, sfe->nameval,
750-
sfe->flags))
785+
if (xfs_attr_match(args, sfe->flags, sfe->nameval,
786+
sfe->namelen, &sfe->nameval[sfe->namelen],
787+
sfe->valuelen))
751788
return sfe;
752789
}
753790

@@ -854,7 +891,8 @@ xfs_attr_sf_removename(
854891
*/
855892
if (totsize == sizeof(struct xfs_attr_sf_hdr) && xfs_has_attr2(mp) &&
856893
(dp->i_df.if_format != XFS_DINODE_FMT_BTREE) &&
857-
!(args->op_flags & (XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE))) {
894+
!(args->op_flags & (XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE)) &&
895+
!xfs_has_parent(mp)) {
858896
xfs_attr_fork_remove(dp, args->trans);
859897
} else {
860898
xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
@@ -863,7 +901,8 @@ xfs_attr_sf_removename(
863901
ASSERT(totsize > sizeof(struct xfs_attr_sf_hdr) ||
864902
(args->op_flags & XFS_DA_OP_ADDNAME) ||
865903
!xfs_has_attr2(mp) ||
866-
dp->i_df.if_format == XFS_DINODE_FMT_BTREE);
904+
dp->i_df.if_format == XFS_DINODE_FMT_BTREE ||
905+
xfs_has_parent(mp));
867906
xfs_trans_log_inode(args->trans, dp,
868907
XFS_ILOG_CORE | XFS_ILOG_ADATA);
869908
}
@@ -947,14 +986,13 @@ xfs_attr_shortform_to_leaf(
947986
nargs.namelen = sfe->namelen;
948987
nargs.value = &sfe->nameval[nargs.namelen];
949988
nargs.valuelen = sfe->valuelen;
950-
nargs.hashval = xfs_da_hashname(sfe->nameval,
951-
sfe->namelen);
952989
nargs.attr_filter = sfe->flags & XFS_ATTR_NSP_ONDISK_MASK;
953990
if (!xfs_attr_check_namespace(sfe->flags)) {
954991
xfs_da_mark_sick(args);
955992
error = -EFSCORRUPTED;
956993
goto out;
957994
}
995+
xfs_attr_sethash(&nargs);
958996
error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
959997
ASSERT(error == -ENOATTR);
960998
error = xfs_attr3_leaf_add(bp, &nargs);
@@ -2443,18 +2481,23 @@ xfs_attr3_leaf_lookup_int(
24432481
*/
24442482
if (entry->flags & XFS_ATTR_LOCAL) {
24452483
name_loc = xfs_attr3_leaf_name_local(leaf, probe);
2446-
if (!xfs_attr_match(args, name_loc->namelen,
2447-
name_loc->nameval, entry->flags))
2484+
if (!xfs_attr_match(args, entry->flags,
2485+
name_loc->nameval, name_loc->namelen,
2486+
&name_loc->nameval[name_loc->namelen],
2487+
be16_to_cpu(name_loc->valuelen)))
24482488
continue;
24492489
args->index = probe;
24502490
return -EEXIST;
24512491
} else {
2492+
unsigned int valuelen;
2493+
24522494
name_rmt = xfs_attr3_leaf_name_remote(leaf, probe);
2453-
if (!xfs_attr_match(args, name_rmt->namelen,
2454-
name_rmt->name, entry->flags))
2495+
valuelen = be32_to_cpu(name_rmt->valuelen);
2496+
if (!xfs_attr_match(args, entry->flags, name_rmt->name,
2497+
name_rmt->namelen, NULL, valuelen))
24552498
continue;
24562499
args->index = probe;
2457-
args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen);
2500+
args->rmtvaluelen = valuelen;
24582501
args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
24592502
args->rmtblkcnt = xfs_attr3_rmt_blocks(
24602503
args->dp->i_mount,

fs/xfs/libxfs/xfs_attr_sf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ typedef struct xfs_attr_sf_sort {
1616
uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */
1717
xfs_dahash_t hash; /* this entry's hash value */
1818
unsigned char *name; /* name value, pointer into buffer */
19+
void *value;
1920
} xfs_attr_sf_sort_t;
2021

2122
#define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \

0 commit comments

Comments
 (0)