ceph: use bit flags to define vxattr attributes
[linux-block.git] / fs / ceph / xattr.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
3d14c5d2 2#include <linux/ceph/ceph_debug.h>
25e6bae3 3#include <linux/ceph/pagelist.h>
3d14c5d2 4
355da1eb 5#include "super.h"
3d14c5d2
YS
6#include "mds_client.h"
7
8#include <linux/ceph/decode.h>
355da1eb
SW
9
10#include <linux/xattr.h>
4db658ea 11#include <linux/posix_acl_xattr.h>
5a0e3ad6 12#include <linux/slab.h>
355da1eb 13
22891907
AE
14#define XATTR_CEPH_PREFIX "ceph."
15#define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1)
16
bcdfeb2e
YZ
17static int __remove_xattr(struct ceph_inode_info *ci,
18 struct ceph_inode_xattr *xattr);
19
5130ccea 20static const struct xattr_handler ceph_other_xattr_handler;
2cdeb1e4 21
7221fe4c
GZ
22/*
23 * List of handlers for synthetic system.* attributes. Other
24 * attributes are handled directly.
25 */
26const struct xattr_handler *ceph_xattr_handlers[] = {
27#ifdef CONFIG_CEPH_FS_POSIX_ACL
4db658ea
LT
28 &posix_acl_access_xattr_handler,
29 &posix_acl_default_xattr_handler,
7221fe4c 30#endif
2cdeb1e4 31 &ceph_other_xattr_handler,
7221fe4c
GZ
32 NULL,
33};
34
355da1eb
SW
35static bool ceph_is_valid_xattr(const char *name)
36{
22891907 37 return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) ||
1a756278 38 !strncmp(name, XATTR_SECURITY_PREFIX,
355da1eb
SW
39 XATTR_SECURITY_PREFIX_LEN) ||
40 !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
41 !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
42}
43
44/*
45 * These define virtual xattrs exposing the recursive directory
46 * statistics and layout metadata.
47 */
881a5fa2 48struct ceph_vxattr {
355da1eb 49 char *name;
3ce6cd12 50 size_t name_size; /* strlen(name) + 1 (for '\0') */
355da1eb
SW
51 size_t (*getxattr_cb)(struct ceph_inode_info *ci, char *val,
52 size_t size);
f36e4472 53 bool (*exists_cb)(struct ceph_inode_info *ci);
4e9906e7 54 unsigned int flags;
355da1eb
SW
55};
56
4e9906e7
YZ
57#define VXATTR_FLAG_READONLY (1<<0)
58#define VXATTR_FLAG_HIDDEN (1<<1)
59
32ab0bd7
SW
60/* layouts */
61
62static bool ceph_vxattrcb_layout_exists(struct ceph_inode_info *ci)
63{
779fe0fb
YZ
64 struct ceph_file_layout *fl = &ci->i_layout;
65 return (fl->stripe_unit > 0 || fl->stripe_count > 0 ||
66 fl->object_size > 0 || fl->pool_id >= 0 ||
67 rcu_dereference_raw(fl->pool_ns) != NULL);
32ab0bd7
SW
68}
69
70static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
1e5c6649 71 size_t size)
32ab0bd7 72{
32ab0bd7
SW
73 struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb);
74 struct ceph_osd_client *osdc = &fsc->client->osdc;
779fe0fb 75 struct ceph_string *pool_ns;
7627151e 76 s64 pool = ci->i_layout.pool_id;
32ab0bd7 77 const char *pool_name;
779fe0fb 78 const char *ns_field = " pool_namespace=";
1e5c6649 79 char buf[128];
779fe0fb
YZ
80 size_t len, total_len = 0;
81 int ret;
82
83 pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);
32ab0bd7
SW
84
85 dout("ceph_vxattrcb_layout %p\n", &ci->vfs_inode);
5aea3dcd 86 down_read(&osdc->lock);
32ab0bd7 87 pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool);
1e5c6649 88 if (pool_name) {
779fe0fb 89 len = snprintf(buf, sizeof(buf),
7627151e
YZ
90 "stripe_unit=%u stripe_count=%u object_size=%u pool=",
91 ci->i_layout.stripe_unit, ci->i_layout.stripe_count,
92 ci->i_layout.object_size);
779fe0fb 93 total_len = len + strlen(pool_name);
1e5c6649 94 } else {
779fe0fb 95 len = snprintf(buf, sizeof(buf),
7627151e
YZ
96 "stripe_unit=%u stripe_count=%u object_size=%u pool=%lld",
97 ci->i_layout.stripe_unit, ci->i_layout.stripe_count,
98 ci->i_layout.object_size, (unsigned long long)pool);
779fe0fb
YZ
99 total_len = len;
100 }
101
102 if (pool_ns)
103 total_len += strlen(ns_field) + pool_ns->len;
104
105 if (!size) {
106 ret = total_len;
107 } else if (total_len > size) {
108 ret = -ERANGE;
109 } else {
110 memcpy(val, buf, len);
111 ret = len;
112 if (pool_name) {
113 len = strlen(pool_name);
114 memcpy(val + ret, pool_name, len);
115 ret += len;
116 }
117 if (pool_ns) {
118 len = strlen(ns_field);
119 memcpy(val + ret, ns_field, len);
120 ret += len;
121 memcpy(val + ret, pool_ns->str, pool_ns->len);
122 ret += pool_ns->len;
1e5c6649
YZ
123 }
124 }
5aea3dcd 125 up_read(&osdc->lock);
779fe0fb 126 ceph_put_string(pool_ns);
32ab0bd7
SW
127 return ret;
128}
129
695b7119
SW
130static size_t ceph_vxattrcb_layout_stripe_unit(struct ceph_inode_info *ci,
131 char *val, size_t size)
132{
7627151e 133 return snprintf(val, size, "%u", ci->i_layout.stripe_unit);
695b7119
SW
134}
135
136static size_t ceph_vxattrcb_layout_stripe_count(struct ceph_inode_info *ci,
137 char *val, size_t size)
138{
7627151e 139 return snprintf(val, size, "%u", ci->i_layout.stripe_count);
695b7119
SW
140}
141
142static size_t ceph_vxattrcb_layout_object_size(struct ceph_inode_info *ci,
143 char *val, size_t size)
144{
7627151e 145 return snprintf(val, size, "%u", ci->i_layout.object_size);
695b7119
SW
146}
147
148static size_t ceph_vxattrcb_layout_pool(struct ceph_inode_info *ci,
149 char *val, size_t size)
150{
151 int ret;
152 struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb);
153 struct ceph_osd_client *osdc = &fsc->client->osdc;
7627151e 154 s64 pool = ci->i_layout.pool_id;
695b7119
SW
155 const char *pool_name;
156
5aea3dcd 157 down_read(&osdc->lock);
695b7119
SW
158 pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool);
159 if (pool_name)
160 ret = snprintf(val, size, "%s", pool_name);
161 else
162 ret = snprintf(val, size, "%lld", (unsigned long long)pool);
5aea3dcd 163 up_read(&osdc->lock);
695b7119
SW
164 return ret;
165}
166
779fe0fb
YZ
167static size_t ceph_vxattrcb_layout_pool_namespace(struct ceph_inode_info *ci,
168 char *val, size_t size)
169{
170 int ret = 0;
171 struct ceph_string *ns = ceph_try_get_string(ci->i_layout.pool_ns);
172 if (ns) {
173 ret = snprintf(val, size, "%.*s", (int)ns->len, ns->str);
174 ceph_put_string(ns);
175 }
176 return ret;
177}
178
355da1eb
SW
179/* directories */
180
aa4066ed 181static size_t ceph_vxattrcb_dir_entries(struct ceph_inode_info *ci, char *val,
355da1eb
SW
182 size_t size)
183{
184 return snprintf(val, size, "%lld", ci->i_files + ci->i_subdirs);
185}
186
aa4066ed 187static size_t ceph_vxattrcb_dir_files(struct ceph_inode_info *ci, char *val,
355da1eb
SW
188 size_t size)
189{
190 return snprintf(val, size, "%lld", ci->i_files);
191}
192
aa4066ed 193static size_t ceph_vxattrcb_dir_subdirs(struct ceph_inode_info *ci, char *val,
355da1eb
SW
194 size_t size)
195{
196 return snprintf(val, size, "%lld", ci->i_subdirs);
197}
198
aa4066ed 199static size_t ceph_vxattrcb_dir_rentries(struct ceph_inode_info *ci, char *val,
355da1eb
SW
200 size_t size)
201{
202 return snprintf(val, size, "%lld", ci->i_rfiles + ci->i_rsubdirs);
203}
204
aa4066ed 205static size_t ceph_vxattrcb_dir_rfiles(struct ceph_inode_info *ci, char *val,
355da1eb
SW
206 size_t size)
207{
208 return snprintf(val, size, "%lld", ci->i_rfiles);
209}
210
aa4066ed 211static size_t ceph_vxattrcb_dir_rsubdirs(struct ceph_inode_info *ci, char *val,
355da1eb
SW
212 size_t size)
213{
214 return snprintf(val, size, "%lld", ci->i_rsubdirs);
215}
216
aa4066ed 217static size_t ceph_vxattrcb_dir_rbytes(struct ceph_inode_info *ci, char *val,
355da1eb
SW
218 size_t size)
219{
220 return snprintf(val, size, "%lld", ci->i_rbytes);
221}
222
aa4066ed 223static size_t ceph_vxattrcb_dir_rctime(struct ceph_inode_info *ci, char *val,
355da1eb
SW
224 size_t size)
225{
3489b42a 226 return snprintf(val, size, "%ld.09%ld", (long)ci->i_rctime.tv_sec,
355da1eb
SW
227 (long)ci->i_rctime.tv_nsec);
228}
229
fb18a575
LH
230/* quotas */
231
232static bool ceph_vxattrcb_quota_exists(struct ceph_inode_info *ci)
233{
f1919826
YZ
234 bool ret = false;
235 spin_lock(&ci->i_ceph_lock);
236 if ((ci->i_max_files || ci->i_max_bytes) &&
237 ci->i_vino.snap == CEPH_NOSNAP &&
238 ci->i_snap_realm &&
239 ci->i_snap_realm->ino == ci->i_vino.ino)
240 ret = true;
241 spin_unlock(&ci->i_ceph_lock);
242 return ret;
fb18a575
LH
243}
244
245static size_t ceph_vxattrcb_quota(struct ceph_inode_info *ci, char *val,
246 size_t size)
247{
248 return snprintf(val, size, "max_bytes=%llu max_files=%llu",
249 ci->i_max_bytes, ci->i_max_files);
250}
251
252static size_t ceph_vxattrcb_quota_max_bytes(struct ceph_inode_info *ci,
253 char *val, size_t size)
254{
255 return snprintf(val, size, "%llu", ci->i_max_bytes);
256}
257
258static size_t ceph_vxattrcb_quota_max_files(struct ceph_inode_info *ci,
259 char *val, size_t size)
260{
261 return snprintf(val, size, "%llu", ci->i_max_files);
262}
32ab0bd7 263
eb788084 264#define CEPH_XATTR_NAME(_type, _name) XATTR_CEPH_PREFIX #_type "." #_name
695b7119
SW
265#define CEPH_XATTR_NAME2(_type, _name, _name2) \
266 XATTR_CEPH_PREFIX #_type "." #_name "." #_name2
eb788084 267
8860147a
SW
268#define XATTR_NAME_CEPH(_type, _name) \
269 { \
270 .name = CEPH_XATTR_NAME(_type, _name), \
271 .name_size = sizeof (CEPH_XATTR_NAME(_type, _name)), \
272 .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \
4e9906e7
YZ
273 .exists_cb = NULL, \
274 .flags = VXATTR_FLAG_READONLY, \
8860147a 275 }
695b7119
SW
276#define XATTR_LAYOUT_FIELD(_type, _name, _field) \
277 { \
278 .name = CEPH_XATTR_NAME2(_type, _name, _field), \
279 .name_size = sizeof (CEPH_XATTR_NAME2(_type, _name, _field)), \
280 .getxattr_cb = ceph_vxattrcb_ ## _name ## _ ## _field, \
695b7119 281 .exists_cb = ceph_vxattrcb_layout_exists, \
4e9906e7 282 .flags = VXATTR_FLAG_HIDDEN, \
695b7119 283 }
fb18a575
LH
284#define XATTR_QUOTA_FIELD(_type, _name) \
285 { \
286 .name = CEPH_XATTR_NAME(_type, _name), \
287 .name_size = sizeof(CEPH_XATTR_NAME(_type, _name)), \
288 .getxattr_cb = ceph_vxattrcb_ ## _type ## _ ## _name, \
fb18a575 289 .exists_cb = ceph_vxattrcb_quota_exists, \
4e9906e7 290 .flags = VXATTR_FLAG_HIDDEN, \
fb18a575 291 }
eb788084 292
881a5fa2 293static struct ceph_vxattr ceph_dir_vxattrs[] = {
1f08f2b0
SW
294 {
295 .name = "ceph.dir.layout",
296 .name_size = sizeof("ceph.dir.layout"),
297 .getxattr_cb = ceph_vxattrcb_layout,
1f08f2b0 298 .exists_cb = ceph_vxattrcb_layout_exists,
4e9906e7 299 .flags = VXATTR_FLAG_HIDDEN,
1f08f2b0 300 },
695b7119
SW
301 XATTR_LAYOUT_FIELD(dir, layout, stripe_unit),
302 XATTR_LAYOUT_FIELD(dir, layout, stripe_count),
303 XATTR_LAYOUT_FIELD(dir, layout, object_size),
304 XATTR_LAYOUT_FIELD(dir, layout, pool),
779fe0fb 305 XATTR_LAYOUT_FIELD(dir, layout, pool_namespace),
eb788084
AE
306 XATTR_NAME_CEPH(dir, entries),
307 XATTR_NAME_CEPH(dir, files),
308 XATTR_NAME_CEPH(dir, subdirs),
309 XATTR_NAME_CEPH(dir, rentries),
310 XATTR_NAME_CEPH(dir, rfiles),
311 XATTR_NAME_CEPH(dir, rsubdirs),
312 XATTR_NAME_CEPH(dir, rbytes),
313 XATTR_NAME_CEPH(dir, rctime),
fb18a575
LH
314 {
315 .name = "ceph.quota",
316 .name_size = sizeof("ceph.quota"),
317 .getxattr_cb = ceph_vxattrcb_quota,
fb18a575 318 .exists_cb = ceph_vxattrcb_quota_exists,
4e9906e7 319 .flags = VXATTR_FLAG_HIDDEN,
fb18a575
LH
320 },
321 XATTR_QUOTA_FIELD(quota, max_bytes),
322 XATTR_QUOTA_FIELD(quota, max_files),
2c3dd4ff 323 { .name = NULL, 0 } /* Required table terminator */
355da1eb 324};
3ce6cd12 325static size_t ceph_dir_vxattrs_name_size; /* total size of all names */
355da1eb
SW
326
327/* files */
328
881a5fa2 329static struct ceph_vxattr ceph_file_vxattrs[] = {
32ab0bd7
SW
330 {
331 .name = "ceph.file.layout",
332 .name_size = sizeof("ceph.file.layout"),
333 .getxattr_cb = ceph_vxattrcb_layout,
32ab0bd7 334 .exists_cb = ceph_vxattrcb_layout_exists,
4e9906e7 335 .flags = VXATTR_FLAG_HIDDEN,
32ab0bd7 336 },
695b7119
SW
337 XATTR_LAYOUT_FIELD(file, layout, stripe_unit),
338 XATTR_LAYOUT_FIELD(file, layout, stripe_count),
339 XATTR_LAYOUT_FIELD(file, layout, object_size),
340 XATTR_LAYOUT_FIELD(file, layout, pool),
779fe0fb 341 XATTR_LAYOUT_FIELD(file, layout, pool_namespace),
2c3dd4ff 342 { .name = NULL, 0 } /* Required table terminator */
355da1eb 343};
3ce6cd12 344static size_t ceph_file_vxattrs_name_size; /* total size of all names */
355da1eb 345
881a5fa2 346static struct ceph_vxattr *ceph_inode_vxattrs(struct inode *inode)
355da1eb
SW
347{
348 if (S_ISDIR(inode->i_mode))
349 return ceph_dir_vxattrs;
350 else if (S_ISREG(inode->i_mode))
351 return ceph_file_vxattrs;
352 return NULL;
353}
354
3ce6cd12
AE
355static size_t ceph_vxattrs_name_size(struct ceph_vxattr *vxattrs)
356{
357 if (vxattrs == ceph_dir_vxattrs)
358 return ceph_dir_vxattrs_name_size;
359 if (vxattrs == ceph_file_vxattrs)
360 return ceph_file_vxattrs_name_size;
0abb43dc 361 BUG_ON(vxattrs);
3ce6cd12
AE
362 return 0;
363}
364
365/*
366 * Compute the aggregate size (including terminating '\0') of all
367 * virtual extended attribute names in the given vxattr table.
368 */
369static size_t __init vxattrs_name_size(struct ceph_vxattr *vxattrs)
370{
371 struct ceph_vxattr *vxattr;
372 size_t size = 0;
373
4e9906e7
YZ
374 for (vxattr = vxattrs; vxattr->name; vxattr++) {
375 if (!(vxattr->flags & VXATTR_FLAG_HIDDEN))
8860147a 376 size += vxattr->name_size;
4e9906e7 377 }
3ce6cd12
AE
378
379 return size;
380}
381
382/* Routines called at initialization and exit time */
383
384void __init ceph_xattr_init(void)
385{
386 ceph_dir_vxattrs_name_size = vxattrs_name_size(ceph_dir_vxattrs);
387 ceph_file_vxattrs_name_size = vxattrs_name_size(ceph_file_vxattrs);
388}
389
390void ceph_xattr_exit(void)
391{
392 ceph_dir_vxattrs_name_size = 0;
393 ceph_file_vxattrs_name_size = 0;
394}
395
881a5fa2 396static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode,
355da1eb
SW
397 const char *name)
398{
881a5fa2 399 struct ceph_vxattr *vxattr = ceph_inode_vxattrs(inode);
06476a69
AE
400
401 if (vxattr) {
402 while (vxattr->name) {
403 if (!strcmp(vxattr->name, name))
404 return vxattr;
405 vxattr++;
406 }
407 }
408
355da1eb
SW
409 return NULL;
410}
411
412static int __set_xattr(struct ceph_inode_info *ci,
413 const char *name, int name_len,
414 const char *val, int val_len,
fbc0b970 415 int flags, int update_xattr,
355da1eb
SW
416 struct ceph_inode_xattr **newxattr)
417{
418 struct rb_node **p;
419 struct rb_node *parent = NULL;
420 struct ceph_inode_xattr *xattr = NULL;
421 int c;
422 int new = 0;
423
424 p = &ci->i_xattrs.index.rb_node;
425 while (*p) {
426 parent = *p;
427 xattr = rb_entry(parent, struct ceph_inode_xattr, node);
428 c = strncmp(name, xattr->name, min(name_len, xattr->name_len));
429 if (c < 0)
430 p = &(*p)->rb_left;
431 else if (c > 0)
432 p = &(*p)->rb_right;
433 else {
434 if (name_len == xattr->name_len)
435 break;
436 else if (name_len < xattr->name_len)
437 p = &(*p)->rb_left;
438 else
439 p = &(*p)->rb_right;
440 }
441 xattr = NULL;
442 }
443
fbc0b970
YZ
444 if (update_xattr) {
445 int err = 0;
eeca958d 446
fbc0b970
YZ
447 if (xattr && (flags & XATTR_CREATE))
448 err = -EEXIST;
449 else if (!xattr && (flags & XATTR_REPLACE))
450 err = -ENODATA;
451 if (err) {
452 kfree(name);
453 kfree(val);
eeca958d 454 kfree(*newxattr);
fbc0b970
YZ
455 return err;
456 }
bcdfeb2e
YZ
457 if (update_xattr < 0) {
458 if (xattr)
459 __remove_xattr(ci, xattr);
460 kfree(name);
eeca958d 461 kfree(*newxattr);
bcdfeb2e
YZ
462 return 0;
463 }
fbc0b970
YZ
464 }
465
355da1eb
SW
466 if (!xattr) {
467 new = 1;
468 xattr = *newxattr;
469 xattr->name = name;
470 xattr->name_len = name_len;
fbc0b970 471 xattr->should_free_name = update_xattr;
355da1eb
SW
472
473 ci->i_xattrs.count++;
474 dout("__set_xattr count=%d\n", ci->i_xattrs.count);
475 } else {
476 kfree(*newxattr);
477 *newxattr = NULL;
478 if (xattr->should_free_val)
479 kfree((void *)xattr->val);
480
fbc0b970 481 if (update_xattr) {
355da1eb
SW
482 kfree((void *)name);
483 name = xattr->name;
484 }
485 ci->i_xattrs.names_size -= xattr->name_len;
486 ci->i_xattrs.vals_size -= xattr->val_len;
487 }
355da1eb
SW
488 ci->i_xattrs.names_size += name_len;
489 ci->i_xattrs.vals_size += val_len;
490 if (val)
491 xattr->val = val;
492 else
493 xattr->val = "";
494
495 xattr->val_len = val_len;
fbc0b970
YZ
496 xattr->dirty = update_xattr;
497 xattr->should_free_val = (val && update_xattr);
355da1eb
SW
498
499 if (new) {
500 rb_link_node(&xattr->node, parent, p);
501 rb_insert_color(&xattr->node, &ci->i_xattrs.index);
502 dout("__set_xattr_val p=%p\n", p);
503 }
504
505 dout("__set_xattr_val added %llx.%llx xattr %p %s=%.*s\n",
506 ceph_vinop(&ci->vfs_inode), xattr, name, val_len, val);
507
508 return 0;
509}
510
511static struct ceph_inode_xattr *__get_xattr(struct ceph_inode_info *ci,
512 const char *name)
513{
514 struct rb_node **p;
515 struct rb_node *parent = NULL;
516 struct ceph_inode_xattr *xattr = NULL;
17db143f 517 int name_len = strlen(name);
355da1eb
SW
518 int c;
519
520 p = &ci->i_xattrs.index.rb_node;
521 while (*p) {
522 parent = *p;
523 xattr = rb_entry(parent, struct ceph_inode_xattr, node);
524 c = strncmp(name, xattr->name, xattr->name_len);
17db143f
SW
525 if (c == 0 && name_len > xattr->name_len)
526 c = 1;
355da1eb
SW
527 if (c < 0)
528 p = &(*p)->rb_left;
529 else if (c > 0)
530 p = &(*p)->rb_right;
531 else {
532 dout("__get_xattr %s: found %.*s\n", name,
533 xattr->val_len, xattr->val);
534 return xattr;
535 }
536 }
537
538 dout("__get_xattr %s: not found\n", name);
539
540 return NULL;
541}
542
543static void __free_xattr(struct ceph_inode_xattr *xattr)
544{
545 BUG_ON(!xattr);
546
547 if (xattr->should_free_name)
548 kfree((void *)xattr->name);
549 if (xattr->should_free_val)
550 kfree((void *)xattr->val);
551
552 kfree(xattr);
553}
554
555static int __remove_xattr(struct ceph_inode_info *ci,
556 struct ceph_inode_xattr *xattr)
557{
558 if (!xattr)
524186ac 559 return -ENODATA;
355da1eb
SW
560
561 rb_erase(&xattr->node, &ci->i_xattrs.index);
562
563 if (xattr->should_free_name)
564 kfree((void *)xattr->name);
565 if (xattr->should_free_val)
566 kfree((void *)xattr->val);
567
568 ci->i_xattrs.names_size -= xattr->name_len;
569 ci->i_xattrs.vals_size -= xattr->val_len;
570 ci->i_xattrs.count--;
571 kfree(xattr);
572
573 return 0;
574}
575
355da1eb
SW
576static char *__copy_xattr_names(struct ceph_inode_info *ci,
577 char *dest)
578{
579 struct rb_node *p;
580 struct ceph_inode_xattr *xattr = NULL;
581
582 p = rb_first(&ci->i_xattrs.index);
583 dout("__copy_xattr_names count=%d\n", ci->i_xattrs.count);
584
585 while (p) {
586 xattr = rb_entry(p, struct ceph_inode_xattr, node);
587 memcpy(dest, xattr->name, xattr->name_len);
588 dest[xattr->name_len] = '\0';
589
590 dout("dest=%s %p (%s) (%d/%d)\n", dest, xattr, xattr->name,
591 xattr->name_len, ci->i_xattrs.names_size);
592
593 dest += xattr->name_len + 1;
594 p = rb_next(p);
595 }
596
597 return dest;
598}
599
600void __ceph_destroy_xattrs(struct ceph_inode_info *ci)
601{
602 struct rb_node *p, *tmp;
603 struct ceph_inode_xattr *xattr = NULL;
604
605 p = rb_first(&ci->i_xattrs.index);
606
607 dout("__ceph_destroy_xattrs p=%p\n", p);
608
609 while (p) {
610 xattr = rb_entry(p, struct ceph_inode_xattr, node);
611 tmp = p;
612 p = rb_next(tmp);
613 dout("__ceph_destroy_xattrs next p=%p (%.*s)\n", p,
614 xattr->name_len, xattr->name);
615 rb_erase(tmp, &ci->i_xattrs.index);
616
617 __free_xattr(xattr);
618 }
619
620 ci->i_xattrs.names_size = 0;
621 ci->i_xattrs.vals_size = 0;
622 ci->i_xattrs.index_version = 0;
623 ci->i_xattrs.count = 0;
624 ci->i_xattrs.index = RB_ROOT;
625}
626
627static int __build_xattrs(struct inode *inode)
be655596
SW
628 __releases(ci->i_ceph_lock)
629 __acquires(ci->i_ceph_lock)
355da1eb
SW
630{
631 u32 namelen;
632 u32 numattr = 0;
633 void *p, *end;
634 u32 len;
635 const char *name, *val;
636 struct ceph_inode_info *ci = ceph_inode(inode);
637 int xattr_version;
638 struct ceph_inode_xattr **xattrs = NULL;
63ff78b2 639 int err = 0;
355da1eb
SW
640 int i;
641
642 dout("__build_xattrs() len=%d\n",
643 ci->i_xattrs.blob ? (int)ci->i_xattrs.blob->vec.iov_len : 0);
644
645 if (ci->i_xattrs.index_version >= ci->i_xattrs.version)
646 return 0; /* already built */
647
648 __ceph_destroy_xattrs(ci);
649
650start:
651 /* updated internal xattr rb tree */
652 if (ci->i_xattrs.blob && ci->i_xattrs.blob->vec.iov_len > 4) {
653 p = ci->i_xattrs.blob->vec.iov_base;
654 end = p + ci->i_xattrs.blob->vec.iov_len;
655 ceph_decode_32_safe(&p, end, numattr, bad);
656 xattr_version = ci->i_xattrs.version;
be655596 657 spin_unlock(&ci->i_ceph_lock);
355da1eb 658
7e8a2952 659 xattrs = kcalloc(numattr, sizeof(struct ceph_inode_xattr *),
355da1eb
SW
660 GFP_NOFS);
661 err = -ENOMEM;
662 if (!xattrs)
663 goto bad_lock;
1a295bd8 664
355da1eb
SW
665 for (i = 0; i < numattr; i++) {
666 xattrs[i] = kmalloc(sizeof(struct ceph_inode_xattr),
667 GFP_NOFS);
668 if (!xattrs[i])
669 goto bad_lock;
670 }
671
be655596 672 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
673 if (ci->i_xattrs.version != xattr_version) {
674 /* lost a race, retry */
675 for (i = 0; i < numattr; i++)
676 kfree(xattrs[i]);
677 kfree(xattrs);
21ec6ffa 678 xattrs = NULL;
355da1eb
SW
679 goto start;
680 }
681 err = -EIO;
682 while (numattr--) {
683 ceph_decode_32_safe(&p, end, len, bad);
684 namelen = len;
685 name = p;
686 p += len;
687 ceph_decode_32_safe(&p, end, len, bad);
688 val = p;
689 p += len;
690
691 err = __set_xattr(ci, name, namelen, val, len,
fbc0b970 692 0, 0, &xattrs[numattr]);
355da1eb
SW
693
694 if (err < 0)
695 goto bad;
696 }
697 kfree(xattrs);
698 }
699 ci->i_xattrs.index_version = ci->i_xattrs.version;
700 ci->i_xattrs.dirty = false;
701
702 return err;
703bad_lock:
be655596 704 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
705bad:
706 if (xattrs) {
707 for (i = 0; i < numattr; i++)
708 kfree(xattrs[i]);
709 kfree(xattrs);
710 }
711 ci->i_xattrs.names_size = 0;
712 return err;
713}
714
715static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size,
716 int val_size)
717{
718 /*
719 * 4 bytes for the length, and additional 4 bytes per each xattr name,
720 * 4 bytes per each value
721 */
722 int size = 4 + ci->i_xattrs.count*(4 + 4) +
723 ci->i_xattrs.names_size +
724 ci->i_xattrs.vals_size;
725 dout("__get_required_blob_size c=%d names.size=%d vals.size=%d\n",
726 ci->i_xattrs.count, ci->i_xattrs.names_size,
727 ci->i_xattrs.vals_size);
728
729 if (name_size)
730 size += 4 + 4 + name_size + val_size;
731
732 return size;
733}
734
735/*
736 * If there are dirty xattrs, reencode xattrs into the prealloc_blob
737 * and swap into place.
738 */
739void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
740{
741 struct rb_node *p;
742 struct ceph_inode_xattr *xattr = NULL;
743 void *dest;
744
745 dout("__build_xattrs_blob %p\n", &ci->vfs_inode);
746 if (ci->i_xattrs.dirty) {
747 int need = __get_required_blob_size(ci, 0, 0);
748
749 BUG_ON(need > ci->i_xattrs.prealloc_blob->alloc_len);
750
751 p = rb_first(&ci->i_xattrs.index);
752 dest = ci->i_xattrs.prealloc_blob->vec.iov_base;
753
754 ceph_encode_32(&dest, ci->i_xattrs.count);
755 while (p) {
756 xattr = rb_entry(p, struct ceph_inode_xattr, node);
757
758 ceph_encode_32(&dest, xattr->name_len);
759 memcpy(dest, xattr->name, xattr->name_len);
760 dest += xattr->name_len;
761 ceph_encode_32(&dest, xattr->val_len);
762 memcpy(dest, xattr->val, xattr->val_len);
763 dest += xattr->val_len;
764
765 p = rb_next(p);
766 }
767
768 /* adjust buffer len; it may be larger than we need */
769 ci->i_xattrs.prealloc_blob->vec.iov_len =
770 dest - ci->i_xattrs.prealloc_blob->vec.iov_base;
771
b6c1d5b8
SW
772 if (ci->i_xattrs.blob)
773 ceph_buffer_put(ci->i_xattrs.blob);
355da1eb
SW
774 ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob;
775 ci->i_xattrs.prealloc_blob = NULL;
776 ci->i_xattrs.dirty = false;
4a625be4 777 ci->i_xattrs.version++;
355da1eb
SW
778 }
779}
780
315f2408
YZ
781static inline int __get_request_mask(struct inode *in) {
782 struct ceph_mds_request *req = current->journal_info;
783 int mask = 0;
784 if (req && req->r_target_inode == in) {
785 if (req->r_op == CEPH_MDS_OP_LOOKUP ||
786 req->r_op == CEPH_MDS_OP_LOOKUPINO ||
787 req->r_op == CEPH_MDS_OP_LOOKUPPARENT ||
788 req->r_op == CEPH_MDS_OP_GETATTR) {
789 mask = le32_to_cpu(req->r_args.getattr.mask);
790 } else if (req->r_op == CEPH_MDS_OP_OPEN ||
791 req->r_op == CEPH_MDS_OP_CREATE) {
792 mask = le32_to_cpu(req->r_args.open.mask);
793 }
794 }
795 return mask;
796}
797
7221fe4c 798ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
355da1eb
SW
799 size_t size)
800{
355da1eb 801 struct ceph_inode_info *ci = ceph_inode(inode);
355da1eb 802 struct ceph_inode_xattr *xattr;
881a5fa2 803 struct ceph_vxattr *vxattr = NULL;
315f2408
YZ
804 int req_mask;
805 int err;
355da1eb 806
0bee82fb
SW
807 /* let's see if a virtual xattr was requested */
808 vxattr = ceph_match_vxattr(inode, name);
29dccfa5 809 if (vxattr) {
1684dd03
YZ
810 err = ceph_do_getattr(inode, 0, true);
811 if (err)
812 return err;
29dccfa5
YZ
813 err = -ENODATA;
814 if (!(vxattr->exists_cb && !vxattr->exists_cb(ci)))
815 err = vxattr->getxattr_cb(ci, value, size);
a1dc1937 816 return err;
0bee82fb
SW
817 }
818
315f2408
YZ
819 req_mask = __get_request_mask(inode);
820
a1dc1937 821 spin_lock(&ci->i_ceph_lock);
822 dout("getxattr %p ver=%lld index_ver=%lld\n", inode,
823 ci->i_xattrs.version, ci->i_xattrs.index_version);
824
508b32d8 825 if (ci->i_xattrs.version == 0 ||
315f2408
YZ
826 !((req_mask & CEPH_CAP_XATTR_SHARED) ||
827 __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1))) {
be655596 828 spin_unlock(&ci->i_ceph_lock);
315f2408
YZ
829
830 /* security module gets xattr while filling trace */
d37b1d99 831 if (current->journal_info) {
315f2408
YZ
832 pr_warn_ratelimited("sync getxattr %p "
833 "during filling trace\n", inode);
834 return -EBUSY;
835 }
836
355da1eb 837 /* get xattrs from mds (if we don't already have them) */
508b32d8 838 err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true);
355da1eb
SW
839 if (err)
840 return err;
508b32d8 841 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
842 }
843
355da1eb
SW
844 err = __build_xattrs(inode);
845 if (err < 0)
846 goto out;
847
355da1eb
SW
848 err = -ENODATA; /* == ENOATTR */
849 xattr = __get_xattr(ci, name);
0bee82fb 850 if (!xattr)
355da1eb 851 goto out;
355da1eb
SW
852
853 err = -ERANGE;
854 if (size && size < xattr->val_len)
855 goto out;
856
857 err = xattr->val_len;
858 if (size == 0)
859 goto out;
860
861 memcpy(value, xattr->val, xattr->val_len);
862
d37b1d99 863 if (current->journal_info &&
315f2408
YZ
864 !strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN))
865 ci->i_ceph_flags |= CEPH_I_SEC_INITED;
355da1eb 866out:
be655596 867 spin_unlock(&ci->i_ceph_lock);
355da1eb
SW
868 return err;
869}
870
871ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
872{
2b0143b5 873 struct inode *inode = d_inode(dentry);
355da1eb 874 struct ceph_inode_info *ci = ceph_inode(inode);
881a5fa2 875 struct ceph_vxattr *vxattrs = ceph_inode_vxattrs(inode);
355da1eb
SW
876 u32 vir_namelen = 0;
877 u32 namelen;
878 int err;
879 u32 len;
880 int i;
881
be655596 882 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
883 dout("listxattr %p ver=%lld index_ver=%lld\n", inode,
884 ci->i_xattrs.version, ci->i_xattrs.index_version);
885
508b32d8
YZ
886 if (ci->i_xattrs.version == 0 ||
887 !__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 1)) {
be655596 888 spin_unlock(&ci->i_ceph_lock);
508b32d8 889 err = ceph_do_getattr(inode, CEPH_STAT_CAP_XATTR, true);
355da1eb
SW
890 if (err)
891 return err;
508b32d8 892 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
893 }
894
355da1eb
SW
895 err = __build_xattrs(inode);
896 if (err < 0)
897 goto out;
3ce6cd12
AE
898 /*
899 * Start with virtual dir xattr names (if any) (including
900 * terminating '\0' characters for each).
901 */
902 vir_namelen = ceph_vxattrs_name_size(vxattrs);
903
355da1eb 904 /* adding 1 byte per each variable due to the null termination */
b65917dd 905 namelen = ci->i_xattrs.names_size + ci->i_xattrs.count;
355da1eb 906 err = -ERANGE;
b65917dd 907 if (size && vir_namelen + namelen > size)
355da1eb
SW
908 goto out;
909
b65917dd 910 err = namelen + vir_namelen;
355da1eb
SW
911 if (size == 0)
912 goto out;
913
914 names = __copy_xattr_names(ci, names);
915
916 /* virtual xattr names, too */
b65917dd
SW
917 err = namelen;
918 if (vxattrs) {
355da1eb 919 for (i = 0; vxattrs[i].name; i++) {
4e9906e7 920 if (!(vxattrs[i].flags & VXATTR_FLAG_HIDDEN) &&
b65917dd
SW
921 !(vxattrs[i].exists_cb &&
922 !vxattrs[i].exists_cb(ci))) {
923 len = sprintf(names, "%s", vxattrs[i].name);
924 names += len + 1;
925 err += len + 1;
926 }
355da1eb 927 }
b65917dd 928 }
355da1eb
SW
929
930out:
be655596 931 spin_unlock(&ci->i_ceph_lock);
355da1eb
SW
932 return err;
933}
934
a26fecca 935static int ceph_sync_setxattr(struct inode *inode, const char *name,
355da1eb
SW
936 const char *value, size_t size, int flags)
937{
a26fecca 938 struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
355da1eb 939 struct ceph_inode_info *ci = ceph_inode(inode);
355da1eb 940 struct ceph_mds_request *req;
3d14c5d2 941 struct ceph_mds_client *mdsc = fsc->mdsc;
25e6bae3 942 struct ceph_pagelist *pagelist = NULL;
04303d8a 943 int op = CEPH_MDS_OP_SETXATTR;
355da1eb 944 int err;
25e6bae3 945
0aeff37a 946 if (size > 0) {
25e6bae3
YZ
947 /* copy value into pagelist */
948 pagelist = kmalloc(sizeof(*pagelist), GFP_NOFS);
949 if (!pagelist)
355da1eb 950 return -ENOMEM;
25e6bae3
YZ
951
952 ceph_pagelist_init(pagelist);
953 err = ceph_pagelist_append(pagelist, value, size);
954 if (err)
955 goto out;
0aeff37a 956 } else if (!value) {
04303d8a
YZ
957 if (flags & CEPH_XATTR_REPLACE)
958 op = CEPH_MDS_OP_RMXATTR;
959 else
960 flags |= CEPH_XATTR_REMOVE;
355da1eb
SW
961 }
962
963 dout("setxattr value=%.*s\n", (int)size, value);
964
965 /* do request */
04303d8a 966 req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
60d87733
JL
967 if (IS_ERR(req)) {
968 err = PTR_ERR(req);
969 goto out;
970 }
a149bb9a 971
355da1eb 972 req->r_path2 = kstrdup(name, GFP_NOFS);
a149bb9a
SK
973 if (!req->r_path2) {
974 ceph_mdsc_put_request(req);
975 err = -ENOMEM;
976 goto out;
977 }
355da1eb 978
04303d8a
YZ
979 if (op == CEPH_MDS_OP_SETXATTR) {
980 req->r_args.setxattr.flags = cpu_to_le32(flags);
981 req->r_pagelist = pagelist;
982 pagelist = NULL;
983 }
355da1eb 984
a149bb9a
SK
985 req->r_inode = inode;
986 ihold(inode);
987 req->r_num_caps = 1;
988 req->r_inode_drop = CEPH_CAP_XATTR_SHARED;
989
355da1eb 990 dout("xattr.ver (before): %lld\n", ci->i_xattrs.version);
752c8bdc 991 err = ceph_mdsc_do_request(mdsc, NULL, req);
355da1eb
SW
992 ceph_mdsc_put_request(req);
993 dout("xattr.ver (after): %lld\n", ci->i_xattrs.version);
994
995out:
25e6bae3
YZ
996 if (pagelist)
997 ceph_pagelist_release(pagelist);
355da1eb
SW
998 return err;
999}
1000
a26fecca 1001int __ceph_setxattr(struct inode *inode, const char *name,
7221fe4c 1002 const void *value, size_t size, int flags)
355da1eb 1003{
881a5fa2 1004 struct ceph_vxattr *vxattr;
355da1eb 1005 struct ceph_inode_info *ci = ceph_inode(inode);
a26fecca 1006 struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
f66fd9f0 1007 struct ceph_cap_flush *prealloc_cf = NULL;
18fa8b3f 1008 int issued;
355da1eb 1009 int err;
fbc0b970 1010 int dirty = 0;
355da1eb
SW
1011 int name_len = strlen(name);
1012 int val_len = size;
1013 char *newname = NULL;
1014 char *newval = NULL;
1015 struct ceph_inode_xattr *xattr = NULL;
355da1eb 1016 int required_blob_size;
f1919826 1017 bool check_realm = false;
604d1b02 1018 bool lock_snap_rwsem = false;
355da1eb 1019
2cdeb1e4
AG
1020 if (ceph_snap(inode) != CEPH_NOSNAP)
1021 return -EROFS;
355da1eb 1022
06476a69 1023 vxattr = ceph_match_vxattr(inode, name);
f1919826 1024 if (vxattr) {
4e9906e7 1025 if (vxattr->flags & VXATTR_FLAG_READONLY)
f1919826
YZ
1026 return -EOPNOTSUPP;
1027 if (value && !strncmp(vxattr->name, "ceph.quota", 10))
1028 check_realm = true;
1029 }
355da1eb 1030
3adf654d
SW
1031 /* pass any unhandled ceph.* xattrs through to the MDS */
1032 if (!strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN))
1033 goto do_sync_unlocked;
1034
355da1eb
SW
1035 /* preallocate memory for xattr name, value, index node */
1036 err = -ENOMEM;
61413c2f 1037 newname = kmemdup(name, name_len + 1, GFP_NOFS);
355da1eb
SW
1038 if (!newname)
1039 goto out;
355da1eb
SW
1040
1041 if (val_len) {
b829c195 1042 newval = kmemdup(value, val_len, GFP_NOFS);
355da1eb
SW
1043 if (!newval)
1044 goto out;
355da1eb
SW
1045 }
1046
1047 xattr = kmalloc(sizeof(struct ceph_inode_xattr), GFP_NOFS);
1048 if (!xattr)
1049 goto out;
1050
f66fd9f0
YZ
1051 prealloc_cf = ceph_alloc_cap_flush();
1052 if (!prealloc_cf)
1053 goto out;
1054
be655596 1055 spin_lock(&ci->i_ceph_lock);
355da1eb
SW
1056retry:
1057 issued = __ceph_caps_issued(ci, NULL);
508b32d8 1058 if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL))
355da1eb 1059 goto do_sync;
604d1b02
YZ
1060
1061 if (!lock_snap_rwsem && !ci->i_head_snapc) {
1062 lock_snap_rwsem = true;
1063 if (!down_read_trylock(&mdsc->snap_rwsem)) {
1064 spin_unlock(&ci->i_ceph_lock);
1065 down_read(&mdsc->snap_rwsem);
1066 spin_lock(&ci->i_ceph_lock);
1067 goto retry;
1068 }
1069 }
1070
1071 dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued));
355da1eb
SW
1072 __build_xattrs(inode);
1073
1074 required_blob_size = __get_required_blob_size(ci, name_len, val_len);
1075
1076 if (!ci->i_xattrs.prealloc_blob ||
1077 required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
18fa8b3f 1078 struct ceph_buffer *blob;
355da1eb 1079
be655596 1080 spin_unlock(&ci->i_ceph_lock);
355da1eb 1081 dout(" preaallocating new blob size=%d\n", required_blob_size);
b6c1d5b8 1082 blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
355da1eb 1083 if (!blob)
604d1b02 1084 goto do_sync_unlocked;
be655596 1085 spin_lock(&ci->i_ceph_lock);
b6c1d5b8
SW
1086 if (ci->i_xattrs.prealloc_blob)
1087 ceph_buffer_put(ci->i_xattrs.prealloc_blob);
355da1eb
SW
1088 ci->i_xattrs.prealloc_blob = blob;
1089 goto retry;
1090 }
1091
bcdfeb2e
YZ
1092 err = __set_xattr(ci, newname, name_len, newval, val_len,
1093 flags, value ? 1 : -1, &xattr);
18fa8b3f 1094
fbc0b970 1095 if (!err) {
f66fd9f0
YZ
1096 dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL,
1097 &prealloc_cf);
fbc0b970 1098 ci->i_xattrs.dirty = true;
c2050a45 1099 inode->i_ctime = current_time(inode);
fbc0b970 1100 }
18fa8b3f 1101
be655596 1102 spin_unlock(&ci->i_ceph_lock);
604d1b02
YZ
1103 if (lock_snap_rwsem)
1104 up_read(&mdsc->snap_rwsem);
fca65b4a
SW
1105 if (dirty)
1106 __mark_inode_dirty(inode, dirty);
f66fd9f0 1107 ceph_free_cap_flush(prealloc_cf);
355da1eb
SW
1108 return err;
1109
1110do_sync:
be655596 1111 spin_unlock(&ci->i_ceph_lock);
3adf654d 1112do_sync_unlocked:
604d1b02
YZ
1113 if (lock_snap_rwsem)
1114 up_read(&mdsc->snap_rwsem);
315f2408
YZ
1115
1116 /* security module set xattr while filling trace */
d37b1d99 1117 if (current->journal_info) {
315f2408
YZ
1118 pr_warn_ratelimited("sync setxattr %p "
1119 "during filling trace\n", inode);
1120 err = -EBUSY;
1121 } else {
a26fecca 1122 err = ceph_sync_setxattr(inode, name, value, size, flags);
f1919826
YZ
1123 if (err >= 0 && check_realm) {
1124 /* check if snaprealm was created for quota inode */
1125 spin_lock(&ci->i_ceph_lock);
1126 if ((ci->i_max_files || ci->i_max_bytes) &&
1127 !(ci->i_snap_realm &&
1128 ci->i_snap_realm->ino == ci->i_vino.ino))
1129 err = -EOPNOTSUPP;
1130 spin_unlock(&ci->i_ceph_lock);
1131 }
315f2408 1132 }
355da1eb 1133out:
f66fd9f0 1134 ceph_free_cap_flush(prealloc_cf);
355da1eb
SW
1135 kfree(newname);
1136 kfree(newval);
1137 kfree(xattr);
1138 return err;
1139}
1140
2cdeb1e4
AG
1141static int ceph_get_xattr_handler(const struct xattr_handler *handler,
1142 struct dentry *dentry, struct inode *inode,
1143 const char *name, void *value, size_t size)
7221fe4c 1144{
2cdeb1e4
AG
1145 if (!ceph_is_valid_xattr(name))
1146 return -EOPNOTSUPP;
1147 return __ceph_getxattr(inode, name, value, size);
1148}
7221fe4c 1149
2cdeb1e4 1150static int ceph_set_xattr_handler(const struct xattr_handler *handler,
59301226
AV
1151 struct dentry *unused, struct inode *inode,
1152 const char *name, const void *value,
1153 size_t size, int flags)
2cdeb1e4
AG
1154{
1155 if (!ceph_is_valid_xattr(name))
1156 return -EOPNOTSUPP;
59301226 1157 return __ceph_setxattr(inode, name, value, size, flags);
7221fe4c 1158}
315f2408 1159
5130ccea 1160static const struct xattr_handler ceph_other_xattr_handler = {
2cdeb1e4
AG
1161 .prefix = "", /* match any name => handlers called with full name */
1162 .get = ceph_get_xattr_handler,
1163 .set = ceph_set_xattr_handler,
1164};
1165
315f2408
YZ
1166#ifdef CONFIG_SECURITY
1167bool ceph_security_xattr_wanted(struct inode *in)
1168{
1169 return in->i_security != NULL;
1170}
1171
1172bool ceph_security_xattr_deadlock(struct inode *in)
1173{
1174 struct ceph_inode_info *ci;
1175 bool ret;
d37b1d99 1176 if (!in->i_security)
315f2408
YZ
1177 return false;
1178 ci = ceph_inode(in);
1179 spin_lock(&ci->i_ceph_lock);
1180 ret = !(ci->i_ceph_flags & CEPH_I_SEC_INITED) &&
1181 !(ci->i_xattrs.version > 0 &&
1182 __ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0));
1183 spin_unlock(&ci->i_ceph_lock);
1184 return ret;
1185}
1186#endif