]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcache/bkey_methods.c
bcache in userspace; userspace fsck
[bcachefs-tools-debian] / libbcache / bkey_methods.c
1
2 #include "bcache.h"
3 #include "bkey_methods.h"
4 #include "btree_types.h"
5 #include "dirent.h"
6 #include "error.h"
7 #include "extents.h"
8 #include "inode.h"
9 #include "xattr.h"
10
11 const struct bkey_ops *bch_bkey_ops[] = {
12         [BKEY_TYPE_EXTENTS]     = &bch_bkey_extent_ops,
13         [BKEY_TYPE_INODES]      = &bch_bkey_inode_ops,
14         [BKEY_TYPE_DIRENTS]     = &bch_bkey_dirent_ops,
15         [BKEY_TYPE_XATTRS]      = &bch_bkey_xattr_ops,
16         [BKEY_TYPE_BTREE]       = &bch_bkey_btree_ops,
17 };
18
19 /* Returns string indicating reason for being invalid, or NULL if valid: */
20 const char *bkey_invalid(struct cache_set *c, enum bkey_type type,
21                          struct bkey_s_c k)
22 {
23         const struct bkey_ops *ops = bch_bkey_ops[type];
24
25         if (k.k->u64s < BKEY_U64s)
26                 return "u64s too small";
27
28         if (k.k->size &&
29             (bkey_deleted(k.k) || !ops->is_extents))
30                 return "nonzero size field";
31
32         switch (k.k->type) {
33         case KEY_TYPE_DELETED:
34         case KEY_TYPE_DISCARD:
35                 return NULL;
36
37         case KEY_TYPE_ERROR:
38                 return bkey_val_bytes(k.k) != 0
39                         ? "value size should be zero"
40                         : NULL;
41
42         case KEY_TYPE_COOKIE:
43                 return bkey_val_bytes(k.k) != sizeof(struct bch_cookie)
44                         ? "incorrect value size"
45                         : NULL;
46
47         default:
48                 if (k.k->type < KEY_TYPE_GENERIC_NR)
49                         return "invalid type";
50
51                 return ops->key_invalid(c, k);
52         }
53 }
54
55 const char *btree_bkey_invalid(struct cache_set *c, struct btree *b,
56                                struct bkey_s_c k)
57 {
58         if (bkey_cmp(bkey_start_pos(k.k), b->data->min_key) < 0)
59                 return "key before start of btree node";
60
61         if (bkey_cmp(k.k->p, b->data->max_key) > 0)
62                 return "key past end of btree node";
63
64         if (k.k->p.snapshot)
65                 return "nonzero snapshot";
66
67         return bkey_invalid(c, btree_node_type(b), k);
68 }
69
70 void bkey_debugcheck(struct cache_set *c, struct btree *b, struct bkey_s_c k)
71 {
72         enum bkey_type type = btree_node_type(b);
73         const struct bkey_ops *ops = bch_bkey_ops[type];
74         const char *invalid;
75
76         BUG_ON(!k.k->u64s);
77
78         invalid = btree_bkey_invalid(c, b, k);
79         if (invalid) {
80                 char buf[160];
81
82                 bch_bkey_val_to_text(c, type, buf, sizeof(buf), k);
83                 cache_set_bug(c, "invalid bkey %s: %s", buf, invalid);
84                 return;
85         }
86
87         if (k.k->type >= KEY_TYPE_GENERIC_NR &&
88             ops->key_debugcheck)
89                 ops->key_debugcheck(c, b, k);
90 }
91
92 void bch_bkey_val_to_text(struct cache_set *c, enum bkey_type type,
93                           char *buf, size_t size, struct bkey_s_c k)
94 {
95         const struct bkey_ops *ops = bch_bkey_ops[type];
96         char *out = buf, *end = buf + size;
97
98         out += bch_bkey_to_text(out, end - out, k.k);
99
100         if (k.k->type >= KEY_TYPE_GENERIC_NR &&
101             ops->val_to_text) {
102                 out += scnprintf(out, end - out, " -> ");
103                 ops->val_to_text(c, out, end - out, k);
104         }
105 }
106
107 void bch_bkey_swab(enum bkey_type type,
108                    const struct bkey_format *f,
109                    struct bkey_packed *k)
110 {
111         const struct bkey_ops *ops = bch_bkey_ops[type];
112
113         bch_bkey_swab_key(f, k);
114
115         if (ops->swab)
116                 ops->swab(f, k);
117 }