xref: /linux/fs/9p/xattr.c (revision d39d0ed196aa1685bb24771e92f78633c66ac9cb)
1 /*
2  * Copyright IBM Corporation, 2010
3  * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2.1 of the GNU Lesser General Public License
7  * as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  */
14 
15 #include <linux/module.h>
16 #include <linux/fs.h>
17 #include <linux/sched.h>
18 #include <net/9p/9p.h>
19 #include <net/9p/client.h>
20 
21 #include "fid.h"
22 #include "xattr.h"
23 
24 /*
25  * v9fs_xattr_get()
26  *
27  * Copy an extended attribute into the buffer
28  * provided, or compute the buffer size required.
29  * Buffer is NULL to compute the size of the buffer required.
30  *
31  * Returns a negative error number on failure, or the number of bytes
32  * used / required on success.
33  */
34 ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
35 		       void *buffer, size_t buffer_size)
36 {
37 	ssize_t retval;
38 	int msize, read_count;
39 	u64 offset = 0, attr_size;
40 	struct p9_fid *fid, *attr_fid;
41 
42 	P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
43 		__func__, name, buffer_size);
44 
45 	fid = v9fs_fid_lookup(dentry);
46 	if (IS_ERR(fid))
47 		return PTR_ERR(fid);
48 
49 	attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
50 	if (IS_ERR(attr_fid)) {
51 		retval = PTR_ERR(attr_fid);
52 		P9_DPRINTK(P9_DEBUG_VFS,
53 			"p9_client_attrwalk failed %zd\n", retval);
54 		attr_fid = NULL;
55 		goto error;
56 	}
57 	if (!buffer_size) {
58 		/* request to get the attr_size */
59 		retval = attr_size;
60 		goto error;
61 	}
62 	if (attr_size > buffer_size) {
63 		retval = -ERANGE;
64 		goto error;
65 	}
66 	msize = attr_fid->clnt->msize;
67 	while (attr_size) {
68 		if (attr_size > (msize - P9_IOHDRSZ))
69 			read_count = msize - P9_IOHDRSZ;
70 		else
71 			read_count = attr_size;
72 		read_count = p9_client_read(attr_fid, ((char *)buffer)+offset,
73 					NULL, offset, read_count);
74 		if (read_count < 0) {
75 			/* error in xattr read */
76 			retval = read_count;
77 			goto error;
78 		}
79 		offset += read_count;
80 		attr_size -= read_count;
81 	}
82 	/* Total read xattr bytes */
83 	retval = offset;
84 error:
85 	if (attr_fid)
86 		p9_client_clunk(attr_fid);
87 	return retval;
88 
89 }
90 
91 /*
92  * v9fs_xattr_set()
93  *
94  * Create, replace or remove an extended attribute for this inode. Buffer
95  * is NULL to remove an existing extended attribute, and non-NULL to
96  * either replace an existing extended attribute, or create a new extended
97  * attribute. The flags XATTR_REPLACE and XATTR_CREATE
98  * specify that an extended attribute must exist and must not exist
99  * previous to the call, respectively.
100  *
101  * Returns 0, or a negative error number on failure.
102  */
103 int v9fs_xattr_set(struct dentry *dentry, const char *name,
104 		   const void *value, size_t value_len, int flags)
105 {
106 	u64 offset = 0;
107 	int retval, msize, write_count;
108 	struct p9_fid *fid = NULL;
109 
110 	P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu flags = %d\n",
111 		__func__, name, value_len, flags);
112 
113 	fid = v9fs_fid_clone(dentry);
114 	if (IS_ERR(fid)) {
115 		retval = PTR_ERR(fid);
116 		fid = NULL;
117 		goto error;
118 	}
119 	/*
120 	 * On success fid points to xattr
121 	 */
122 	retval = p9_client_xattrcreate(fid, name, value_len, flags);
123 	if (retval < 0) {
124 		P9_DPRINTK(P9_DEBUG_VFS,
125 			"p9_client_xattrcreate failed %d\n", retval);
126 		goto error;
127 	}
128 	msize = fid->clnt->msize;;
129 	while (value_len) {
130 		if (value_len > (msize - P9_IOHDRSZ))
131 			write_count = msize - P9_IOHDRSZ;
132 		else
133 			write_count = value_len;
134 		write_count = p9_client_write(fid, ((char *)value)+offset,
135 					NULL, offset, write_count);
136 		if (write_count < 0) {
137 			/* error in xattr write */
138 			retval = write_count;
139 			goto error;
140 		}
141 		offset += write_count;
142 		value_len -= write_count;
143 	}
144 	/* Total read xattr bytes */
145 	retval = offset;
146 error:
147 	if (fid)
148 		retval = p9_client_clunk(fid);
149 	return retval;
150 }
151 
152 ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
153 {
154 	return v9fs_xattr_get(dentry, NULL, buffer, buffer_size);
155 }
156 
157 const struct xattr_handler *v9fs_xattr_handlers[] = {
158 	&v9fs_xattr_user_handler,
159 	NULL
160 };
161