From: Darrick J. Wong <djwong@xxxxxxxxxx> Source kernel commit: c27411d4c640037d70e2fa5751616e175e52ca5e Parent pointers match attrs on name+value, unlike everything else which matches on only the name. Therefore, we cannot keep using the heuristic that !value means remove. Make this an explicit operation code. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> --- db/attrset.c | 4 ++-- libxfs/xfs_attr.c | 19 ++++++++++--------- libxfs/xfs_attr.h | 3 ++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/db/attrset.c b/db/attrset.c index 736482fea..a59d5473e 100644 --- a/db/attrset.c +++ b/db/attrset.c @@ -69,7 +69,7 @@ attr_set_f( { struct xfs_da_args args = { }; char *sp; - enum xfs_attr_update op = XFS_ATTRUPDATE_UPSERTR; + enum xfs_attr_update op = XFS_ATTRUPDATE_UPSERT; int c; if (cur_typ == NULL) { @@ -247,7 +247,7 @@ attr_remove_f( goto out; } - if (libxfs_attr_set(&args, XFS_ATTRUPDATE_UPSERTR)) { + if (libxfs_attr_set(&args, XFS_ATTRUPDATE_REMOVE)) { dbprintf(_("failed to remove attr %s from inode %llu\n"), (unsigned char *)args.name, (unsigned long long)iocur_top->ino); diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c index 9a6787624..5249f9be0 100644 --- a/libxfs/xfs_attr.c +++ b/libxfs/xfs_attr.c @@ -914,10 +914,6 @@ xfs_attr_defer_add( trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp); } -/* - * Note: If args->value is NULL the attribute will be removed, just like the - * Linux ->setattr API. - */ int xfs_attr_set( struct xfs_da_args *args, @@ -953,7 +949,10 @@ xfs_attr_set( args->op_flags = XFS_DA_OP_OKNOENT | (args->op_flags & XFS_DA_OP_LOGGED); - if (args->value) { + switch (op) { + case XFS_ATTRUPDATE_UPSERT: + case XFS_ATTRUPDATE_CREATE: + case XFS_ATTRUPDATE_REPLACE: XFS_STATS_INC(mp, xs_attr_set); args->total = xfs_attr_calc_size(args, &local); @@ -973,9 +972,11 @@ xfs_attr_set( if (!local) rmt_blks = xfs_attr3_rmt_blocks(mp, args->valuelen); - } else { + break; + case XFS_ATTRUPDATE_REMOVE: XFS_STATS_INC(mp, xs_attr_remove); rmt_blks = xfs_attr3_rmt_blocks(mp, XFS_XATTR_SIZE_MAX); + break; } /* @@ -987,7 +988,7 @@ xfs_attr_set( if (error) return error; - if (args->value || xfs_inode_hasattr(dp)) { + if (op != XFS_ATTRUPDATE_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) @@ -1000,7 +1001,7 @@ xfs_attr_set( error = xfs_attr_lookup(args); switch (error) { case -EEXIST: - if (!args->value) { + if (op == XFS_ATTRUPDATE_REMOVE) { /* if no value, we are performing a remove operation */ xfs_attr_defer_add(args, XFS_ATTRI_OP_FLAGS_REMOVE); break; @@ -1013,7 +1014,7 @@ xfs_attr_set( break; case -ENOATTR: /* Can't remove what isn't there. */ - if (!args->value) + if (op == XFS_ATTRUPDATE_REMOVE) goto out_trans_cancel; /* Pure replace fails if no existing attr to replace. */ diff --git a/libxfs/xfs_attr.h b/libxfs/xfs_attr.h index 228360f7c..c8005f521 100644 --- a/libxfs/xfs_attr.h +++ b/libxfs/xfs_attr.h @@ -546,7 +546,8 @@ int xfs_attr_get_ilocked(struct xfs_da_args *args); int xfs_attr_get(struct xfs_da_args *args); enum xfs_attr_update { - XFS_ATTRUPDATE_UPSERTR, /* set/remove value, replace any existing attr */ + XFS_ATTRUPDATE_REMOVE, /* remove attr */ + XFS_ATTRUPDATE_UPSERT, /* set value, replace any existing attr */ XFS_ATTRUPDATE_CREATE, /* set value, fail if attr already exists */ XFS_ATTRUPDATE_REPLACE, /* set value, fail if attr does not exist */ };