1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include "bcachefs.h" |
4 | #include "acl.h" |
5 | #include "bkey_methods.h" |
6 | #include "btree_update.h" |
7 | #include "extents.h" |
8 | #include "fs.h" |
9 | #include "rebalance.h" |
10 | #include "str_hash.h" |
11 | #include "xattr.h" |
12 | |
13 | #include <linux/dcache.h> |
14 | #include <linux/posix_acl_xattr.h> |
15 | #include <linux/xattr.h> |
16 | |
17 | static const struct xattr_handler *bch2_xattr_type_to_handler(unsigned); |
18 | |
19 | static u64 bch2_xattr_hash(const struct bch_hash_info *info, |
20 | const struct xattr_search_key *key) |
21 | { |
22 | struct bch_str_hash_ctx ctx; |
23 | |
24 | bch2_str_hash_init(ctx: &ctx, info); |
25 | bch2_str_hash_update(ctx: &ctx, info, data: &key->type, len: sizeof(key->type)); |
26 | bch2_str_hash_update(ctx: &ctx, info, data: key->name.name, len: key->name.len); |
27 | |
28 | return bch2_str_hash_end(ctx: &ctx, info); |
29 | } |
30 | |
31 | static u64 xattr_hash_key(const struct bch_hash_info *info, const void *key) |
32 | { |
33 | return bch2_xattr_hash(info, key); |
34 | } |
35 | |
36 | static u64 xattr_hash_bkey(const struct bch_hash_info *info, struct bkey_s_c k) |
37 | { |
38 | struct bkey_s_c_xattr x = bkey_s_c_to_xattr(k); |
39 | |
40 | return bch2_xattr_hash(info, |
41 | key: &X_SEARCH(x.v->x_type, x.v->x_name, x.v->x_name_len)); |
42 | } |
43 | |
44 | static bool xattr_cmp_key(struct bkey_s_c _l, const void *_r) |
45 | { |
46 | struct bkey_s_c_xattr l = bkey_s_c_to_xattr(k: _l); |
47 | const struct xattr_search_key *r = _r; |
48 | |
49 | return l.v->x_type != r->type || |
50 | l.v->x_name_len != r->name.len || |
51 | memcmp(p: l.v->x_name, q: r->name.name, size: r->name.len); |
52 | } |
53 | |
54 | static bool xattr_cmp_bkey(struct bkey_s_c _l, struct bkey_s_c _r) |
55 | { |
56 | struct bkey_s_c_xattr l = bkey_s_c_to_xattr(k: _l); |
57 | struct bkey_s_c_xattr r = bkey_s_c_to_xattr(k: _r); |
58 | |
59 | return l.v->x_type != r.v->x_type || |
60 | l.v->x_name_len != r.v->x_name_len || |
61 | memcmp(p: l.v->x_name, q: r.v->x_name, size: r.v->x_name_len); |
62 | } |
63 | |
64 | const struct bch_hash_desc bch2_xattr_hash_desc = { |
65 | .btree_id = BTREE_ID_xattrs, |
66 | .key_type = KEY_TYPE_xattr, |
67 | .hash_key = xattr_hash_key, |
68 | .hash_bkey = xattr_hash_bkey, |
69 | .cmp_key = xattr_cmp_key, |
70 | .cmp_bkey = xattr_cmp_bkey, |
71 | }; |
72 | |
73 | int bch2_xattr_invalid(struct bch_fs *c, struct bkey_s_c k, |
74 | enum bkey_invalid_flags flags, |
75 | struct printbuf *err) |
76 | { |
77 | struct bkey_s_c_xattr xattr = bkey_s_c_to_xattr(k); |
78 | unsigned val_u64s = xattr_val_u64s(name_len: xattr.v->x_name_len, |
79 | le16_to_cpu(xattr.v->x_val_len)); |
80 | int ret = 0; |
81 | |
82 | bkey_fsck_err_on(bkey_val_u64s(k.k) < val_u64s, c, err, |
83 | xattr_val_size_too_small, |
84 | "value too small (%zu < %u)" , |
85 | bkey_val_u64s(k.k), val_u64s); |
86 | |
87 | /* XXX why +4 ? */ |
88 | val_u64s = xattr_val_u64s(name_len: xattr.v->x_name_len, |
89 | le16_to_cpu(xattr.v->x_val_len) + 4); |
90 | |
91 | bkey_fsck_err_on(bkey_val_u64s(k.k) > val_u64s, c, err, |
92 | xattr_val_size_too_big, |
93 | "value too big (%zu > %u)" , |
94 | bkey_val_u64s(k.k), val_u64s); |
95 | |
96 | bkey_fsck_err_on(!bch2_xattr_type_to_handler(xattr.v->x_type), c, err, |
97 | xattr_invalid_type, |
98 | "invalid type (%u)" , xattr.v->x_type); |
99 | |
100 | bkey_fsck_err_on(memchr(xattr.v->x_name, '\0', xattr.v->x_name_len), c, err, |
101 | xattr_name_invalid_chars, |
102 | "xattr name has invalid characters" ); |
103 | fsck_err: |
104 | return ret; |
105 | } |
106 | |
107 | void bch2_xattr_to_text(struct printbuf *out, struct bch_fs *c, |
108 | struct bkey_s_c k) |
109 | { |
110 | const struct xattr_handler *handler; |
111 | struct bkey_s_c_xattr xattr = bkey_s_c_to_xattr(k); |
112 | |
113 | handler = bch2_xattr_type_to_handler(xattr.v->x_type); |
114 | if (handler && handler->prefix) |
115 | prt_printf(out, "%s" , handler->prefix); |
116 | else if (handler) |
117 | prt_printf(out, "(type %u)" , xattr.v->x_type); |
118 | else |
119 | prt_printf(out, "(unknown type %u)" , xattr.v->x_type); |
120 | |
121 | prt_printf(out, "%.*s:%.*s" , |
122 | xattr.v->x_name_len, |
123 | xattr.v->x_name, |
124 | le16_to_cpu(xattr.v->x_val_len), |
125 | (char *) xattr_val(xattr.v)); |
126 | |
127 | if (xattr.v->x_type == KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS || |
128 | xattr.v->x_type == KEY_TYPE_XATTR_INDEX_POSIX_ACL_DEFAULT) { |
129 | prt_char(out, c: ' '); |
130 | bch2_acl_to_text(out, xattr_val(xattr.v), |
131 | le16_to_cpu(xattr.v->x_val_len)); |
132 | } |
133 | } |
134 | |
135 | static int bch2_xattr_get_trans(struct btree_trans *trans, struct bch_inode_info *inode, |
136 | const char *name, void *buffer, size_t size, int type) |
137 | { |
138 | struct bch_hash_info hash = bch2_hash_info_init(c: trans->c, bi: &inode->ei_inode); |
139 | struct xattr_search_key search = X_SEARCH(type, name, strlen(name)); |
140 | struct btree_iter iter; |
141 | struct bkey_s_c_xattr xattr; |
142 | struct bkey_s_c k; |
143 | int ret; |
144 | |
145 | ret = bch2_hash_lookup(trans, iter: &iter, desc: bch2_xattr_hash_desc, info: &hash, |
146 | inum: inode_inum(inode), key: &search, flags: 0); |
147 | if (ret) |
148 | goto err1; |
149 | |
150 | k = bch2_btree_iter_peek_slot(&iter); |
151 | ret = bkey_err(k); |
152 | if (ret) |
153 | goto err2; |
154 | |
155 | xattr = bkey_s_c_to_xattr(k); |
156 | ret = le16_to_cpu(xattr.v->x_val_len); |
157 | if (buffer) { |
158 | if (ret > size) |
159 | ret = -ERANGE; |
160 | else |
161 | memcpy(buffer, xattr_val(xattr.v), ret); |
162 | } |
163 | err2: |
164 | bch2_trans_iter_exit(trans, &iter); |
165 | err1: |
166 | return ret < 0 && bch2_err_matches(ret, ENOENT) ? -ENODATA : ret; |
167 | } |
168 | |
169 | int bch2_xattr_set(struct btree_trans *trans, subvol_inum inum, |
170 | struct bch_inode_unpacked *inode_u, |
171 | const struct bch_hash_info *hash_info, |
172 | const char *name, const void *value, size_t size, |
173 | int type, int flags) |
174 | { |
175 | struct bch_fs *c = trans->c; |
176 | struct btree_iter inode_iter = { NULL }; |
177 | int ret; |
178 | |
179 | ret = bch2_subvol_is_ro_trans(trans, inum.subvol) ?: |
180 | bch2_inode_peek(trans, &inode_iter, inode_u, inum, BTREE_ITER_INTENT); |
181 | if (ret) |
182 | return ret; |
183 | |
184 | inode_u->bi_ctime = bch2_current_time(c); |
185 | |
186 | ret = bch2_inode_write(trans, iter: &inode_iter, inode: inode_u); |
187 | bch2_trans_iter_exit(trans, &inode_iter); |
188 | |
189 | if (ret) |
190 | return ret; |
191 | |
192 | if (value) { |
193 | struct bkey_i_xattr *xattr; |
194 | unsigned namelen = strlen(name); |
195 | unsigned u64s = BKEY_U64s + |
196 | xattr_val_u64s(name_len: namelen, val_len: size); |
197 | |
198 | if (u64s > U8_MAX) |
199 | return -ERANGE; |
200 | |
201 | xattr = bch2_trans_kmalloc(trans, size: u64s * sizeof(u64)); |
202 | if (IS_ERR(ptr: xattr)) |
203 | return PTR_ERR(ptr: xattr); |
204 | |
205 | bkey_xattr_init(k: &xattr->k_i); |
206 | xattr->k.u64s = u64s; |
207 | xattr->v.x_type = type; |
208 | xattr->v.x_name_len = namelen; |
209 | xattr->v.x_val_len = cpu_to_le16(size); |
210 | memcpy(xattr->v.x_name, name, namelen); |
211 | memcpy(xattr_val(&xattr->v), value, size); |
212 | |
213 | ret = bch2_hash_set(trans, desc: bch2_xattr_hash_desc, info: hash_info, |
214 | inum, insert: &xattr->k_i, |
215 | str_hash_flags: (flags & XATTR_CREATE ? BCH_HASH_SET_MUST_CREATE : 0)| |
216 | (flags & XATTR_REPLACE ? BCH_HASH_SET_MUST_REPLACE : 0)); |
217 | } else { |
218 | struct xattr_search_key search = |
219 | X_SEARCH(type, name, strlen(name)); |
220 | |
221 | ret = bch2_hash_delete(trans, desc: bch2_xattr_hash_desc, |
222 | info: hash_info, inum, key: &search); |
223 | } |
224 | |
225 | if (bch2_err_matches(ret, ENOENT)) |
226 | ret = flags & XATTR_REPLACE ? -ENODATA : 0; |
227 | |
228 | return ret; |
229 | } |
230 | |
231 | struct xattr_buf { |
232 | char *buf; |
233 | size_t len; |
234 | size_t used; |
235 | }; |
236 | |
237 | static int __bch2_xattr_emit(const char *prefix, |
238 | const char *name, size_t name_len, |
239 | struct xattr_buf *buf) |
240 | { |
241 | const size_t prefix_len = strlen(prefix); |
242 | const size_t total_len = prefix_len + name_len + 1; |
243 | |
244 | if (buf->buf) { |
245 | if (buf->used + total_len > buf->len) |
246 | return -ERANGE; |
247 | |
248 | memcpy(buf->buf + buf->used, prefix, prefix_len); |
249 | memcpy(buf->buf + buf->used + prefix_len, |
250 | name, name_len); |
251 | buf->buf[buf->used + prefix_len + name_len] = '\0'; |
252 | } |
253 | |
254 | buf->used += total_len; |
255 | return 0; |
256 | } |
257 | |
258 | static int bch2_xattr_emit(struct dentry *dentry, |
259 | const struct bch_xattr *xattr, |
260 | struct xattr_buf *buf) |
261 | { |
262 | const struct xattr_handler *handler = |
263 | bch2_xattr_type_to_handler(xattr->x_type); |
264 | |
265 | return handler && (!handler->list || handler->list(dentry)) |
266 | ? __bch2_xattr_emit(prefix: handler->prefix ?: handler->name, |
267 | name: xattr->x_name, name_len: xattr->x_name_len, buf) |
268 | : 0; |
269 | } |
270 | |
271 | static int bch2_xattr_list_bcachefs(struct bch_fs *c, |
272 | struct bch_inode_unpacked *inode, |
273 | struct xattr_buf *buf, |
274 | bool all) |
275 | { |
276 | const char *prefix = all ? "bcachefs_effective." : "bcachefs." ; |
277 | unsigned id; |
278 | int ret = 0; |
279 | u64 v; |
280 | |
281 | for (id = 0; id < Inode_opt_nr; id++) { |
282 | v = bch2_inode_opt_get(inode, id); |
283 | if (!v) |
284 | continue; |
285 | |
286 | if (!all && |
287 | !(inode->bi_fields_set & (1 << id))) |
288 | continue; |
289 | |
290 | ret = __bch2_xattr_emit(prefix, name: bch2_inode_opts[id], |
291 | strlen(bch2_inode_opts[id]), buf); |
292 | if (ret) |
293 | break; |
294 | } |
295 | |
296 | return ret; |
297 | } |
298 | |
299 | ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) |
300 | { |
301 | struct bch_fs *c = dentry->d_sb->s_fs_info; |
302 | struct bch_inode_info *inode = to_bch_ei(dentry->d_inode); |
303 | struct btree_trans *trans = bch2_trans_get(c); |
304 | struct btree_iter iter; |
305 | struct bkey_s_c k; |
306 | struct xattr_buf buf = { .buf = buffer, .len = buffer_size }; |
307 | u64 offset = 0, inum = inode->ei_inode.bi_inum; |
308 | u32 snapshot; |
309 | int ret; |
310 | retry: |
311 | bch2_trans_begin(trans); |
312 | iter = (struct btree_iter) { NULL }; |
313 | |
314 | ret = bch2_subvolume_get_snapshot(trans, inode->ei_subvol, &snapshot); |
315 | if (ret) |
316 | goto err; |
317 | |
318 | for_each_btree_key_upto_norestart(trans, iter, BTREE_ID_xattrs, |
319 | SPOS(inum, offset, snapshot), |
320 | POS(inum, U64_MAX), 0, k, ret) { |
321 | if (k.k->type != KEY_TYPE_xattr) |
322 | continue; |
323 | |
324 | ret = bch2_xattr_emit(dentry, xattr: bkey_s_c_to_xattr(k).v, buf: &buf); |
325 | if (ret) |
326 | break; |
327 | } |
328 | |
329 | offset = iter.pos.offset; |
330 | bch2_trans_iter_exit(trans, &iter); |
331 | err: |
332 | if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) |
333 | goto retry; |
334 | |
335 | bch2_trans_put(trans); |
336 | |
337 | if (ret) |
338 | goto out; |
339 | |
340 | ret = bch2_xattr_list_bcachefs(c, inode: &inode->ei_inode, buf: &buf, all: false); |
341 | if (ret) |
342 | goto out; |
343 | |
344 | ret = bch2_xattr_list_bcachefs(c, inode: &inode->ei_inode, buf: &buf, all: true); |
345 | if (ret) |
346 | goto out; |
347 | |
348 | return buf.used; |
349 | out: |
350 | return bch2_err_class(err: ret); |
351 | } |
352 | |
353 | static int bch2_xattr_get_handler(const struct xattr_handler *handler, |
354 | struct dentry *dentry, struct inode *vinode, |
355 | const char *name, void *buffer, size_t size) |
356 | { |
357 | struct bch_inode_info *inode = to_bch_ei(vinode); |
358 | struct bch_fs *c = inode->v.i_sb->s_fs_info; |
359 | int ret = bch2_trans_do(c, NULL, NULL, 0, |
360 | bch2_xattr_get_trans(trans, inode, name, buffer, size, handler->flags)); |
361 | |
362 | return bch2_err_class(err: ret); |
363 | } |
364 | |
365 | static int bch2_xattr_set_handler(const struct xattr_handler *handler, |
366 | struct mnt_idmap *idmap, |
367 | struct dentry *dentry, struct inode *vinode, |
368 | const char *name, const void *value, |
369 | size_t size, int flags) |
370 | { |
371 | struct bch_inode_info *inode = to_bch_ei(vinode); |
372 | struct bch_fs *c = inode->v.i_sb->s_fs_info; |
373 | struct bch_hash_info hash = bch2_hash_info_init(c, bi: &inode->ei_inode); |
374 | struct bch_inode_unpacked inode_u; |
375 | int ret; |
376 | |
377 | ret = bch2_trans_run(c, |
378 | commit_do(trans, NULL, NULL, 0, |
379 | bch2_xattr_set(trans, inode_inum(inode), &inode_u, |
380 | &hash, name, value, size, |
381 | handler->flags, flags)) ?: |
382 | (bch2_inode_update_after_write(trans, inode, &inode_u, ATTR_CTIME), 0)); |
383 | |
384 | return bch2_err_class(err: ret); |
385 | } |
386 | |
387 | static const struct xattr_handler bch_xattr_user_handler = { |
388 | .prefix = XATTR_USER_PREFIX, |
389 | .get = bch2_xattr_get_handler, |
390 | .set = bch2_xattr_set_handler, |
391 | .flags = KEY_TYPE_XATTR_INDEX_USER, |
392 | }; |
393 | |
394 | static bool bch2_xattr_trusted_list(struct dentry *dentry) |
395 | { |
396 | return capable(CAP_SYS_ADMIN); |
397 | } |
398 | |
399 | static const struct xattr_handler bch_xattr_trusted_handler = { |
400 | .prefix = XATTR_TRUSTED_PREFIX, |
401 | .list = bch2_xattr_trusted_list, |
402 | .get = bch2_xattr_get_handler, |
403 | .set = bch2_xattr_set_handler, |
404 | .flags = KEY_TYPE_XATTR_INDEX_TRUSTED, |
405 | }; |
406 | |
407 | static const struct xattr_handler bch_xattr_security_handler = { |
408 | .prefix = XATTR_SECURITY_PREFIX, |
409 | .get = bch2_xattr_get_handler, |
410 | .set = bch2_xattr_set_handler, |
411 | .flags = KEY_TYPE_XATTR_INDEX_SECURITY, |
412 | }; |
413 | |
414 | #ifndef NO_BCACHEFS_FS |
415 | |
416 | static int opt_to_inode_opt(int id) |
417 | { |
418 | switch (id) { |
419 | #define x(name, ...) \ |
420 | case Opt_##name: return Inode_opt_##name; |
421 | BCH_INODE_OPTS() |
422 | #undef x |
423 | default: |
424 | return -1; |
425 | } |
426 | } |
427 | |
428 | static int __bch2_xattr_bcachefs_get(const struct xattr_handler *handler, |
429 | struct dentry *dentry, struct inode *vinode, |
430 | const char *name, void *buffer, size_t size, |
431 | bool all) |
432 | { |
433 | struct bch_inode_info *inode = to_bch_ei(vinode); |
434 | struct bch_fs *c = inode->v.i_sb->s_fs_info; |
435 | struct bch_opts opts = |
436 | bch2_inode_opts_to_opts(&inode->ei_inode); |
437 | const struct bch_option *opt; |
438 | int id, inode_opt_id; |
439 | struct printbuf out = PRINTBUF; |
440 | int ret; |
441 | u64 v; |
442 | |
443 | id = bch2_opt_lookup(name); |
444 | if (id < 0 || !bch2_opt_is_inode_opt(id)) |
445 | return -EINVAL; |
446 | |
447 | inode_opt_id = opt_to_inode_opt(id); |
448 | if (inode_opt_id < 0) |
449 | return -EINVAL; |
450 | |
451 | opt = bch2_opt_table + id; |
452 | |
453 | if (!bch2_opt_defined_by_id(&opts, id)) |
454 | return -ENODATA; |
455 | |
456 | if (!all && |
457 | !(inode->ei_inode.bi_fields_set & (1 << inode_opt_id))) |
458 | return -ENODATA; |
459 | |
460 | v = bch2_opt_get_by_id(&opts, id); |
461 | bch2_opt_to_text(&out, c, c->disk_sb.sb, opt, v, 0); |
462 | |
463 | ret = out.pos; |
464 | |
465 | if (out.allocation_failure) { |
466 | ret = -ENOMEM; |
467 | } else if (buffer) { |
468 | if (out.pos > size) |
469 | ret = -ERANGE; |
470 | else |
471 | memcpy(buffer, out.buf, out.pos); |
472 | } |
473 | |
474 | printbuf_exit(&out); |
475 | return ret; |
476 | } |
477 | |
478 | static int bch2_xattr_bcachefs_get(const struct xattr_handler *handler, |
479 | struct dentry *dentry, struct inode *vinode, |
480 | const char *name, void *buffer, size_t size) |
481 | { |
482 | return __bch2_xattr_bcachefs_get(handler, dentry, vinode, |
483 | name, buffer, size, all: false); |
484 | } |
485 | |
486 | struct inode_opt_set { |
487 | int id; |
488 | u64 v; |
489 | bool defined; |
490 | }; |
491 | |
492 | static int inode_opt_set_fn(struct btree_trans *trans, |
493 | struct bch_inode_info *inode, |
494 | struct bch_inode_unpacked *bi, |
495 | void *p) |
496 | { |
497 | struct inode_opt_set *s = p; |
498 | |
499 | if (s->defined) |
500 | bi->bi_fields_set |= 1U << s->id; |
501 | else |
502 | bi->bi_fields_set &= ~(1U << s->id); |
503 | |
504 | bch2_inode_opt_set(inode: bi, id: s->id, v: s->v); |
505 | |
506 | return 0; |
507 | } |
508 | |
509 | static int bch2_xattr_bcachefs_set(const struct xattr_handler *handler, |
510 | struct mnt_idmap *idmap, |
511 | struct dentry *dentry, struct inode *vinode, |
512 | const char *name, const void *value, |
513 | size_t size, int flags) |
514 | { |
515 | struct bch_inode_info *inode = to_bch_ei(vinode); |
516 | struct bch_fs *c = inode->v.i_sb->s_fs_info; |
517 | const struct bch_option *opt; |
518 | char *buf; |
519 | struct inode_opt_set s; |
520 | int opt_id, inode_opt_id, ret; |
521 | |
522 | opt_id = bch2_opt_lookup(name); |
523 | if (opt_id < 0) |
524 | return -EINVAL; |
525 | |
526 | opt = bch2_opt_table + opt_id; |
527 | |
528 | inode_opt_id = opt_to_inode_opt(id: opt_id); |
529 | if (inode_opt_id < 0) |
530 | return -EINVAL; |
531 | |
532 | s.id = inode_opt_id; |
533 | |
534 | if (value) { |
535 | u64 v = 0; |
536 | |
537 | buf = kmalloc(size: size + 1, GFP_KERNEL); |
538 | if (!buf) |
539 | return -ENOMEM; |
540 | memcpy(buf, value, size); |
541 | buf[size] = '\0'; |
542 | |
543 | ret = bch2_opt_parse(c, opt, buf, &v, NULL); |
544 | kfree(objp: buf); |
545 | |
546 | if (ret < 0) |
547 | goto err_class_exit; |
548 | |
549 | ret = bch2_opt_check_may_set(c, opt_id, v); |
550 | if (ret < 0) |
551 | goto err_class_exit; |
552 | |
553 | s.v = v + 1; |
554 | s.defined = true; |
555 | } else { |
556 | /* |
557 | * Check if this option was set on the parent - if so, switched |
558 | * back to inheriting from the parent: |
559 | * |
560 | * rename() also has to deal with keeping inherited options up |
561 | * to date - see bch2_reinherit_attrs() |
562 | */ |
563 | spin_lock(lock: &dentry->d_lock); |
564 | if (!IS_ROOT(dentry)) { |
565 | struct bch_inode_info *dir = |
566 | to_bch_ei(d_inode(dentry->d_parent)); |
567 | |
568 | s.v = bch2_inode_opt_get(inode: &dir->ei_inode, id: inode_opt_id); |
569 | } else { |
570 | s.v = 0; |
571 | } |
572 | spin_unlock(lock: &dentry->d_lock); |
573 | |
574 | s.defined = false; |
575 | } |
576 | |
577 | mutex_lock(&inode->ei_update_lock); |
578 | if (inode_opt_id == Inode_opt_project) { |
579 | /* |
580 | * inode fields accessible via the xattr interface are stored |
581 | * with a +1 bias, so that 0 means unset: |
582 | */ |
583 | ret = bch2_set_projid(c, inode, projid: s.v ? s.v - 1 : 0); |
584 | if (ret) |
585 | goto err; |
586 | } |
587 | |
588 | ret = bch2_write_inode(c, inode, inode_opt_set_fn, &s, 0); |
589 | err: |
590 | mutex_unlock(lock: &inode->ei_update_lock); |
591 | |
592 | if (value && |
593 | (opt_id == Opt_background_target || |
594 | opt_id == Opt_background_compression || |
595 | (opt_id == Opt_compression && !inode_opt_get(c, &inode->ei_inode, background_compression)))) |
596 | bch2_set_rebalance_needs_scan(c, inum: inode->ei_inode.bi_inum); |
597 | |
598 | err_class_exit: |
599 | return bch2_err_class(err: ret); |
600 | } |
601 | |
602 | static const struct xattr_handler bch_xattr_bcachefs_handler = { |
603 | .prefix = "bcachefs." , |
604 | .get = bch2_xattr_bcachefs_get, |
605 | .set = bch2_xattr_bcachefs_set, |
606 | }; |
607 | |
608 | static int bch2_xattr_bcachefs_get_effective( |
609 | const struct xattr_handler *handler, |
610 | struct dentry *dentry, struct inode *vinode, |
611 | const char *name, void *buffer, size_t size) |
612 | { |
613 | return __bch2_xattr_bcachefs_get(handler, dentry, vinode, |
614 | name, buffer, size, all: true); |
615 | } |
616 | |
617 | static const struct xattr_handler bch_xattr_bcachefs_effective_handler = { |
618 | .prefix = "bcachefs_effective." , |
619 | .get = bch2_xattr_bcachefs_get_effective, |
620 | .set = bch2_xattr_bcachefs_set, |
621 | }; |
622 | |
623 | #endif /* NO_BCACHEFS_FS */ |
624 | |
625 | const struct xattr_handler *bch2_xattr_handlers[] = { |
626 | &bch_xattr_user_handler, |
627 | #ifdef CONFIG_BCACHEFS_POSIX_ACL |
628 | &nop_posix_acl_access, |
629 | &nop_posix_acl_default, |
630 | #endif |
631 | &bch_xattr_trusted_handler, |
632 | &bch_xattr_security_handler, |
633 | #ifndef NO_BCACHEFS_FS |
634 | &bch_xattr_bcachefs_handler, |
635 | &bch_xattr_bcachefs_effective_handler, |
636 | #endif |
637 | NULL |
638 | }; |
639 | |
640 | static const struct xattr_handler *bch_xattr_handler_map[] = { |
641 | [KEY_TYPE_XATTR_INDEX_USER] = &bch_xattr_user_handler, |
642 | [KEY_TYPE_XATTR_INDEX_POSIX_ACL_ACCESS] = |
643 | &nop_posix_acl_access, |
644 | [KEY_TYPE_XATTR_INDEX_POSIX_ACL_DEFAULT] = |
645 | &nop_posix_acl_default, |
646 | [KEY_TYPE_XATTR_INDEX_TRUSTED] = &bch_xattr_trusted_handler, |
647 | [KEY_TYPE_XATTR_INDEX_SECURITY] = &bch_xattr_security_handler, |
648 | }; |
649 | |
650 | static const struct xattr_handler *bch2_xattr_type_to_handler(unsigned type) |
651 | { |
652 | return type < ARRAY_SIZE(bch_xattr_handler_map) |
653 | ? bch_xattr_handler_map[type] |
654 | : NULL; |
655 | } |
656 | |