]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/xattr.c
bcachefs-in-userspace improvements
[bcachefs-tools-debian] / libbcachefs / xattr.c
1
2 #include "bcachefs.h"
3 #include "bkey_methods.h"
4 #include "btree_update.h"
5 #include "extents.h"
6 #include "fs.h"
7 #include "str_hash.h"
8 #include "xattr.h"
9
10 #include <linux/dcache.h>
11 #include <linux/posix_acl_xattr.h>
12 #include <linux/xattr.h>
13
14 struct xattr_search_key {
15         u8              type;
16         struct qstr     name;
17 };
18
19 #define X_SEARCH(_type, _name, _len) ((struct xattr_search_key) \
20         { .type = _type, .name = QSTR_INIT(_name, _len) })
21
22 static u64 bch2_xattr_hash(const struct bch_hash_info *info,
23                           const struct xattr_search_key *key)
24 {
25         struct bch_str_hash_ctx ctx;
26
27         bch2_str_hash_init(&ctx, info);
28         bch2_str_hash_update(&ctx, info, &key->type, sizeof(key->type));
29         bch2_str_hash_update(&ctx, info, key->name.name, key->name.len);
30
31         return bch2_str_hash_end(&ctx, info);
32 }
33
34 #define xattr_val(_xattr)       ((_xattr)->x_name + (_xattr)->x_name_len)
35
36 static u64 xattr_hash_key(const struct bch_hash_info *info, const void *key)
37 {
38         return bch2_xattr_hash(info, key);
39 }
40
41 static u64 xattr_hash_bkey(const struct bch_hash_info *info, struct bkey_s_c k)
42 {
43         struct bkey_s_c_xattr x = bkey_s_c_to_xattr(k);
44
45         return bch2_xattr_hash(info,
46                  &X_SEARCH(x.v->x_type, x.v->x_name, x.v->x_name_len));
47 }
48
49 static bool xattr_cmp_key(struct bkey_s_c _l, const void *_r)
50 {
51         struct bkey_s_c_xattr l = bkey_s_c_to_xattr(_l);
52         const struct xattr_search_key *r = _r;
53
54         return l.v->x_type != r->type ||
55                 l.v->x_name_len != r->name.len ||
56                 memcmp(l.v->x_name, r->name.name, r->name.len);
57 }
58
59 static bool xattr_cmp_bkey(struct bkey_s_c _l, struct bkey_s_c _r)
60 {
61         struct bkey_s_c_xattr l = bkey_s_c_to_xattr(_l);
62         struct bkey_s_c_xattr r = bkey_s_c_to_xattr(_r);
63
64         return l.v->x_type != r.v->x_type ||
65                 l.v->x_name_len != r.v->x_name_len ||
66                 memcmp(l.v->x_name, r.v->x_name, r.v->x_name_len);
67 }
68
69 static const struct bch_hash_desc xattr_hash_desc = {
70         .btree_id       = BTREE_ID_XATTRS,
71         .key_type       = BCH_XATTR,
72         .whiteout_type  = BCH_XATTR_WHITEOUT,
73         .hash_key       = xattr_hash_key,
74         .hash_bkey      = xattr_hash_bkey,
75         .cmp_key        = xattr_cmp_key,
76         .cmp_bkey       = xattr_cmp_bkey,
77 };
78
79 static const char *bch2_xattr_invalid(const struct bch_fs *c,
80                                      struct bkey_s_c k)
81 {
82         switch (k.k->type) {
83         case BCH_XATTR:
84                 return bkey_val_bytes(k.k) < sizeof(struct bch_xattr)
85                         ? "value too small"
86                         : NULL;
87
88         case BCH_XATTR_WHITEOUT:
89                 return bkey_val_bytes(k.k) != 0
90                         ? "value size should be zero"
91                         : NULL;
92
93         default:
94                 return "invalid type";
95         }
96 }
97
98 static void bch2_xattr_to_text(struct bch_fs *c, char *buf,
99                               size_t size, struct bkey_s_c k)
100 {
101         struct bkey_s_c_xattr xattr;
102         int n;
103
104         switch (k.k->type) {
105         case BCH_XATTR:
106                 xattr = bkey_s_c_to_xattr(k);
107
108                 if (size) {
109                         n = min_t(unsigned, size, xattr.v->x_name_len);
110                         memcpy(buf, xattr.v->x_name, n);
111                         buf[size - 1] = '\0';
112                         buf += n;
113                         size -= n;
114                 }
115
116                 n = scnprintf(buf, size, " -> ");
117                 buf += n;
118                 size -= n;
119
120                 if (size) {
121                         n = min_t(unsigned, size,
122                                   le16_to_cpu(xattr.v->x_val_len));
123                         memcpy(buf, xattr_val(xattr.v), n);
124                         buf[size - 1] = '\0';
125                         buf += n;
126                         size -= n;
127                 }
128
129                 break;
130         case BCH_XATTR_WHITEOUT:
131                 scnprintf(buf, size, "whiteout");
132                 break;
133         }
134 }
135
136 const struct bkey_ops bch2_bkey_xattr_ops = {
137         .key_invalid    = bch2_xattr_invalid,
138         .val_to_text    = bch2_xattr_to_text,
139 };
140
141 int bch2_xattr_get(struct bch_fs *c, struct inode *inode,
142                   const char *name, void *buffer, size_t size, int type)
143 {
144         struct bch_inode_info *ei = to_bch_ei(inode);
145         struct btree_iter iter;
146         struct bkey_s_c k;
147         struct bkey_s_c_xattr xattr;
148         int ret;
149
150         k = bch2_hash_lookup(xattr_hash_desc, &ei->str_hash, c,
151                             ei->vfs_inode.i_ino, &iter,
152                             &X_SEARCH(type, name, strlen(name)));
153         if (IS_ERR(k.k))
154                 return bch2_btree_iter_unlock(&iter) ?: -ENODATA;
155
156         xattr = bkey_s_c_to_xattr(k);
157         ret = le16_to_cpu(xattr.v->x_val_len);
158         if (buffer) {
159                 if (ret > size)
160                         ret = -ERANGE;
161                 else
162                         memcpy(buffer, xattr_val(xattr.v), ret);
163         }
164
165         bch2_btree_iter_unlock(&iter);
166         return ret;
167 }
168
169 int __bch2_xattr_set(struct bch_fs *c, u64 inum,
170                     const struct bch_hash_info *hash_info,
171                     const char *name, const void *value, size_t size,
172                     int flags, int type, u64 *journal_seq)
173 {
174         struct xattr_search_key search = X_SEARCH(type, name, strlen(name));
175         int ret;
176
177         if (!value) {
178                 ret = bch2_hash_delete(xattr_hash_desc, hash_info,
179                                       c, inum,
180                                       journal_seq, &search);
181         } else {
182                 struct bkey_i_xattr *xattr;
183                 unsigned u64s = BKEY_U64s +
184                         DIV_ROUND_UP(sizeof(struct bch_xattr) +
185                                      search.name.len + size,
186                                      sizeof(u64));
187
188                 if (u64s > U8_MAX)
189                         return -ERANGE;
190
191                 xattr = kmalloc(u64s * sizeof(u64), GFP_NOFS);
192                 if (!xattr)
193                         return -ENOMEM;
194
195                 bkey_xattr_init(&xattr->k_i);
196                 xattr->k.u64s           = u64s;
197                 xattr->v.x_type         = type;
198                 xattr->v.x_name_len     = search.name.len;
199                 xattr->v.x_val_len      = cpu_to_le16(size);
200                 memcpy(xattr->v.x_name, search.name.name, search.name.len);
201                 memcpy(xattr_val(&xattr->v), value, size);
202
203                 ret = bch2_hash_set(xattr_hash_desc, hash_info, c,
204                                 inum, journal_seq,
205                                 &xattr->k_i,
206                                 (flags & XATTR_CREATE ? BCH_HASH_SET_MUST_CREATE : 0)|
207                                 (flags & XATTR_REPLACE ? BCH_HASH_SET_MUST_REPLACE : 0));
208                 kfree(xattr);
209         }
210
211         if (ret == -ENOENT)
212                 ret = flags & XATTR_REPLACE ? -ENODATA : 0;
213
214         return ret;
215 }
216
217 int bch2_xattr_set(struct bch_fs *c, struct inode *inode,
218                   const char *name, const void *value, size_t size,
219                   int flags, int type)
220 {
221         struct bch_inode_info *ei = to_bch_ei(inode);
222
223         return __bch2_xattr_set(c, inode->i_ino, &ei->str_hash,
224                                name, value, size, flags, type,
225                                &ei->journal_seq);
226 }
227
228 static const struct xattr_handler *bch2_xattr_type_to_handler(unsigned);
229
230 static size_t bch2_xattr_emit(struct dentry *dentry,
231                              const struct bch_xattr *xattr,
232                              char *buffer, size_t buffer_size)
233 {
234         const struct xattr_handler *handler =
235                 bch2_xattr_type_to_handler(xattr->x_type);
236
237         if (handler && (!handler->list || handler->list(dentry))) {
238                 const char *prefix = handler->prefix ?: handler->name;
239                 const size_t prefix_len = strlen(prefix);
240                 const size_t total_len = prefix_len + xattr->x_name_len + 1;
241
242                 if (buffer && total_len <= buffer_size) {
243                         memcpy(buffer, prefix, prefix_len);
244                         memcpy(buffer + prefix_len,
245                                xattr->x_name, xattr->x_name_len);
246                         buffer[prefix_len + xattr->x_name_len] = '\0';
247                 }
248
249                 return total_len;
250         } else {
251                 return 0;
252         }
253 }
254
255 ssize_t bch2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size)
256 {
257         struct bch_fs *c = dentry->d_sb->s_fs_info;
258         struct btree_iter iter;
259         struct bkey_s_c k;
260         const struct bch_xattr *xattr;
261         u64 inum = dentry->d_inode->i_ino;
262         ssize_t ret = 0;
263         size_t len;
264
265         for_each_btree_key(&iter, c, BTREE_ID_XATTRS, POS(inum, 0), k) {
266                 BUG_ON(k.k->p.inode < inum);
267
268                 if (k.k->p.inode > inum)
269                         break;
270
271                 if (k.k->type != BCH_XATTR)
272                         continue;
273
274                 xattr = bkey_s_c_to_xattr(k).v;
275
276                 len = bch2_xattr_emit(dentry, xattr, buffer, buffer_size);
277                 if (buffer) {
278                         if (len > buffer_size) {
279                                 bch2_btree_iter_unlock(&iter);
280                                 return -ERANGE;
281                         }
282
283                         buffer += len;
284                         buffer_size -= len;
285                 }
286
287                 ret += len;
288
289         }
290         bch2_btree_iter_unlock(&iter);
291
292         return ret;
293 }
294
295 static int bch2_xattr_get_handler(const struct xattr_handler *handler,
296                                  struct dentry *dentry, struct inode *inode,
297                                  const char *name, void *buffer, size_t size)
298 {
299         struct bch_fs *c = inode->i_sb->s_fs_info;
300
301         return bch2_xattr_get(c, inode, name, buffer, size, handler->flags);
302 }
303
304 static int bch2_xattr_set_handler(const struct xattr_handler *handler,
305                                  struct dentry *dentry, struct inode *inode,
306                                  const char *name, const void *value,
307                                  size_t size, int flags)
308 {
309         struct bch_fs *c = inode->i_sb->s_fs_info;
310
311         return bch2_xattr_set(c, inode, name, value, size, flags,
312                              handler->flags);
313 }
314
315 static const struct xattr_handler bch_xattr_user_handler = {
316         .prefix = XATTR_USER_PREFIX,
317         .get    = bch2_xattr_get_handler,
318         .set    = bch2_xattr_set_handler,
319         .flags  = BCH_XATTR_INDEX_USER,
320 };
321
322 static bool bch2_xattr_trusted_list(struct dentry *dentry)
323 {
324         return capable(CAP_SYS_ADMIN);
325 }
326
327 static const struct xattr_handler bch_xattr_trusted_handler = {
328         .prefix = XATTR_TRUSTED_PREFIX,
329         .list   = bch2_xattr_trusted_list,
330         .get    = bch2_xattr_get_handler,
331         .set    = bch2_xattr_set_handler,
332         .flags  = BCH_XATTR_INDEX_TRUSTED,
333 };
334
335 static const struct xattr_handler bch_xattr_security_handler = {
336         .prefix = XATTR_SECURITY_PREFIX,
337         .get    = bch2_xattr_get_handler,
338         .set    = bch2_xattr_set_handler,
339         .flags  = BCH_XATTR_INDEX_SECURITY,
340 };
341
342 static const struct xattr_handler *bch_xattr_handler_map[] = {
343         [BCH_XATTR_INDEX_USER]                  = &bch_xattr_user_handler,
344         [BCH_XATTR_INDEX_POSIX_ACL_ACCESS]      =
345                 &posix_acl_access_xattr_handler,
346         [BCH_XATTR_INDEX_POSIX_ACL_DEFAULT]     =
347                 &posix_acl_default_xattr_handler,
348         [BCH_XATTR_INDEX_TRUSTED]               = &bch_xattr_trusted_handler,
349         [BCH_XATTR_INDEX_SECURITY]              = &bch_xattr_security_handler,
350 };
351
352 const struct xattr_handler *bch2_xattr_handlers[] = {
353         &bch_xattr_user_handler,
354         &posix_acl_access_xattr_handler,
355         &posix_acl_default_xattr_handler,
356         &bch_xattr_trusted_handler,
357         &bch_xattr_security_handler,
358         NULL
359 };
360
361 static const struct xattr_handler *bch2_xattr_type_to_handler(unsigned type)
362 {
363         return type < ARRAY_SIZE(bch_xattr_handler_map)
364                 ? bch_xattr_handler_map[type]
365                 : NULL;
366 }