aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph/xattr.c
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2009-10-06 14:31:08 -0400
committerSage Weil <sage@newdream.net>2009-10-06 14:31:08 -0400
commit355da1eb7a1f91c276b991764e951bbcd8047599 (patch)
tree18b30761cbbeaa2b104957f5d50fb4c5296a52c5 /fs/ceph/xattr.c
parent16725b9d2a2e3d0fd2b0034482e2eb0a2d78050f (diff)
ceph: inode operations
Inode cache and inode operations. We also include routines to incorporate metadata structures returned by the MDS into the client cache, and some helpers to deal with file capabilities and metadata leases. The bulk of that work is done by fill_inode() and fill_trace(). Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs/ceph/xattr.c')
-rw-r--r--fs/ceph/xattr.c833
1 files changed, 833 insertions, 0 deletions
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
new file mode 100644
index 000000000000..8eaac04d1b87
--- /dev/null
+++ b/fs/ceph/xattr.c
@@ -0,0 +1,833 @@
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