1024b7d6aSDominique Martinet // SPDX-License-Identifier: LGPL-2.1
2ebf46264SAneesh Kumar K.V /*
3ebf46264SAneesh Kumar K.V * Copyright IBM Corporation, 2010
4ebf46264SAneesh Kumar K.V * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
5ebf46264SAneesh Kumar K.V */
6ebf46264SAneesh Kumar K.V
7ebf46264SAneesh Kumar K.V #include <linux/module.h>
8ebf46264SAneesh Kumar K.V #include <linux/fs.h>
9ebf46264SAneesh Kumar K.V #include <linux/sched.h>
10070b3656SAl Viro #include <linux/uio.h>
1139a6497aSChristian Brauner #include <linux/posix_acl_xattr.h>
12ebf46264SAneesh Kumar K.V #include <net/9p/9p.h>
13ebf46264SAneesh Kumar K.V #include <net/9p/client.h>
14ebf46264SAneesh Kumar K.V
15ebf46264SAneesh Kumar K.V #include "fid.h"
16ebf46264SAneesh Kumar K.V #include "xattr.h"
17ebf46264SAneesh Kumar K.V
v9fs_fid_xattr_get(struct p9_fid * fid,const char * name,void * buffer,size_t buffer_size)1885ff872dSAneesh Kumar K.V ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
19ebf46264SAneesh Kumar K.V void *buffer, size_t buffer_size)
20ebf46264SAneesh Kumar K.V {
21ebf46264SAneesh Kumar K.V ssize_t retval;
22e1200fe6SAl Viro u64 attr_size;
2385ff872dSAneesh Kumar K.V struct p9_fid *attr_fid;
24e1200fe6SAl Viro struct kvec kvec = {.iov_base = buffer, .iov_len = buffer_size};
25e1200fe6SAl Viro struct iov_iter to;
26e1200fe6SAl Viro int err;
27e1200fe6SAl Viro
28de4eda9dSAl Viro iov_iter_kvec(&to, ITER_DEST, &kvec, 1, buffer_size);
29ebf46264SAneesh Kumar K.V
30ebf46264SAneesh Kumar K.V attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
31ebf46264SAneesh Kumar K.V if (IS_ERR(attr_fid)) {
32ebf46264SAneesh Kumar K.V retval = PTR_ERR(attr_fid);
335d385153SJoe Perches p9_debug(P9_DEBUG_VFS, "p9_client_attrwalk failed %zd\n",
345d385153SJoe Perches retval);
35e1200fe6SAl Viro return retval;
36ebf46264SAneesh Kumar K.V }
37ebf46264SAneesh Kumar K.V if (attr_size > buffer_size) {
38707823e7SIvan Orlov if (buffer_size)
39e1200fe6SAl Viro retval = -ERANGE;
40707823e7SIvan Orlov else if (attr_size > SSIZE_MAX)
41707823e7SIvan Orlov retval = -EOVERFLOW;
42707823e7SIvan Orlov else /* request to get the attr_size */
43707823e7SIvan Orlov retval = attr_size;
44e1200fe6SAl Viro } else {
45e1200fe6SAl Viro iov_iter_truncate(&to, attr_size);
46e1200fe6SAl Viro retval = p9_client_read(attr_fid, 0, &to, &err);
47e1200fe6SAl Viro if (err)
48e1200fe6SAl Viro retval = err;
49ebf46264SAneesh Kumar K.V }
50b48dbb99SDominique Martinet p9_fid_put(attr_fid);
51ebf46264SAneesh Kumar K.V return retval;
52ebf46264SAneesh Kumar K.V }
53ebf46264SAneesh Kumar K.V
5485ff872dSAneesh Kumar K.V
5585ff872dSAneesh Kumar K.V /*
5685ff872dSAneesh Kumar K.V * v9fs_xattr_get()
5785ff872dSAneesh Kumar K.V *
5885ff872dSAneesh Kumar K.V * Copy an extended attribute into the buffer
5985ff872dSAneesh Kumar K.V * provided, or compute the buffer size required.
6085ff872dSAneesh Kumar K.V * Buffer is NULL to compute the size of the buffer required.
6185ff872dSAneesh Kumar K.V *
6285ff872dSAneesh Kumar K.V * Returns a negative error number on failure, or the number of bytes
6385ff872dSAneesh Kumar K.V * used / required on success.
6485ff872dSAneesh Kumar K.V */
v9fs_xattr_get(struct dentry * dentry,const char * name,void * buffer,size_t buffer_size)6585ff872dSAneesh Kumar K.V ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
6685ff872dSAneesh Kumar K.V void *buffer, size_t buffer_size)
6785ff872dSAneesh Kumar K.V {
6885ff872dSAneesh Kumar K.V struct p9_fid *fid;
696636b6dcSJianyong Wu int ret;
7085ff872dSAneesh Kumar K.V
71*35663b6bSDominique Martinet p9_debug(P9_DEBUG_VFS, "name = '%s' value_len = %zu\n",
725d385153SJoe Perches name, buffer_size);
7385ff872dSAneesh Kumar K.V fid = v9fs_fid_lookup(dentry);
7485ff872dSAneesh Kumar K.V if (IS_ERR(fid))
7585ff872dSAneesh Kumar K.V return PTR_ERR(fid);
766636b6dcSJianyong Wu ret = v9fs_fid_xattr_get(fid, name, buffer, buffer_size);
77b48dbb99SDominique Martinet p9_fid_put(fid);
7885ff872dSAneesh Kumar K.V
796636b6dcSJianyong Wu return ret;
8085ff872dSAneesh Kumar K.V }
8185ff872dSAneesh Kumar K.V
82ebf46264SAneesh Kumar K.V /*
83ebf46264SAneesh Kumar K.V * v9fs_xattr_set()
84ebf46264SAneesh Kumar K.V *
85ebf46264SAneesh Kumar K.V * Create, replace or remove an extended attribute for this inode. Buffer
86ebf46264SAneesh Kumar K.V * is NULL to remove an existing extended attribute, and non-NULL to
87ebf46264SAneesh Kumar K.V * either replace an existing extended attribute, or create a new extended
88ebf46264SAneesh Kumar K.V * attribute. The flags XATTR_REPLACE and XATTR_CREATE
89ebf46264SAneesh Kumar K.V * specify that an extended attribute must exist and must not exist
90ebf46264SAneesh Kumar K.V * previous to the call, respectively.
91ebf46264SAneesh Kumar K.V *
92ebf46264SAneesh Kumar K.V * Returns 0, or a negative error number on failure.
93ebf46264SAneesh Kumar K.V */
v9fs_xattr_set(struct dentry * dentry,const char * name,const void * value,size_t value_len,int flags)94ebf46264SAneesh Kumar K.V int v9fs_xattr_set(struct dentry *dentry, const char *name,
95ebf46264SAneesh Kumar K.V const void *value, size_t value_len, int flags)
96ebf46264SAneesh Kumar K.V {
976636b6dcSJianyong Wu int ret;
986636b6dcSJianyong Wu struct p9_fid *fid;
996636b6dcSJianyong Wu
1006636b6dcSJianyong Wu fid = v9fs_fid_lookup(dentry);
1016636b6dcSJianyong Wu if (IS_ERR(fid))
1026636b6dcSJianyong Wu return PTR_ERR(fid);
1036636b6dcSJianyong Wu ret = v9fs_fid_xattr_set(fid, name, value, value_len, flags);
104b48dbb99SDominique Martinet p9_fid_put(fid);
1056636b6dcSJianyong Wu return ret;
10638baba9eSAl Viro }
10738baba9eSAl Viro
v9fs_fid_xattr_set(struct p9_fid * fid,const char * name,const void * value,size_t value_len,int flags)10838baba9eSAl Viro int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
10938baba9eSAl Viro const void *value, size_t value_len, int flags)
11038baba9eSAl Viro {
111070b3656SAl Viro struct kvec kvec = {.iov_base = (void *)value, .iov_len = value_len};
112070b3656SAl Viro struct iov_iter from;
1133111784bSpiaojun int retval, err;
114070b3656SAl Viro
115de4eda9dSAl Viro iov_iter_kvec(&from, ITER_SOURCE, &kvec, 1, value_len);
116ebf46264SAneesh Kumar K.V
1175d385153SJoe Perches p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu flags = %d\n",
1185d385153SJoe Perches name, value_len, flags);
119ebf46264SAneesh Kumar K.V
12038baba9eSAl Viro /* Clone it */
1217d50a29fSAl Viro fid = clone_fid(fid);
12238baba9eSAl Viro if (IS_ERR(fid))
12338baba9eSAl Viro return PTR_ERR(fid);
12438baba9eSAl Viro
125ebf46264SAneesh Kumar K.V /*
126ebf46264SAneesh Kumar K.V * On success fid points to xattr
127ebf46264SAneesh Kumar K.V */
128ebf46264SAneesh Kumar K.V retval = p9_client_xattrcreate(fid, name, value_len, flags);
129070b3656SAl Viro if (retval < 0)
1305d385153SJoe Perches p9_debug(P9_DEBUG_VFS, "p9_client_xattrcreate failed %d\n",
1315d385153SJoe Perches retval);
132ebf46264SAneesh Kumar K.V else
133070b3656SAl Viro p9_client_write(fid, 0, &from, &retval);
134b48dbb99SDominique Martinet err = p9_fid_put(fid);
1353111784bSpiaojun if (!retval && err)
1363111784bSpiaojun retval = err;
137bdd5c28dSGeyslan G. Bem return retval;
138ebf46264SAneesh Kumar K.V }
139ebf46264SAneesh Kumar K.V
v9fs_listxattr(struct dentry * dentry,char * buffer,size_t buffer_size)140ebf46264SAneesh Kumar K.V ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
141ebf46264SAneesh Kumar K.V {
142*35663b6bSDominique Martinet /* Txattrwalk with an empty string lists xattrs instead */
143*35663b6bSDominique Martinet return v9fs_xattr_get(dentry, "", buffer, buffer_size);
144ebf46264SAneesh Kumar K.V }
145ebf46264SAneesh Kumar K.V
v9fs_xattr_handler_get(const struct xattr_handler * handler,struct dentry * dentry,struct inode * inode,const char * name,void * buffer,size_t size)146e409de99SAndreas Gruenbacher static int v9fs_xattr_handler_get(const struct xattr_handler *handler,
147b296821aSAl Viro struct dentry *dentry, struct inode *inode,
148b296821aSAl Viro const char *name, void *buffer, size_t size)
149e409de99SAndreas Gruenbacher {
150e409de99SAndreas Gruenbacher const char *full_name = xattr_full_name(handler, name);
151e409de99SAndreas Gruenbacher
152e409de99SAndreas Gruenbacher return v9fs_xattr_get(dentry, full_name, buffer, size);
153e409de99SAndreas Gruenbacher }
154e409de99SAndreas Gruenbacher
v9fs_xattr_handler_set(const struct xattr_handler * handler,struct mnt_idmap * idmap,struct dentry * dentry,struct inode * inode,const char * name,const void * value,size_t size,int flags)155e409de99SAndreas Gruenbacher static int v9fs_xattr_handler_set(const struct xattr_handler *handler,
15639f60c1cSChristian Brauner struct mnt_idmap *idmap,
15759301226SAl Viro struct dentry *dentry, struct inode *inode,
15859301226SAl Viro const char *name, const void *value,
15959301226SAl Viro size_t size, int flags)
160e409de99SAndreas Gruenbacher {
161e409de99SAndreas Gruenbacher const char *full_name = xattr_full_name(handler, name);
162e409de99SAndreas Gruenbacher
163e409de99SAndreas Gruenbacher return v9fs_xattr_set(dentry, full_name, value, size, flags);
164e409de99SAndreas Gruenbacher }
165e409de99SAndreas Gruenbacher
166e409de99SAndreas Gruenbacher static struct xattr_handler v9fs_xattr_user_handler = {
167e409de99SAndreas Gruenbacher .prefix = XATTR_USER_PREFIX,
168e409de99SAndreas Gruenbacher .get = v9fs_xattr_handler_get,
169e409de99SAndreas Gruenbacher .set = v9fs_xattr_handler_set,
170e409de99SAndreas Gruenbacher };
171e409de99SAndreas Gruenbacher
172e409de99SAndreas Gruenbacher static struct xattr_handler v9fs_xattr_trusted_handler = {
173e409de99SAndreas Gruenbacher .prefix = XATTR_TRUSTED_PREFIX,
174e409de99SAndreas Gruenbacher .get = v9fs_xattr_handler_get,
175e409de99SAndreas Gruenbacher .set = v9fs_xattr_handler_set,
176e409de99SAndreas Gruenbacher };
177e409de99SAndreas Gruenbacher
178e409de99SAndreas Gruenbacher #ifdef CONFIG_9P_FS_SECURITY
179e409de99SAndreas Gruenbacher static struct xattr_handler v9fs_xattr_security_handler = {
180e409de99SAndreas Gruenbacher .prefix = XATTR_SECURITY_PREFIX,
181e409de99SAndreas Gruenbacher .get = v9fs_xattr_handler_get,
182e409de99SAndreas Gruenbacher .set = v9fs_xattr_handler_set,
183e409de99SAndreas Gruenbacher };
184e409de99SAndreas Gruenbacher #endif
185e409de99SAndreas Gruenbacher
186ebf46264SAneesh Kumar K.V const struct xattr_handler *v9fs_xattr_handlers[] = {
187ebf46264SAneesh Kumar K.V &v9fs_xattr_user_handler,
188d9a73859SJim Garlick &v9fs_xattr_trusted_handler,
189d9a73859SJim Garlick #ifdef CONFIG_9P_FS_SECURITY
190d9a73859SJim Garlick &v9fs_xattr_security_handler,
191d9a73859SJim Garlick #endif
192ebf46264SAneesh Kumar K.V NULL
193ebf46264SAneesh Kumar K.V };
194