]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - fs/orangefs/xattr.c
Orangefs: kernel client part 5
[mirror_ubuntu-focal-kernel.git] / fs / orangefs / xattr.c
CommitLineData
1182fca3
MM
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6
7/*
8 * Linux VFS extended attribute operations.
9 */
10
11#include "protocol.h"
12#include "pvfs2-kernel.h"
13#include "pvfs2-bufmap.h"
14#include <linux/posix_acl_xattr.h>
15#include <linux/xattr.h>
16
17
18#define SYSTEM_PVFS2_KEY "system.pvfs2."
19#define SYSTEM_PVFS2_KEY_LEN 13
20
21/*
22 * this function returns
23 * 0 if the key corresponding to name is not meant to be printed as part
24 * of a listxattr.
25 * 1 if the key corresponding to name is meant to be returned as part of
26 * a listxattr.
27 * The ones that start SYSTEM_PVFS2_KEY are the ones to avoid printing.
28 */
29static int is_reserved_key(const char *key, size_t size)
30{
31
32 if (size < SYSTEM_PVFS2_KEY_LEN)
33 return 1;
34
35 return strncmp(key, SYSTEM_PVFS2_KEY, SYSTEM_PVFS2_KEY_LEN) ? 1 : 0;
36}
37
38static inline int convert_to_internal_xattr_flags(int setxattr_flags)
39{
40 int internal_flag = 0;
41
42 if (setxattr_flags & XATTR_REPLACE) {
43 /* Attribute must exist! */
44 internal_flag = PVFS_XATTR_REPLACE;
45 } else if (setxattr_flags & XATTR_CREATE) {
46 /* Attribute must not exist */
47 internal_flag = PVFS_XATTR_CREATE;
48 }
49 return internal_flag;
50}
51
52
53/*
54 * Tries to get a specified key's attributes of a given
55 * file into a user-specified buffer. Note that the getxattr
56 * interface allows for the users to probe the size of an
57 * extended attribute by passing in a value of 0 to size.
58 * Thus our return value is always the size of the attribute
59 * unless the key does not exist for the file and/or if
60 * there were errors in fetching the attribute value.
61 */
62ssize_t pvfs2_inode_getxattr(struct inode *inode, const char *prefix,
63 const char *name, void *buffer, size_t size)
64{
65 struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode);
66 struct pvfs2_kernel_op_s *new_op = NULL;
67 ssize_t ret = -ENOMEM;
68 ssize_t length = 0;
69 int fsuid;
70 int fsgid;
71
72 gossip_debug(GOSSIP_XATTR_DEBUG,
73 "%s: prefix %s name %s, buffer_size %zd\n",
74 __func__, prefix, name, size);
75
76 if (name == NULL || (size > 0 && buffer == NULL)) {
77 gossip_err("pvfs2_inode_getxattr: bogus NULL pointers\n");
78 return -EINVAL;
79 }
80 if (size < 0 ||
81 (strlen(name) + strlen(prefix)) >= PVFS_MAX_XATTR_NAMELEN) {
82 gossip_err("Invalid size (%d) or key length (%d)\n",
83 (int)size,
84 (int)(strlen(name) + strlen(prefix)));
85 return -EINVAL;
86 }
87
88 fsuid = from_kuid(current_user_ns(), current_fsuid());
89 fsgid = from_kgid(current_user_ns(), current_fsgid());
90
91 gossip_debug(GOSSIP_XATTR_DEBUG,
92 "getxattr on inode %pU, name %s "
93 "(uid %o, gid %o)\n",
94 get_khandle_from_ino(inode),
95 name,
96 fsuid,
97 fsgid);
98
99 down_read(&pvfs2_inode->xattr_sem);
100
101 new_op = op_alloc(PVFS2_VFS_OP_GETXATTR);
102 if (!new_op)
103 goto out_unlock;
104
105 new_op->upcall.req.getxattr.refn = pvfs2_inode->refn;
106 ret = snprintf((char *)new_op->upcall.req.getxattr.key,
107 PVFS_MAX_XATTR_NAMELEN, "%s%s", prefix, name);
108
109 /*
110 * NOTE: Although keys are meant to be NULL terminated textual
111 * strings, I am going to explicitly pass the length just in case
112 * we change this later on...
113 */
114 new_op->upcall.req.getxattr.key_sz = ret + 1;
115
116 ret = service_operation(new_op, "pvfs2_inode_getxattr",
117 get_interruptible_flag(inode));
118 if (ret != 0) {
119 if (ret == -ENOENT) {
120 ret = -ENODATA;
121 gossip_debug(GOSSIP_XATTR_DEBUG,
122 "pvfs2_inode_getxattr: inode %pU key %s"
123 " does not exist!\n",
124 get_khandle_from_ino(inode),
125 (char *)new_op->upcall.req.getxattr.key);
126 }
127 goto out_release_op;
128 }
129
130 /*
131 * Length returned includes null terminator.
132 */
133 length = new_op->downcall.resp.getxattr.val_sz;
134
135 /*
136 * Just return the length of the queried attribute.
137 */
138 if (size == 0) {
139 ret = length;
140 goto out_release_op;
141 }
142
143 /*
144 * Check to see if key length is > provided buffer size.
145 */
146 if (length > size) {
147 ret = -ERANGE;
148 goto out_release_op;
149 }
150
151 memset(buffer, 0, size);
152 memcpy(buffer, new_op->downcall.resp.getxattr.val, length);
153 gossip_debug(GOSSIP_XATTR_DEBUG,
154 "pvfs2_inode_getxattr: inode %pU "
155 "key %s key_sz %d, val_len %d\n",
156 get_khandle_from_ino(inode),
157 (char *)new_op->
158 upcall.req.getxattr.key,
159 (int)new_op->
160 upcall.req.getxattr.key_sz,
161 (int)ret);
162
163 ret = length;
164
165out_release_op:
166 op_release(new_op);
167out_unlock:
168 up_read(&pvfs2_inode->xattr_sem);
169 return ret;
170}
171
172static int pvfs2_inode_removexattr(struct inode *inode,
173 const char *prefix,
174 const char *name,
175 int flags)
176{
177 struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode);
178 struct pvfs2_kernel_op_s *new_op = NULL;
179 int ret = -ENOMEM;
180
181 down_write(&pvfs2_inode->xattr_sem);
182 new_op = op_alloc(PVFS2_VFS_OP_REMOVEXATTR);
183 if (!new_op)
184 goto out_unlock;
185
186 new_op->upcall.req.removexattr.refn = pvfs2_inode->refn;
187 /*
188 * NOTE: Although keys are meant to be NULL terminated
189 * textual strings, I am going to explicitly pass the
190 * length just in case we change this later on...
191 */
192 ret = snprintf((char *)new_op->upcall.req.removexattr.key,
193 PVFS_MAX_XATTR_NAMELEN,
194 "%s%s",
195 (prefix ? prefix : ""),
196 name);
197 new_op->upcall.req.removexattr.key_sz = ret + 1;
198
199 gossip_debug(GOSSIP_XATTR_DEBUG,
200 "pvfs2_inode_removexattr: key %s, key_sz %d\n",
201 (char *)new_op->upcall.req.removexattr.key,
202 (int)new_op->upcall.req.removexattr.key_sz);
203
204 ret = service_operation(new_op,
205 "pvfs2_inode_removexattr",
206 get_interruptible_flag(inode));
207 if (ret == -ENOENT) {
208 /*
209 * Request to replace a non-existent attribute is an error.
210 */
211 if (flags & XATTR_REPLACE)
212 ret = -ENODATA;
213 else
214 ret = 0;
215 }
216
217 gossip_debug(GOSSIP_XATTR_DEBUG,
218 "pvfs2_inode_removexattr: returning %d\n", ret);
219
220 op_release(new_op);
221out_unlock:
222 up_write(&pvfs2_inode->xattr_sem);
223 return ret;
224}
225
226/*
227 * Tries to set an attribute for a given key on a file.
228 *
229 * Returns a -ve number on error and 0 on success. Key is text, but value
230 * can be binary!
231 */
232int pvfs2_inode_setxattr(struct inode *inode, const char *prefix,
233 const char *name, const void *value, size_t size, int flags)
234{
235 struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode);
236 struct pvfs2_kernel_op_s *new_op;
237 int internal_flag = 0;
238 int ret = -ENOMEM;
239
240 gossip_debug(GOSSIP_XATTR_DEBUG,
241 "%s: prefix %s, name %s, buffer_size %zd\n",
242 __func__, prefix, name, size);
243
244 if (size < 0 ||
245 size >= PVFS_MAX_XATTR_VALUELEN ||
246 flags < 0) {
247 gossip_err("pvfs2_inode_setxattr: bogus values of size(%d), flags(%d)\n",
248 (int)size,
249 flags);
250 return -EINVAL;
251 }
252
253 if (name == NULL ||
254 (size > 0 && value == NULL)) {
255 gossip_err("pvfs2_inode_setxattr: bogus NULL pointers!\n");
256 return -EINVAL;
257 }
258
259 internal_flag = convert_to_internal_xattr_flags(flags);
260
261 if (prefix) {
262 if (strlen(name) + strlen(prefix) >= PVFS_MAX_XATTR_NAMELEN) {
263 gossip_err
264 ("pvfs2_inode_setxattr: bogus key size (%d)\n",
265 (int)(strlen(name) + strlen(prefix)));
266 return -EINVAL;
267 }
268 } else {
269 if (strlen(name) >= PVFS_MAX_XATTR_NAMELEN) {
270 gossip_err
271 ("pvfs2_inode_setxattr: bogus key size (%d)\n",
272 (int)(strlen(name)));
273 return -EINVAL;
274 }
275 }
276
277 /* This is equivalent to a removexattr */
278 if (size == 0 && value == NULL) {
279 gossip_debug(GOSSIP_XATTR_DEBUG,
280 "removing xattr (%s%s)\n",
281 prefix,
282 name);
283 return pvfs2_inode_removexattr(inode, prefix, name, flags);
284 }
285
286 gossip_debug(GOSSIP_XATTR_DEBUG,
287 "setxattr on inode %pU, name %s\n",
288 get_khandle_from_ino(inode),
289 name);
290
291 down_write(&pvfs2_inode->xattr_sem);
292 new_op = op_alloc(PVFS2_VFS_OP_SETXATTR);
293 if (!new_op)
294 goto out_unlock;
295
296
297 new_op->upcall.req.setxattr.refn = pvfs2_inode->refn;
298 new_op->upcall.req.setxattr.flags = internal_flag;
299 /*
300 * NOTE: Although keys are meant to be NULL terminated textual
301 * strings, I am going to explicitly pass the length just in
302 * case we change this later on...
303 */
304 ret = snprintf((char *)new_op->upcall.req.setxattr.keyval.key,
305 PVFS_MAX_XATTR_NAMELEN,
306 "%s%s",
307 prefix, name);
308 new_op->upcall.req.setxattr.keyval.key_sz = ret + 1;
309 memcpy(new_op->upcall.req.setxattr.keyval.val, value, size);
310 new_op->upcall.req.setxattr.keyval.val_sz = size;
311
312 gossip_debug(GOSSIP_XATTR_DEBUG,
313 "pvfs2_inode_setxattr: key %s, key_sz %d "
314 " value size %zd\n",
315 (char *)new_op->upcall.req.setxattr.keyval.key,
316 (int)new_op->upcall.req.setxattr.keyval.key_sz,
317 size);
318
319 ret = service_operation(new_op,
320 "pvfs2_inode_setxattr",
321 get_interruptible_flag(inode));
322
323 gossip_debug(GOSSIP_XATTR_DEBUG,
324 "pvfs2_inode_setxattr: returning %d\n",
325 ret);
326
327 /* when request is serviced properly, free req op struct */
328 op_release(new_op);
329out_unlock:
330 up_write(&pvfs2_inode->xattr_sem);
331 return ret;
332}
333
334/*
335 * Tries to get a specified object's keys into a user-specified buffer of a
336 * given size. Note that like the previous instances of xattr routines, this
337 * also allows you to pass in a NULL pointer and 0 size to probe the size for
338 * subsequent memory allocations. Thus our return value is always the size of
339 * all the keys unless there were errors in fetching the keys!
340 */
341ssize_t pvfs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
342{
343 struct inode *inode = dentry->d_inode;
344 struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(inode);
345 struct pvfs2_kernel_op_s *new_op;
346 __u64 token = PVFS_ITERATE_START;
347 ssize_t ret = -ENOMEM;
348 ssize_t total = 0;
349 ssize_t length = 0;
350 int count_keys = 0;
351 int key_size;
352 int i = 0;
353
354 if (size > 0 && buffer == NULL) {
355 gossip_err("%s: bogus NULL pointers\n", __func__);
356 return -EINVAL;
357 }
358 if (size < 0) {
359 gossip_err("Invalid size (%d)\n", (int)size);
360 return -EINVAL;
361 }
362
363 down_read(&pvfs2_inode->xattr_sem);
364 new_op = op_alloc(PVFS2_VFS_OP_LISTXATTR);
365 if (!new_op)
366 goto out_unlock;
367
368 if (buffer && size > 0)
369 memset(buffer, 0, size);
370
371try_again:
372 key_size = 0;
373 new_op->upcall.req.listxattr.refn = pvfs2_inode->refn;
374 new_op->upcall.req.listxattr.token = token;
375 new_op->upcall.req.listxattr.requested_count =
376 (size == 0) ? 0 : PVFS_MAX_XATTR_LISTLEN;
377 ret = service_operation(new_op, __func__,
378 get_interruptible_flag(inode));
379 if (ret != 0)
380 goto done;
381
382 if (size == 0) {
383 /*
384 * This is a bit of a big upper limit, but I did not want to
385 * spend too much time getting this correct, since users end
386 * up allocating memory rather than us...
387 */
388 total = new_op->downcall.resp.listxattr.returned_count *
389 PVFS_MAX_XATTR_NAMELEN;
390 goto done;
391 }
392
393 length = new_op->downcall.resp.listxattr.keylen;
394 if (length == 0)
395 goto done;
396
397 /*
398 * Check to see how much can be fit in the buffer. Fit only whole keys.
399 */
400 for (i = 0; i < new_op->downcall.resp.listxattr.returned_count; i++) {
401 if (total + new_op->downcall.resp.listxattr.lengths[i] > size)
402 goto done;
403
404 /*
405 * Since many dumb programs try to setxattr() on our reserved
406 * xattrs this is a feeble attempt at defeating those by not
407 * listing them in the output of listxattr.. sigh
408 */
409 if (is_reserved_key(new_op->downcall.resp.listxattr.key +
410 key_size,
411 new_op->downcall.resp.
412 listxattr.lengths[i])) {
413 gossip_debug(GOSSIP_XATTR_DEBUG, "Copying key %d -> %s\n",
414 i, new_op->downcall.resp.listxattr.key +
415 key_size);
416 memcpy(buffer + total,
417 new_op->downcall.resp.listxattr.key + key_size,
418 new_op->downcall.resp.listxattr.lengths[i]);
419 total += new_op->downcall.resp.listxattr.lengths[i];
420 count_keys++;
421 } else {
422 gossip_debug(GOSSIP_XATTR_DEBUG, "[RESERVED] key %d -> %s\n",
423 i, new_op->downcall.resp.listxattr.key +
424 key_size);
425 }
426 key_size += new_op->downcall.resp.listxattr.lengths[i];
427 }
428
429 /*
430 * Since the buffer was large enough, we might have to continue
431 * fetching more keys!
432 */
433 token = new_op->downcall.resp.listxattr.token;
434 if (token != PVFS_ITERATE_END)
435 goto try_again;
436
437done:
438 gossip_debug(GOSSIP_XATTR_DEBUG, "%s: returning %d"
439 " [size of buffer %ld] (filled in %d keys)\n",
440 __func__,
441 ret ? (int)ret : (int)total,
442 (long)size,
443 count_keys);
444 op_release(new_op);
445 if (ret == 0)
446 ret = total;
447out_unlock:
448 up_read(&pvfs2_inode->xattr_sem);
449 return ret;
450}
451
452int pvfs2_xattr_set_default(struct dentry *dentry,
453 const char *name,
454 const void *buffer,
455 size_t size,
456 int flags,
457 int handler_flags)
458{
459 return pvfs2_inode_setxattr(dentry->d_inode,
460 PVFS2_XATTR_NAME_DEFAULT_PREFIX,
461 name,
462 buffer,
463 size,
464 flags);
465}
466
467int pvfs2_xattr_get_default(struct dentry *dentry,
468 const char *name,
469 void *buffer,
470 size_t size,
471 int handler_flags)
472{
473 return pvfs2_inode_getxattr(dentry->d_inode,
474 PVFS2_XATTR_NAME_DEFAULT_PREFIX,
475 name,
476 buffer,
477 size);
478
479}
480
481static int pvfs2_xattr_set_trusted(struct dentry *dentry,
482 const char *name,
483 const void *buffer,
484 size_t size,
485 int flags,
486 int handler_flags)
487{
488 return pvfs2_inode_setxattr(dentry->d_inode,
489 PVFS2_XATTR_NAME_TRUSTED_PREFIX,
490 name,
491 buffer,
492 size,
493 flags);
494}
495
496static int pvfs2_xattr_get_trusted(struct dentry *dentry,
497 const char *name,
498 void *buffer,
499 size_t size,
500 int handler_flags)
501{
502 return pvfs2_inode_getxattr(dentry->d_inode,
503 PVFS2_XATTR_NAME_TRUSTED_PREFIX,
504 name,
505 buffer,
506 size);
507}
508
509static struct xattr_handler pvfs2_xattr_trusted_handler = {
510 .prefix = PVFS2_XATTR_NAME_TRUSTED_PREFIX,
511 .get = pvfs2_xattr_get_trusted,
512 .set = pvfs2_xattr_set_trusted,
513};
514
515static struct xattr_handler pvfs2_xattr_default_handler = {
516 /*
517 * NOTE: this is set to be the empty string.
518 * so that all un-prefixed xattrs keys get caught
519 * here!
520 */
521 .prefix = PVFS2_XATTR_NAME_DEFAULT_PREFIX,
522 .get = pvfs2_xattr_get_default,
523 .set = pvfs2_xattr_set_default,
524};
525
526const struct xattr_handler *pvfs2_xattr_handlers[] = {
527 &posix_acl_access_xattr_handler,
528 &posix_acl_default_xattr_handler,
529 &pvfs2_xattr_trusted_handler,
530 &pvfs2_xattr_default_handler,
531 NULL
532};