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