162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright IBM Corporation, 2010 462306a36Sopenharmony_ci * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/fs.h> 962306a36Sopenharmony_ci#include <linux/sched.h> 1062306a36Sopenharmony_ci#include <linux/uio.h> 1162306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h> 1262306a36Sopenharmony_ci#include <net/9p/9p.h> 1362306a36Sopenharmony_ci#include <net/9p/client.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "fid.h" 1662306a36Sopenharmony_ci#include "xattr.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cissize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name, 1962306a36Sopenharmony_ci void *buffer, size_t buffer_size) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci ssize_t retval; 2262306a36Sopenharmony_ci u64 attr_size; 2362306a36Sopenharmony_ci struct p9_fid *attr_fid; 2462306a36Sopenharmony_ci struct kvec kvec = {.iov_base = buffer, .iov_len = buffer_size}; 2562306a36Sopenharmony_ci struct iov_iter to; 2662306a36Sopenharmony_ci int err; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci iov_iter_kvec(&to, ITER_DEST, &kvec, 1, buffer_size); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci attr_fid = p9_client_xattrwalk(fid, name, &attr_size); 3162306a36Sopenharmony_ci if (IS_ERR(attr_fid)) { 3262306a36Sopenharmony_ci retval = PTR_ERR(attr_fid); 3362306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "p9_client_attrwalk failed %zd\n", 3462306a36Sopenharmony_ci retval); 3562306a36Sopenharmony_ci return retval; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci if (attr_size > buffer_size) { 3862306a36Sopenharmony_ci if (buffer_size) 3962306a36Sopenharmony_ci retval = -ERANGE; 4062306a36Sopenharmony_ci else if (attr_size > SSIZE_MAX) 4162306a36Sopenharmony_ci retval = -EOVERFLOW; 4262306a36Sopenharmony_ci else /* request to get the attr_size */ 4362306a36Sopenharmony_ci retval = attr_size; 4462306a36Sopenharmony_ci } else { 4562306a36Sopenharmony_ci iov_iter_truncate(&to, attr_size); 4662306a36Sopenharmony_ci retval = p9_client_read(attr_fid, 0, &to, &err); 4762306a36Sopenharmony_ci if (err) 4862306a36Sopenharmony_ci retval = err; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci p9_fid_put(attr_fid); 5162306a36Sopenharmony_ci return retval; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* 5662306a36Sopenharmony_ci * v9fs_xattr_get() 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Copy an extended attribute into the buffer 5962306a36Sopenharmony_ci * provided, or compute the buffer size required. 6062306a36Sopenharmony_ci * Buffer is NULL to compute the size of the buffer required. 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * Returns a negative error number on failure, or the number of bytes 6362306a36Sopenharmony_ci * used / required on success. 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_cissize_t v9fs_xattr_get(struct dentry *dentry, const char *name, 6662306a36Sopenharmony_ci void *buffer, size_t buffer_size) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct p9_fid *fid; 6962306a36Sopenharmony_ci int ret; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "name = '%s' value_len = %zu\n", 7262306a36Sopenharmony_ci name, buffer_size); 7362306a36Sopenharmony_ci fid = v9fs_fid_lookup(dentry); 7462306a36Sopenharmony_ci if (IS_ERR(fid)) 7562306a36Sopenharmony_ci return PTR_ERR(fid); 7662306a36Sopenharmony_ci ret = v9fs_fid_xattr_get(fid, name, buffer, buffer_size); 7762306a36Sopenharmony_ci p9_fid_put(fid); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return ret; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* 8362306a36Sopenharmony_ci * v9fs_xattr_set() 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * Create, replace or remove an extended attribute for this inode. Buffer 8662306a36Sopenharmony_ci * is NULL to remove an existing extended attribute, and non-NULL to 8762306a36Sopenharmony_ci * either replace an existing extended attribute, or create a new extended 8862306a36Sopenharmony_ci * attribute. The flags XATTR_REPLACE and XATTR_CREATE 8962306a36Sopenharmony_ci * specify that an extended attribute must exist and must not exist 9062306a36Sopenharmony_ci * previous to the call, respectively. 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * Returns 0, or a negative error number on failure. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ciint v9fs_xattr_set(struct dentry *dentry, const char *name, 9562306a36Sopenharmony_ci const void *value, size_t value_len, int flags) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci int ret; 9862306a36Sopenharmony_ci struct p9_fid *fid; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci fid = v9fs_fid_lookup(dentry); 10162306a36Sopenharmony_ci if (IS_ERR(fid)) 10262306a36Sopenharmony_ci return PTR_ERR(fid); 10362306a36Sopenharmony_ci ret = v9fs_fid_xattr_set(fid, name, value, value_len, flags); 10462306a36Sopenharmony_ci p9_fid_put(fid); 10562306a36Sopenharmony_ci return ret; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciint v9fs_fid_xattr_set(struct p9_fid *fid, const char *name, 10962306a36Sopenharmony_ci const void *value, size_t value_len, int flags) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct kvec kvec = {.iov_base = (void *)value, .iov_len = value_len}; 11262306a36Sopenharmony_ci struct iov_iter from; 11362306a36Sopenharmony_ci int retval, err; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci iov_iter_kvec(&from, ITER_SOURCE, &kvec, 1, value_len); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n", 11862306a36Sopenharmony_ci name, value_len, flags); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* Clone it */ 12162306a36Sopenharmony_ci fid = clone_fid(fid); 12262306a36Sopenharmony_ci if (IS_ERR(fid)) 12362306a36Sopenharmony_ci return PTR_ERR(fid); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* 12662306a36Sopenharmony_ci * On success fid points to xattr 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci retval = p9_client_xattrcreate(fid, name, value_len, flags); 12962306a36Sopenharmony_ci if (retval < 0) 13062306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "p9_client_xattrcreate failed %d\n", 13162306a36Sopenharmony_ci retval); 13262306a36Sopenharmony_ci else 13362306a36Sopenharmony_ci p9_client_write(fid, 0, &from, &retval); 13462306a36Sopenharmony_ci err = p9_fid_put(fid); 13562306a36Sopenharmony_ci if (!retval && err) 13662306a36Sopenharmony_ci retval = err; 13762306a36Sopenharmony_ci return retval; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cissize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci /* Txattrwalk with an empty string lists xattrs instead */ 14362306a36Sopenharmony_ci return v9fs_xattr_get(dentry, "", buffer, buffer_size); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int v9fs_xattr_handler_get(const struct xattr_handler *handler, 14762306a36Sopenharmony_ci struct dentry *dentry, struct inode *inode, 14862306a36Sopenharmony_ci const char *name, void *buffer, size_t size) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci const char *full_name = xattr_full_name(handler, name); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return v9fs_xattr_get(dentry, full_name, buffer, size); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int v9fs_xattr_handler_set(const struct xattr_handler *handler, 15662306a36Sopenharmony_ci struct mnt_idmap *idmap, 15762306a36Sopenharmony_ci struct dentry *dentry, struct inode *inode, 15862306a36Sopenharmony_ci const char *name, const void *value, 15962306a36Sopenharmony_ci size_t size, int flags) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci const char *full_name = xattr_full_name(handler, name); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return v9fs_xattr_set(dentry, full_name, value, size, flags); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic struct xattr_handler v9fs_xattr_user_handler = { 16762306a36Sopenharmony_ci .prefix = XATTR_USER_PREFIX, 16862306a36Sopenharmony_ci .get = v9fs_xattr_handler_get, 16962306a36Sopenharmony_ci .set = v9fs_xattr_handler_set, 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic struct xattr_handler v9fs_xattr_trusted_handler = { 17362306a36Sopenharmony_ci .prefix = XATTR_TRUSTED_PREFIX, 17462306a36Sopenharmony_ci .get = v9fs_xattr_handler_get, 17562306a36Sopenharmony_ci .set = v9fs_xattr_handler_set, 17662306a36Sopenharmony_ci}; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci#ifdef CONFIG_9P_FS_SECURITY 17962306a36Sopenharmony_cistatic struct xattr_handler v9fs_xattr_security_handler = { 18062306a36Sopenharmony_ci .prefix = XATTR_SECURITY_PREFIX, 18162306a36Sopenharmony_ci .get = v9fs_xattr_handler_get, 18262306a36Sopenharmony_ci .set = v9fs_xattr_handler_set, 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci#endif 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ciconst struct xattr_handler *v9fs_xattr_handlers[] = { 18762306a36Sopenharmony_ci &v9fs_xattr_user_handler, 18862306a36Sopenharmony_ci &v9fs_xattr_trusted_handler, 18962306a36Sopenharmony_ci#ifdef CONFIG_9P_FS_SECURITY 19062306a36Sopenharmony_ci &v9fs_xattr_security_handler, 19162306a36Sopenharmony_ci#endif 19262306a36Sopenharmony_ci NULL 19362306a36Sopenharmony_ci}; 194