@@ -967,6 +967,7 @@ xfs_attr_set(
struct xfs_mount *mp = dp->i_mount;
struct xfs_trans_res tres;
bool rsvd = (args->attr_filter & XFS_ATTR_ROOT);
+ bool is_remove = args->op_flags & XFS_DA_OP_REMOVE;
int error, local;
int rmt_blks = 0;
unsigned int total;
@@ -991,7 +992,7 @@ xfs_attr_set(
args->op_flags = XFS_DA_OP_OKNOENT |
(args->op_flags & XFS_DA_OP_LOGGED);
- if (args->value) {
+ if (!is_remove) {
XFS_STATS_INC(mp, xs_attr_set);
args->total = xfs_attr_calc_size(args, &local);
@@ -1025,7 +1026,7 @@ xfs_attr_set(
if (error)
return error;
- if (args->value || xfs_inode_hasattr(dp)) {
+ if (!is_remove || xfs_inode_hasattr(dp)) {
error = xfs_iext_count_may_overflow(dp, XFS_ATTR_FORK,
XFS_IEXT_ATTR_MANIP_CNT(rmt_blks));
if (error == -EFBIG)
@@ -1039,7 +1040,7 @@ xfs_attr_set(
switch (error) {
case -EEXIST:
/* if no value, we are performing a remove operation */
- if (!args->value) {
+ if (is_remove) {
error = xfs_attr_defer_remove(args);
break;
}
@@ -1051,7 +1052,7 @@ xfs_attr_set(
break;
case -ENOATTR:
/* Can't remove what isn't there. */
- if (!args->value)
+ if (is_remove)
goto out_trans_cancel;
/* Pure replace fails if no existing attr to replace. */
@@ -103,6 +103,11 @@ xfs_attr_change(
use_logging = true;
}
+ if (args->value)
+ args->op_flags &= ~XFS_DA_OP_REMOVE;
+ else
+ args->op_flags |= XFS_DA_OP_REMOVE;
+
error = xfs_attr_set(args);
if (use_logging)