Prevent xattr remove from creating xattr directory

Attempting to remove an xattr from a file which does not contain
any directory based xattrs would result in the xattr directory
being created.  This behavior is non-optimal because it results
in write operations to the pool in addition to the expected error
being returned.

To prevent this the CREATE_XATTR_DIR flag is only passed in
zpl_xattr_set_dir() when setting a non-NULL xattr value.  In
addition, zpl_xattr_set() is updated similarly such that it will
return immediately if passed an xattr name which doesn't exist
and a NULL value.

Signed-off-by: Massimo Maggi <me@massimo-maggi.eu>
Signed-off-by: Richard Yao <ryao@gentoo.org>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #170
This commit is contained in:
Brian Behlendorf 2013-10-28 09:07:00 -07:00
parent 37fd6e00a6
commit fc9e0530c9

View File

@ -355,12 +355,20 @@ zpl_xattr_set_dir(struct inode *ip, const char *name, const void *value,
struct inode *xip = NULL; struct inode *xip = NULL;
vattr_t *vap = NULL; vattr_t *vap = NULL;
ssize_t wrote; ssize_t wrote;
int error; int lookup_flags, error;
const int xattr_mode = S_IFREG | 0644; const int xattr_mode = S_IFREG | 0644;
/* Lookup the xattr directory and create it if required. */ /*
error = -zfs_lookup(ip, NULL, &dxip, LOOKUP_XATTR | CREATE_XATTR_DIR, * Lookup the xattr directory. When we're adding an entry pass
cr, NULL, NULL); * CREATE_XATTR_DIR to ensure the xattr directory is created.
* When removing an entry this flag is not passed to avoid
* unnecessarily creating a new xattr directory.
*/
lookup_flags = LOOKUP_XATTR;
if (value != NULL)
lookup_flags |= CREATE_XATTR_DIR;
error = -zfs_lookup(ip, NULL, &dxip, lookup_flags, cr, NULL, NULL);
if (error) if (error)
goto out; goto out;
@ -493,7 +501,12 @@ zpl_xattr_set(struct inode *ip, const char *name, const void *value,
if (error != -ENODATA) if (error != -ENODATA)
goto out; goto out;
if ((error == -ENODATA) && (flags & XATTR_REPLACE)) if (flags & XATTR_REPLACE)
goto out;
/* The xattr to be removed already doesn't exist */
error = 0;
if (value == NULL)
goto out; goto out;
} else { } else {
error = -EEXIST; error = -EEXIST;