From: Darrick J. Wong <djwong@xxxxxxxxxx> Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- fs/xfs/libxfs/xfs_attr_leaf.c | 41 +++++++++++++++++++++++++++++++++++------ fs/xfs/libxfs/xfs_da_btree.h | 4 +++- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index e6c4c8b52a55..d05f2c5cc0cc 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -473,10 +473,12 @@ xfs_attr3_leaf_read( */ static bool xfs_attr_match( - struct xfs_da_args *args, - uint8_t namelen, - unsigned char *name, - int flags) + const struct xfs_da_args *args, + uint8_t namelen, + const unsigned char *name, + unsigned int valuelen, + const void *value, + int flags) { if (args->namelen != namelen) @@ -484,6 +486,23 @@ xfs_attr_match( if (memcmp(args->name, name, namelen) != 0) return false; + if (args->op_flags & XFS_DA_OP_VLOOKUP) { + if (args->valuelen != valuelen) + return false; + if (args->valuelen && !value) { + /* not implemented for remote values */ + ASSERT(0); + return false; + } + if (valuelen && !args->value) { + /* caller gave us valuelen > 0 but no value?? */ + ASSERT(0); + return false; + } + if (valuelen > 0 && memcmp(args->value, value, valuelen) != 0) + return false; + } + /* Recovery ignores the INCOMPLETE flag. */ if ((args->op_flags & XFS_DA_OP_RECOVERY) && args->attr_filter == (flags & XFS_ATTR_NSP_ONDISK_MASK)) @@ -502,6 +521,10 @@ xfs_attr_copy_value( unsigned char *value, int valuelen) { + /* vlookups already supplied the attr value; don't copy anything */ + if (args->op_flags & XFS_DA_OP_VLOOKUP) + return 0; + /* * No copy if all we have to do is get the length */ @@ -726,6 +749,7 @@ xfs_attr_sf_findname( base += size, i++) { size = xfs_attr_sf_entsize(sfe); if (!xfs_attr_match(args, sfe->namelen, sfe->nameval, + sfe->valuelen, &sfe->nameval[sfe->namelen], sfe->flags)) continue; break; @@ -896,6 +920,7 @@ xfs_attr_shortform_lookup(xfs_da_args_t *args) for (i = 0; i < sf->hdr.count; sfe = xfs_attr_sf_nextentry(sfe), i++) { if (xfs_attr_match(args, sfe->namelen, sfe->nameval, + sfe->valuelen, &sfe->nameval[sfe->namelen], sfe->flags)) return -EEXIST; } @@ -923,6 +948,7 @@ xfs_attr_shortform_getvalue( for (i = 0; i < sf->hdr.count; sfe = xfs_attr_sf_nextentry(sfe), i++) { if (xfs_attr_match(args, sfe->namelen, sfe->nameval, + sfe->valuelen, &sfe->nameval[sfe->namelen], sfe->flags)) return xfs_attr_copy_value(args, &sfe->nameval[args->namelen], sfe->valuelen); @@ -2484,14 +2510,17 @@ xfs_attr3_leaf_lookup_int( if (entry->flags & XFS_ATTR_LOCAL) { name_loc = xfs_attr3_leaf_name_local(leaf, probe); if (!xfs_attr_match(args, name_loc->namelen, - name_loc->nameval, entry->flags)) + name_loc->nameval, + be16_to_cpu(name_loc->valuelen), + &name_loc->nameval[name_loc->namelen], + entry->flags)) continue; args->index = probe; return -EEXIST; } else { name_rmt = xfs_attr3_leaf_name_remote(leaf, probe); if (!xfs_attr_match(args, name_rmt->namelen, - name_rmt->name, entry->flags)) + name_rmt->name, 0, NULL, entry->flags)) continue; args->index = probe; args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen); diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h index 90b86d00258f..0ef32f629e1b 100644 --- a/fs/xfs/libxfs/xfs_da_btree.h +++ b/fs/xfs/libxfs/xfs_da_btree.h @@ -96,6 +96,7 @@ typedef struct xfs_da_args { #define XFS_DA_OP_REMOVE (1u << 6) /* this is a remove operation */ #define XFS_DA_OP_RECOVERY (1u << 7) /* Log recovery operation */ #define XFS_DA_OP_LOGGED (1u << 8) /* Use intent items to track op */ +#define XFS_DA_OP_VLOOKUP (1u << 9) /* Compare attr value during lookup */ #define XFS_DA_OP_FLAGS \ { XFS_DA_OP_JUSTCHECK, "JUSTCHECK" }, \ @@ -106,7 +107,8 @@ typedef struct xfs_da_args { { XFS_DA_OP_NOTIME, "NOTIME" }, \ { XFS_DA_OP_REMOVE, "REMOVE" }, \ { XFS_DA_OP_RECOVERY, "RECOVERY" }, \ - { XFS_DA_OP_LOGGED, "LOGGED" } + { XFS_DA_OP_LOGGED, "LOGGED" }, \ + { XFS_DA_OP_VLOOKUP, "VLOOKUP" } /* * Storage for holding state during Btree searches and split/join ops.