@@ -942,9 +942,13 @@ xfs_attr_defer_remove(
{
struct xfs_attr_intent *new;
+ int op_flag = XFS_ATTRI_OP_FLAGS_REMOVE;
int error;
- error = xfs_attr_intent_init(args, XFS_ATTRI_OP_FLAGS_REMOVE, &new);
+ if (args->op_flags & XFS_DA_OP_NVLOOKUP)
+ op_flag = XFS_ATTRI_OP_FLAGS_NVREMOVE;
+
+ error = xfs_attr_intent_init(args, op_flag, &new);
if (error)
return error;
@@ -957,6 +957,7 @@ struct xfs_icreate_log {
#define XFS_ATTRI_OP_FLAGS_SET 1 /* Set the attribute */
#define XFS_ATTRI_OP_FLAGS_REMOVE 2 /* Remove the attribute */
#define XFS_ATTRI_OP_FLAGS_REPLACE 3 /* Replace the attribute */
+#define XFS_ATTRI_OP_FLAGS_NVREMOVE 4 /* Remove attr w/ vlookup */
#define XFS_ATTRI_OP_FLAGS_TYPE_MASK 0xFF /* Flags type mask */
/*
@@ -522,6 +522,7 @@ xfs_attri_validate(
case XFS_ATTRI_OP_FLAGS_SET:
case XFS_ATTRI_OP_FLAGS_REPLACE:
case XFS_ATTRI_OP_FLAGS_REMOVE:
+ case XFS_ATTRI_OP_FLAGS_NVREMOVE:
break;
default:
return false;
@@ -611,6 +612,9 @@ xfs_attri_item_recover(
else
attr->xattri_dela_state = xfs_attr_init_add_state(args);
break;
+ case XFS_ATTRI_OP_FLAGS_NVREMOVE:
+ args->op_flags |= XFS_DA_OP_NVLOOKUP;
+ fallthrough;
case XFS_ATTRI_OP_FLAGS_REMOVE:
if (!xfs_inode_hasattr(args->dp))
goto out;
@@ -736,6 +740,16 @@ xlog_recover_attri_commit_pass2(
/* Check the number of log iovecs makes sense for the op code. */
op = xfs_attr_log_item_op(attri_formatp);
switch (op) {
+ case XFS_ATTRI_OP_FLAGS_NVREMOVE:
+ /* Log item, attr name, optional attr value */
+ if (item->ri_total != 3 && item->ri_total != 2) {
+ XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
+ attri_formatp, len);
+ return -EFSCORRUPTED;
+ }
+ name_len = attri_formatp->alfi_name_len;
+ value_len = attri_formatp->alfi_value_len;
+ break;
case XFS_ATTRI_OP_FLAGS_SET:
case XFS_ATTRI_OP_FLAGS_REPLACE:
/* Log item, attr name, attr value */
@@ -810,12 +824,16 @@ xlog_recover_attri_commit_pass2(
return -EFSCORRUPTED;
}
fallthrough;
+ case XFS_ATTRI_OP_FLAGS_NVREMOVE:
case XFS_ATTRI_OP_FLAGS_SET:
case XFS_ATTRI_OP_FLAGS_REPLACE:
/*
* Regular xattr set/remove/replace operations require a name
* and do not take a newname. Values are optional for set and
* replace.
+ *
+ * Name-value remove operations must have a name, do not
+ * take a newname, and can take a value.
*/
if (attr_name == NULL || name_len == 0) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,