@@ -977,6 +977,7 @@ xfs_attr_set(
struct xfs_inode *dp = args->dp;
struct xfs_mount *mp = dp->i_mount;
struct xfs_trans_res tres;
+ bool is_remove = args->op_flags & XFS_DA_OP_REMOVE;
bool rsvd;
int error, local;
int rmt_blks = 0;
@@ -1004,7 +1005,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);
@@ -1038,7 +1039,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)
@@ -1052,7 +1053,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;
}
@@ -1064,7 +1065,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. */
@@ -460,6 +460,7 @@ xfs_parent_unset(
scr->args.geo = ip->i_mount->m_attr_geo;
scr->args.name = (const unsigned char *)&scr->rec;
scr->args.namelen = reclen;
+ scr->args.op_flags = XFS_DA_OP_REMOVE;
scr->args.whichfork = XFS_ATTR_FORK;
return xfs_attr_set(&scr->args);
@@ -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)