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