@@ -508,10 +508,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)
@@ -519,6 +521,23 @@ xfs_attr_match(
if (memcmp(args->name, name, namelen) != 0)
return false;
+ if (args->op_flags & XFS_DA_OP_NVLOOKUP) {
+ 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))
@@ -537,6 +556,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_NVLOOKUP)
+ return 0;
+
/*
* No copy if all we have to do is get the length
*/
@@ -761,6 +784,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;
@@ -929,6 +953,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;
}
@@ -956,6 +981,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);
@@ -1008,7 +1034,7 @@ xfs_attr_shortform_to_leaf(
nargs.total = args->total;
nargs.whichfork = XFS_ATTR_FORK;
nargs.trans = args->trans;
- nargs.op_flags = XFS_DA_OP_OKNOENT;
+ nargs.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_NVLOOKUP;
nargs.owner = args->owner;
sfe = &sf->list[0];
@@ -1212,7 +1238,7 @@ xfs_attr3_leaf_to_shortform(
nargs.total = args->total;
nargs.whichfork = XFS_ATTR_FORK;
nargs.trans = args->trans;
- nargs.op_flags = XFS_DA_OP_OKNOENT;
+ nargs.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_NVLOOKUP;
nargs.owner = args->owner;
for (i = 0; i < ichdr.count; entry++, i++) {
@@ -2509,14 +2535,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);
@@ -94,6 +94,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_NVLOOKUP (1u << 9) /* Match local attr on name+value */
#define XFS_DA_OP_FLAGS \
{ XFS_DA_OP_JUSTCHECK, "JUSTCHECK" }, \
@@ -104,7 +105,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_NVLOOKUP, "NVLOOKUP" }
/*
* Storage for holding state during Btree searches and split/join ops.