]> git.ipfire.org Git - people/ms/linux.git/blame - fs/ceph/xattr.c
ceph: pass inode rather than table to ceph_match_vxattr()
[people/ms/linux.git] / fs / ceph / xattr.c
CommitLineData
3d14c5d2
YS
1#include <linux/ceph/ceph_debug.h>
2
355da1eb 3#include "super.h"
3d14c5d2
YS
4#include "mds_client.h"
5
6#include <linux/ceph/decode.h>
355da1eb
SW
7
8#include <linux/xattr.h>
5a0e3ad6 9#include <linux/slab.h>
355da1eb
SW
10
11static bool ceph_is_valid_xattr(const char *name)
12{
1a756278
SW
13 return !strncmp(name, "ceph.", 5) ||
14 !strncmp(name, XATTR_SECURITY_PREFIX,
355da1eb
SW
15 XATTR_SECURITY_PREFIX_LEN) ||
16 !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
17 !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
18}
19
20/*
21 * These define virtual xattrs exposing the recursive directory
22 * statistics and layout metadata.
23 */
24struct ceph_vxattr_cb {
25 bool readonly;
26 char *name;
27 size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
28 size_t size);
29};
30
31/* directories */
32
33static size_t ceph_vxattrcb_entries(struct ceph_inode_info *ci, char *val,
34 size_t size)
35{
36 return snprintf(val, size, "%lld", ci->i_files + ci->i_subdirs);
37}
38
39static size_t ceph_vxattrcb_files(struct ceph_inode_info *ci, char *val,
40 size_t size)
41{
42 return snprintf(val, size, "%lld", ci->i_files);
43}
44
45static size_t ceph_vxattrcb_subdirs(struct ceph_inode_info *ci, char *val,
46 size_t size)
47{
48 return snprintf(val, size, "%lld", ci->i_subdirs);
49}
50
51static size_t ceph_vxattrcb_rentries(struct ceph_inode_info *ci, char *val,
52 size_t size)
53{
54 return snprintf(val, size, "%lld", ci->i_rfiles + ci->i_rsubdirs);
55}
56
57static size_t ceph_vxattrcb_rfiles(struct ceph_inode_info *ci, char *val,
58 size_t size)
59{
60 return snprintf(val, size, "%lld", ci->i_rfiles);
61}
62
63static size_t ceph_vxattrcb_rsubdirs(struct ceph_inode_info *ci, char *val,
64 size_t size)
65{
66 return snprintf(val, size, "%lld", ci->i_rsubdirs);
67}
68
69static size_t ceph_vxattrcb_rbytes(struct ceph_inode_info *ci, char *val,
70 size_t size)
71{
72 return snprintf(val, size, "%lld", ci->i_rbytes);
73}
74
75static size_t ceph_vxattrcb_rctime(struct ceph_inode_info *ci, char *val,
76 size_t size)
77{
78 return snprintf(val, size, "%ld.%ld", (long)ci->i_rctime.tv_sec,
79 (long)ci->i_rctime.tv_nsec);
80}
81
82static struct ceph_vxattr_cb ceph_dir_vxattrs[] = {
1a756278
SW
83 { true, "ceph.dir.entries", ceph_vxattrcb_entries},
84 { true, "ceph.dir.files", ceph_vxattrcb_files},
85 { true, "ceph.dir.subdirs", ceph_vxattrcb_subdirs},
86 { true, "ceph.dir.rentries", ceph_vxattrcb_rentries},
87 { true, "ceph.dir.rfiles", ceph_vxattrcb_rfiles},
88 { true, "ceph.dir.rsubdirs", ceph_vxattrcb_rsubdirs},
89 { true, "ceph.dir.rbytes", ceph_vxattrcb_rbytes},
90 { true, "ceph.dir.rctime", ceph_vxattrcb_rctime},
355da1eb
SW
91 { true, NULL, NULL }
92};
93
94/* files */
95
96static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
97 size_t size)
98{
b195befd
SW
99 int ret;
100
101 ret = snprintf(val, size,
355da1eb
SW
102 "chunk_bytes=%lld\nstripe_count=%lld\nobject_size=%lld\n",
103 (unsigned long long)ceph_file_layout_su(ci->i_layout),
104 (unsigned long long)ceph_file_layout_stripe_count(ci->i_layout),
105 (unsigned long long)ceph_file_layout_object_size(ci->i_layout));
b195befd
SW
106 if (ceph_file_layout_pg_preferred(ci->i_layout))
107 ret += snprintf(val + ret, size, "preferred_osd=%lld\n",
108 (unsigned long long)ceph_file_layout_pg_preferred(
109 ci->i_layout));
110 return ret;
355da1eb
SW
111}
112
113static struct ceph_vxattr_cb ceph_file_vxattrs[] = {
114fc474
AE
114 { true, "ceph.file.layout", ceph_vxattrcb_layout},
115 /* The following extended attribute name is deprecated */
1a756278 116 { true, "ceph.layout", ceph_vxattrcb_layout},
114fc474 117 { true, NULL, NULL }
355da1eb
SW
118};
119
120static struct ceph_vxattr_cb *ceph_inode_vxattrs(struct inode *inode)
121{
122 if (S_ISDIR(inode->i_mode))
123 return ceph_dir_vxattrs;
124 else if (S_ISREG(inode->i_mode))
125 return ceph_file_vxattrs;
126 return NULL;
127}
128
06476a69 129static struct ceph_vxattr_cb *ceph_match_vxattr(struct inode *inode,
355da1eb
SW
130 const char *name)
131{
06476a69
AE
132 struct ceph_vxattr_cb *vxattr = ceph_inode_vxattrs(inode);
133
134 if (vxattr) {
135 while (vxattr->name) {
136 if (!strcmp(vxattr->name, name))
137 return vxattr;
138 vxattr++;
139 }
140 }
141
355da1eb
SW
142 return NULL;
143}
144
145static int __set_xattr(struct ceph_inode_info *ci,
146 const char *name, int name_len,
147 const char *val, int val_len,
148 int dirty,
149 int should_free_name, int should_free_val,
150 struct ceph_inode_xattr **newxattr)
151{
152 struct rb_node **p;
153 struct rb_node *parent = NULL;
154 struct ceph_inode_xattr *xattr = NULL;
155 int c;
156 int new = 0;
157
158 p = &ci->i_xattrs.index.rb_node;
159 while (*p) {
160 parent = *p;
161 xattr = rb_entry(parent, struct ceph_inode_xattr, node);
162 c = strncmp(name, xattr->name, min(name_len, xattr->name_len));
163 if (c < 0)
164 p = &(*p)->rb_left;
165 else if (c > 0)
166 p = &(*p)->rb_right;
167 else {
168 if (name_len == xattr->name_len)
169 break;
170 else if (name_len < xattr->name_len)
171 p = &(*p)->rb_left;
172 else
173 p = &(*p)->rb_right;
174 }
175 xattr = NULL;
176 }
177
178 if (!xattr) {
179 new = 1;
180 xattr = *newxattr;
181 xattr->name = name;
182 xattr->name_len = name_len;
183 xattr->should_free_name = should_free_name;
184
185 ci->i_xattrs.count++;
186 dout("__set_xattr count=%d\n", ci->i_xattrs.count);
187 } else {
188 kfree(*newxattr);
189 *newxattr = NULL;
190 if (xattr->should_free_val)
191 kfree((void *)xattr->val);
192
193 if (should_free_name) {
194 kfree((void *)name);
195 name = xattr->name;
196 }
197 ci->i_xattrs.names_size -= xattr->name_len;
198 ci->i_xattrs.vals_size -= xattr->val_len;
199 }
355da1eb
SW
200 ci->i_xattrs.names_size += name_len;
201 ci->i_xattrs.vals_size += val_len;
202 if (val)
203 xattr->val = val;
204 else
205 xattr->val = "";
206
207 xattr->val_len = val_len;
208 xattr->dirty = dirty;
209 xattr->should_free_val = (val && should_free_val);
210
211 if (new) {
212 rb_link_node(&xattr->node, parent, p);
213 rb_insert_color(&xattr->node, &ci->i_xattrs.index);
214 dout("__set_xattr_val p=%p\n", p);
215 }
216
217 dout("__set_xattr_val added %llx.%llx xattr %p %s=%.*s\n",
218 ceph_vinop(&ci->vfs_inode), xattr, name, val_len, val);
219
220 return 0;
221}
222
223static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci,
224 const char *name)
225{
226 struct rb_node **p;
227 struct rb_node *parent = NULL;
228 struct ceph_inode_xattr *xattr = NULL;
17db143f 229 int name_len = strlen(name);
355da1eb
SW
230 int c;
231
232 p = &ci->i_xattrs.index.rb_node;
233 while (*p) {
234 parent = *p;
235 xattr = rb_entry(parent, struct ceph_inode_xattr, node);
236 c = strncmp(name, xattr->name, xattr->name_len);
17db143f
SW
237 if (c == 0 && name_len > xattr->name_len)
238 c = 1;
355da1eb
SW
239 if (c < 0)
240 p = &(*p)->rb_left;
241 else if (c > 0)
242 p = &(*p)->rb_right;
243 else {
244 dout("__get_xattr %s: found %.*s\n", name,
245 xattr->val_len, xattr->val);
246 return xattr;
247 }
248 }
249
250 dout("__get_xattr %s: not found\n", name);
251
252 return NULL;
253}
254
255static void __free_xattr(struct ceph_inode_xattr *xattr)
256{
257 BUG_ON(!xattr);
258
259 if (xattr->should_free_name)
260 kfree((void *)xattr->name);
261 if (xattr->should_free_val)
262 kfree((void *)xattr->val);
263
264 kfree(xattr);
265}
266
267static int __remove_xattr(struct ceph_inode_info *ci,
268 struct ceph_inode_xattr *xattr)
269{
270 if (!xattr)
271 return -EOPNOTSUPP;
272
273 rb_erase(&xattr->node, &ci->i_xattrs.index);
274
275 if (xattr->should_free_name)
276 kfree((void *)xattr->name);
277 if (xattr->should_free_val)
278 kfree((void *)xattr->val);
279
280 ci->i_xattrs.names_size -= xattr->name_len;
281 ci->i_xattrs.vals_size -= xattr->val_len;
282 ci->i_xattrs.count--;
283 kfree(xattr);
284
285 return 0;
286}
287
288static int __remove_xattr_by_name(struct ceph_inode_info *ci,
289 const char *name)
290{
291 struct rb_node **p;
292 struct ceph_inode_xattr *xattr;
293 int err;
294
295 p = &ci->i_xattrs.index.rb_node;
296 xattr = __get_xattr(ci, name);
297 err = __remove_xattr(ci, xattr);
298 return err;
299}
300
301static char *__copy_xattr_names(struct ceph_inode_info *ci,
302 char *dest)
303{
304 struct rb_node *p;
305 struct ceph_inode_xattr *xattr = NULL;
306
307 p = rb_first(&ci->i_xattrs.index);
308 dout("__copy_xattr_names count=%d\n", ci->i_xattrs.count);
309
310 while (p) {
311 xattr = rb_entry(p, struct ceph_inode_xattr, node);
312 memcpy(dest, xattr->name, xattr->name_len);
313 dest[xattr->name_len] = '\0';
314
315 dout("dest=%s %p (%s) (%d/%d)\n", dest, xattr, xattr->name,
316 xattr->name_len, ci->i_xattrs.names_size);
317
318 dest += xattr->name_len + 1;
319 p = rb_next(p);
320 }
321
322 return dest;
323}
324
325void __ceph_destroy_xattrs(struct ceph_inode_info *ci)
326{
327 struct rb_node *p, *tmp;
328 struct ceph_inode_xattr *xattr = NULL;
329
330 p = rb_first(&ci->i_xattrs.index);
331
332 dout("__ceph_destroy_xattrs p=%p\n", p);
333
334 while (p) {
335 xattr = rb_entry(p, struct ceph_inode_xattr, node);
336 tmp = p;
337 p = rb_next(tmp);
338 dout("__ceph_destroy_xattrs next p=%p (%.*s)\n", p,
339 xattr->name_len, xattr->name);
340 rb_erase(tmp, &ci->i_xattrs.index);
341
342 __free_xattr(xattr);
343 }
344
345 ci->i_xattrs.names_size = 0;
346 ci->i_xattrs.vals_size = 0;
347 ci->i_xattrs.index_version = 0;
348 ci->i_xattrs.count = 0;
349 ci->i_xattrs.index = RB_ROOT;
350}
351
352static int __build_xattrs(struct inode *inode)
be655596
SW
353 __releases(ci->i_ceph_lock)
354 __acquires(ci->i_ceph_lock)
355da1eb
SW
355{
356 u32 namelen;
357 u32 numattr = 0;
358 void *p, *end;
359 u32 len;
360 const char *name, *val;
361 struct ceph_inode_info *ci = ceph_inode(inode);
362 int xattr_version;
363 struct ceph_inode_xattr **xattrs = NULL;
63ff78b2 364 int err = 0;
355da1eb
SW
365 int i;
366
367 dout("__build_xattrs() len=%d\n",
368 ci->i_xattrs.blob ? (int)ci->i_xattrs.blob->vec.iov_len : 0);
369
370 if (ci->i_xattrs.index_version >= ci->i_xattrs.version)
371 return 0; /* already built */
372
373 __ceph_destroy_xattrs(ci);
374
375start:
376 /* updated internal xattr rb tree */
377 if (ci->i_xattrs.blob && ci->i_xattrs.blob->vec.iov_len > 4) {
378 p = ci->i_xattrs.blob->vec.iov_base;
379 end = p + ci->i_xattrs.blob->vec.iov_len;
380 ceph_decode_32_safe(&p, end, numattr, bad);
381 xattr_version = ci->i_xattrs.version;
be655596 382 spin_unlock(&ci->i_ceph_lock);
355da1eb
SW
383
384 xattrs = kcalloc(numattr, sizeof(struct ceph_xattr *),
385 GFP_NOFS);
386 err = -ENOMEM;
387 if (!xattrs)
388 goto bad_lock;
389 memset(xattrs, 0, numattr*sizeof(struct ceph_xattr *));
390 for (i = 0; i < numattr; i++) {
391 xattrs[i] = kmalloc(sizeof(struct ceph_inode_xattr),
392 GFP_NOFS);
393 if (!xattrs[i])
394 goto bad_lock;
395 }
396
be655596 397 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
398 if (ci->i_xattrs.version != xattr_version) {
399 /* lost a race, retry */
400 for (i = 0; i < numattr; i++)
401 kfree(xattrs[i]);
402 kfree(xattrs);
403 goto start;
404 }
405 err = -EIO;
406 while (numattr--) {
407 ceph_decode_32_safe(&p, end, len, bad);
408 namelen = len;
409 name = p;
410 p += len;
411 ceph_decode_32_safe(&p, end, len, bad);
412 val = p;
413 p += len;
414
415 err = __set_xattr(ci, name, namelen, val, len,
416 0, 0, 0, &xattrs[numattr]);
417
418 if (err < 0)
419 goto bad;
420 }
421 kfree(xattrs);
422 }
423 ci->i_xattrs.index_version = ci->i_xattrs.version;
424 ci->i_xattrs.dirty = false;
425
426 return err;
427bad_lock:
be655596 428 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
429bad:
430 if (xattrs) {
431 for (i = 0; i < numattr; i++)
432 kfree(xattrs[i]);
433 kfree(xattrs);
434 }
435 ci->i_xattrs.names_size = 0;
436 return err;
437}
438
439static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size,
440 int val_size)
441{
442 /*
443 * 4 bytes for the length, and additional 4 bytes per each xattr name,
444 * 4 bytes per each value
445 */
446 int size = 4 + ci->i_xattrs.count*(4 + 4) +
447 ci->i_xattrs.names_size +
448 ci->i_xattrs.vals_size;
449 dout("__get_required_blob_size c=%d names.size=%d vals.size=%d\n",
450 ci->i_xattrs.count, ci->i_xattrs.names_size,
451 ci->i_xattrs.vals_size);
452
453 if (name_size)
454 size += 4 + 4 + name_size + val_size;
455
456 return size;
457}
458
459/*
460 * If there are dirty xattrs, reencode xattrs into the prealloc_blob
461 * and swap into place.
462 */
463void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
464{
465 struct rb_node *p;
466 struct ceph_inode_xattr *xattr = NULL;
467 void *dest;
468
469 dout("__build_xattrs_blob %p\n", &ci->vfs_inode);
470 if (ci->i_xattrs.dirty) {
471 int need = __get_required_blob_size(ci, 0, 0);
472
473 BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len);
474
475 p = rb_first(&ci->i_xattrs.index);
476 dest = ci->i_xattrs.prealloc_blob->vec.iov_base;
477
478 ceph_encode_32(&dest, ci->i_xattrs.count);
479 while (p) {
480 xattr = rb_entry(p, struct ceph_inode_xattr, node);
481
482 ceph_encode_32(&dest, xattr->name_len);
483 memcpy(dest, xattr->name, xattr->name_len);
484 dest += xattr->name_len;
485 ceph_encode_32(&dest, xattr->val_len);
486 memcpy(dest, xattr->val, xattr->val_len);
487 dest += xattr->val_len;
488
489 p = rb_next(p);
490 }
491
492 /* adjust buffer len; it may be larger than we need */
493 ci->i_xattrs.prealloc_blob->vec.iov_len =
494 dest - ci->i_xattrs.prealloc_blob->vec.iov_base;
495
b6c1d5b8
SW
496 if (ci->i_xattrs.blob)
497 ceph_buffer_put(ci->i_xattrs.blob);
355da1eb
SW
498 ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob;
499 ci->i_xattrs.prealloc_blob = NULL;
500 ci->i_xattrs.dirty = false;
4a625be4 501 ci->i_xattrs.version++;
355da1eb
SW
502 }
503}
504
505ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value,
506 size_t size)
507{
508 struct inode *inode = dentry->d_inode;
509 struct ceph_inode_info *ci = ceph_inode(inode);
355da1eb
SW
510 int err;
511 struct ceph_inode_xattr *xattr;
512 struct ceph_vxattr_cb *vxattr = NULL;
513
514 if (!ceph_is_valid_xattr(name))
515 return -ENODATA;
516
517 /* let's see if a virtual xattr was requested */
06476a69 518 vxattr = ceph_match_vxattr(inode, name);
355da1eb 519
be655596 520 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
521 dout("getxattr %p ver=%lld index_ver=%lld\n", inode,
522 ci->i_xattrs.version, ci->i_xattrs.index_version);
523
524 if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) &&
525 (ci->i_xattrs.index_version >= ci->i_xattrs.version)) {
526 goto get_xattr;
527 } else {
be655596 528 spin_unlock(&ci->i_ceph_lock);
355da1eb
SW
529 /* get xattrs from mds (if we don't already have them) */
530 err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR);
531 if (err)
532 return err;
533 }
534
be655596 535 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
536
537 if (vxattr && vxattr->readonly) {
538 err = vxattr->getxattr_cb(ci, value, size);
539 goto out;
540 }
541
542 err = __build_xattrs(inode);
543 if (err < 0)
544 goto out;
545
546get_xattr:
547 err = -ENODATA; /* == ENOATTR */
548 xattr = __get_xattr(ci, name);
549 if (!xattr) {
550 if (vxattr)
551 err = vxattr->getxattr_cb(ci, value, size);
552 goto out;
553 }
554
555 err = -ERANGE;
556 if (size && size < xattr->val_len)
557 goto out;
558
559 err = xattr->val_len;
560 if (size == 0)
561 goto out;
562
563 memcpy(value, xattr->val, xattr->val_len);
564
565out:
be655596 566 spin_unlock(&ci->i_ceph_lock);
355da1eb
SW
567 return err;
568}
569
570ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
571{
572 struct inode *inode = dentry->d_inode;
573 struct ceph_inode_info *ci = ceph_inode(inode);
574 struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
575 u32 vir_namelen = 0;
576 u32 namelen;
577 int err;
578 u32 len;
579 int i;
580
be655596 581 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
582 dout("listxattr %p ver=%lld index_ver=%lld\n", inode,
583 ci->i_xattrs.version, ci->i_xattrs.index_version);
584
585 if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1) &&
bddfa3cc 586 (ci->i_xattrs.index_version >= ci->i_xattrs.version)) {
355da1eb
SW
587 goto list_xattr;
588 } else {
be655596 589 spin_unlock(&ci->i_ceph_lock);
355da1eb
SW
590 err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR);
591 if (err)
592 return err;
593 }
594
be655596 595 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
596
597 err = __build_xattrs(inode);
598 if (err < 0)
599 goto out;
600
601list_xattr:
602 vir_namelen = 0;
603 /* include virtual dir xattrs */
604 if (vxattrs)
605 for (i = 0; vxattrs[i].name; i++)
606 vir_namelen += strlen(vxattrs[i].name) + 1;
607 /* adding 1 byte per each variable due to the null termination */
608 namelen = vir_namelen + ci->i_xattrs.names_size + ci->i_xattrs.count;
609 err = -ERANGE;
610 if (size && namelen > size)
611 goto out;
612
613 err = namelen;
614 if (size == 0)
615 goto out;
616
617 names = __copy_xattr_names(ci, names);
618
619 /* virtual xattr names, too */
620 if (vxattrs)
621 for (i = 0; vxattrs[i].name; i++) {
622 len = sprintf(names, "%s", vxattrs[i].name);
623 names += len + 1;
624 }
625
626out:
be655596 627 spin_unlock(&ci->i_ceph_lock);
355da1eb
SW
628 return err;
629}
630
631static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
632 const char *value, size_t size, int flags)
633{
3d14c5d2 634 struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
355da1eb
SW
635 struct inode *inode = dentry->d_inode;
636 struct ceph_inode_info *ci = ceph_inode(inode);
5f21c96d 637 struct inode *parent_inode;
355da1eb 638 struct ceph_mds_request *req;
3d14c5d2 639 struct ceph_mds_client *mdsc = fsc->mdsc;
355da1eb
SW
640 int err;
641 int i, nr_pages;
642 struct page **pages = NULL;
643 void *kaddr;
644
645 /* copy value into some pages */
646 nr_pages = calc_pages_for(0, size);
647 if (nr_pages) {
648 pages = kmalloc(sizeof(pages[0])*nr_pages, GFP_NOFS);
649 if (!pages)
650 return -ENOMEM;
651 err = -ENOMEM;
652 for (i = 0; i < nr_pages; i++) {
31459fe4 653 pages[i] = __page_cache_alloc(GFP_NOFS);
355da1eb
SW
654 if (!pages[i]) {
655 nr_pages = i;
656 goto out;
657 }
658 kaddr = kmap(pages[i]);
659 memcpy(kaddr, value + i*PAGE_CACHE_SIZE,
660 min(PAGE_CACHE_SIZE, size-i*PAGE_CACHE_SIZE));
661 }
662 }
663
664 dout("setxattr value=%.*s\n", (int)size, value);
665
666 /* do request */
667 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR,
668 USE_AUTH_MDS);
60d87733
JL
669 if (IS_ERR(req)) {
670 err = PTR_ERR(req);
671 goto out;
672 }
70b666c3
SW
673 req->r_inode = inode;
674 ihold(inode);
355da1eb
SW
675 req->r_inode_drop = CEPH_CAP_XATTR_SHARED;
676 req->r_num_caps = 1;
677 req->r_args.setxattr.flags = cpu_to_le32(flags);
678 req->r_path2 = kstrdup(name, GFP_NOFS);
679
680 req->r_pages = pages;
681 req->r_num_pages = nr_pages;
682 req->r_data_len = size;
683
684 dout("xattr.ver (before): %lld\n", ci->i_xattrs.version);
5f21c96d 685 parent_inode = ceph_get_dentry_parent_inode(dentry);
355da1eb 686 err = ceph_mdsc_do_request(mdsc, parent_inode, req);
5f21c96d 687 iput(parent_inode);
355da1eb
SW
688 ceph_mdsc_put_request(req);
689 dout("xattr.ver (after): %lld\n", ci->i_xattrs.version);
690
691out:
692 if (pages) {
693 for (i = 0; i < nr_pages; i++)
694 __free_page(pages[i]);
695 kfree(pages);
696 }
697 return err;
698}
699
700int ceph_setxattr(struct dentry *dentry, const char *name,
701 const void *value, size_t size, int flags)
702{
703 struct inode *inode = dentry->d_inode;
06476a69 704 struct ceph_vxattr_cb *vxattr;
355da1eb 705 struct ceph_inode_info *ci = ceph_inode(inode);
355da1eb
SW
706 int err;
707 int name_len = strlen(name);
708 int val_len = size;
709 char *newname = NULL;
710 char *newval = NULL;
711 struct ceph_inode_xattr *xattr = NULL;
712 int issued;
713 int required_blob_size;
fca65b4a 714 int dirty;
355da1eb
SW
715
716 if (ceph_snap(inode) != CEPH_NOSNAP)
717 return -EROFS;
718
719 if (!ceph_is_valid_xattr(name))
720 return -EOPNOTSUPP;
721
06476a69
AE
722 vxattr = ceph_match_vxattr(inode, name);
723 if (vxattr && vxattr->readonly)
724 return -EOPNOTSUPP;
355da1eb
SW
725
726 /* preallocate memory for xattr name, value, index node */
727 err = -ENOMEM;
61413c2f 728 newname = kmemdup(name, name_len + 1, GFP_NOFS);
355da1eb
SW
729 if (!newname)
730 goto out;
355da1eb
SW
731
732 if (val_len) {
b829c195 733 newval = kmemdup(value, val_len, GFP_NOFS);
355da1eb
SW
734 if (!newval)
735 goto out;
355da1eb
SW
736 }
737
738 xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS);
739 if (!xattr)
740 goto out;
741
be655596 742 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
743retry:
744 issued = __ceph_caps_issued(ci, NULL);
745 if (!(issued & CEPH_CAP_XATTR_EXCL))
746 goto do_sync;
747 __build_xattrs(inode);
748
749 required_blob_size = __get_required_blob_size(ci, name_len, val_len);
750
751 if (!ci->i_xattrs.prealloc_blob ||
752 required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
753 struct ceph_buffer *blob = NULL;
754
be655596 755 spin_unlock(&ci->i_ceph_lock);
355da1eb 756 dout(" preaallocating new blob size=%d\n", required_blob_size);
b6c1d5b8 757 blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
355da1eb
SW
758 if (!blob)
759 goto out;
be655596 760 spin_lock(&ci->i_ceph_lock);
b6c1d5b8
SW
761 if (ci->i_xattrs.prealloc_blob)
762 ceph_buffer_put(ci->i_xattrs.prealloc_blob);
355da1eb
SW
763 ci->i_xattrs.prealloc_blob = blob;
764 goto retry;
765 }
766
767 dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued));
768 err = __set_xattr(ci, newname, name_len, newval,
769 val_len, 1, 1, 1, &xattr);
fca65b4a 770 dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
355da1eb
SW
771 ci->i_xattrs.dirty = true;
772 inode->i_ctime = CURRENT_TIME;
be655596 773 spin_unlock(&ci->i_ceph_lock);
fca65b4a
SW
774 if (dirty)
775 __mark_inode_dirty(inode, dirty);
355da1eb
SW
776 return err;
777
778do_sync:
be655596 779 spin_unlock(&ci->i_ceph_lock);
355da1eb
SW
780 err = ceph_sync_setxattr(dentry, name, value, size, flags);
781out:
782 kfree(newname);
783 kfree(newval);
784 kfree(xattr);
785 return err;
786}
787
788static int ceph_send_removexattr(struct dentry *dentry, const char *name)
789{
3d14c5d2
YS
790 struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
791 struct ceph_mds_client *mdsc = fsc->mdsc;
355da1eb 792 struct inode *inode = dentry->d_inode;
5f21c96d 793 struct inode *parent_inode;
355da1eb
SW
794 struct ceph_mds_request *req;
795 int err;
796
797 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_RMXATTR,
798 USE_AUTH_MDS);
799 if (IS_ERR(req))
800 return PTR_ERR(req);
70b666c3
SW
801 req->r_inode = inode;
802 ihold(inode);
355da1eb
SW
803 req->r_inode_drop = CEPH_CAP_XATTR_SHARED;
804 req->r_num_caps = 1;
805 req->r_path2 = kstrdup(name, GFP_NOFS);
806
5f21c96d 807 parent_inode = ceph_get_dentry_parent_inode(dentry);
355da1eb 808 err = ceph_mdsc_do_request(mdsc, parent_inode, req);
5f21c96d 809 iput(parent_inode);
355da1eb
SW
810 ceph_mdsc_put_request(req);
811 return err;
812}
813
814int ceph_removexattr(struct dentry *dentry, const char *name)
815{
816 struct inode *inode = dentry->d_inode;
06476a69 817 struct ceph_vxattr_cb *vxattr;
355da1eb 818 struct ceph_inode_info *ci = ceph_inode(inode);
355da1eb
SW
819 int issued;
820 int err;
83eb26af 821 int required_blob_size;
fca65b4a 822 int dirty;
355da1eb
SW
823
824 if (ceph_snap(inode) != CEPH_NOSNAP)
825 return -EROFS;
826
827 if (!ceph_is_valid_xattr(name))
828 return -EOPNOTSUPP;
829
06476a69
AE
830 vxattr = ceph_match_vxattr(inode, name);
831 if (vxattr && vxattr->readonly)
832 return -EOPNOTSUPP;
355da1eb 833
83eb26af 834 err = -ENOMEM;
be655596 835 spin_lock(&ci->i_ceph_lock);
355da1eb 836 __build_xattrs(inode);
83eb26af 837retry:
355da1eb
SW
838 issued = __ceph_caps_issued(ci, NULL);
839 dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued));
840
841 if (!(issued & CEPH_CAP_XATTR_EXCL))
842 goto do_sync;
843
83eb26af
AE
844 required_blob_size = __get_required_blob_size(ci, 0, 0);
845
846 if (!ci->i_xattrs.prealloc_blob ||
847 required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
848 struct ceph_buffer *blob;
849
850 spin_unlock(&ci->i_ceph_lock);
851 dout(" preaallocating new blob size=%d\n", required_blob_size);
852 blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
853 if (!blob)
854 goto out;
855 spin_lock(&ci->i_ceph_lock);
856 if (ci->i_xattrs.prealloc_blob)
857 ceph_buffer_put(ci->i_xattrs.prealloc_blob);
858 ci->i_xattrs.prealloc_blob = blob;
859 goto retry;
860 }
861
355da1eb 862 err = __remove_xattr_by_name(ceph_inode(inode), name);
fca65b4a 863 dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
355da1eb
SW
864 ci->i_xattrs.dirty = true;
865 inode->i_ctime = CURRENT_TIME;
866
be655596 867 spin_unlock(&ci->i_ceph_lock);
fca65b4a
SW
868 if (dirty)
869 __mark_inode_dirty(inode, dirty);
355da1eb
SW
870 return err;
871do_sync:
be655596 872 spin_unlock(&ci->i_ceph_lock);
355da1eb 873 err = ceph_send_removexattr(dentry, name);
83eb26af 874out:
355da1eb
SW
875 return err;
876}
877