char *attr_value = NULL;
char *name_list_orig = NULL;
+ /* query the actual size of the xattr list */
list_size = vfs_listxattr(old_lower_dentry, NULL, 0);
-
if (list_size <= 0) {
err = list_size;
goto out;
}
+ /* allocate space for the actual list */
name_list = unionfs_xattr_alloc(list_size + 1, XATTR_LIST_MAX);
if (!name_list || IS_ERR(name_list)) {
err = PTR_ERR(name_list);
goto out;
}
+
+ name_list_orig = name_list; /* save for kfree at end */
+
+ /* now get the actual xattr list of the source file */
list_size = vfs_listxattr(old_lower_dentry, name_list, list_size);
+ if (list_size <= 0) {
+ err = list_size;
+ goto out;
+ }
+
+ /* allocate space to hold each xattr's value */
attr_value = unionfs_xattr_alloc(XATTR_SIZE_MAX, XATTR_SIZE_MAX);
if (!attr_value || IS_ERR(attr_value)) {
err = PTR_ERR(name_list);
goto out;
}
- name_list_orig = name_list;
+
+ /* in a loop, get and set each xattr from src to dst file */
while (*name_list) {
ssize_t size;
err = size;
goto out;
}
-
if (size > XATTR_SIZE_MAX) {
err = -E2BIG;
goto out;
/* Don't lock here since vfs_setxattr does it for us. */
err = vfs_setxattr(new_lower_dentry, name_list, attr_value,
size, 0);
-
if (err < 0)
goto out;
name_list += strlen(name_list) + 1;
}
out:
- name_list = name_list_orig;
-
- if (name_list)
- unionfs_xattr_free(name_list, list_size + 1);
+ if (name_list_orig)
+ kfree(name_list_orig);
if (attr_value)
- unionfs_xattr_free(attr_value, XATTR_SIZE_MAX);
- /* It is no big deal if this fails, we just roll with the punches. */
- if (err == -ENOTSUPP || err == -EOPNOTSUPP)
+ kfree(attr_value);
+ /*
+ * Ignore if xattr isn't supported. Also ignore EPERM because that
+ * requires CAP_SYS_ADMIN for security.* xattrs, but copyup happens
+ * as normal users.
+ */
+ if (err == -ENOTSUPP || err == -EOPNOTSUPP || err == -EPERM)
err = 0;
return err;
}
#ifdef CONFIG_UNION_FS_XATTR
/* Extended attribute functions. */
extern void *unionfs_xattr_alloc(size_t size, size_t limit);
-extern void unionfs_xattr_free(void *ptr, size_t size);
extern ssize_t unionfs_getxattr(struct dentry *dentry, const char *name,
void *value, size_t size);
if (!size) /* size request, no buffer is needed */
return NULL;
- else if (size <= PAGE_SIZE)
- ptr = kmalloc(size, GFP_KERNEL);
- else
- ptr = vmalloc(size);
+
+ ptr = kmalloc(size, GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
return ptr;
}
-void unionfs_xattr_free(void *ptr, size_t size)
-{
- if (!size) /* size request, no buffer was needed */
- return;
- else if (size <= PAGE_SIZE)
- kfree(ptr);
- else
- vfree(ptr);
-}
-
/*
* BKL held by caller.
* dentry->d_inode->i_mutex locked