]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/bkey_methods.c
Faster crc32c
[bcachefs-tools-debian] / libbcachefs / bkey_methods.c
1
2 #include "bcachefs.h"
3 #include "bkey_methods.h"
4 #include "btree_types.h"
5 #include "alloc.h"
6 #include "dirent.h"
7 #include "error.h"
8 #include "extents.h"
9 #include "inode.h"
10 #include "xattr.h"
11
12 const struct bkey_ops *bch2_bkey_ops[] = {
13         [BKEY_TYPE_EXTENTS]     = &bch2_bkey_extent_ops,
14         [BKEY_TYPE_INODES]      = &bch2_bkey_inode_ops,
15         [BKEY_TYPE_DIRENTS]     = &bch2_bkey_dirent_ops,
16         [BKEY_TYPE_XATTRS]      = &bch2_bkey_xattr_ops,
17         [BKEY_TYPE_ALLOC]       = &bch2_bkey_alloc_ops,
18         [BKEY_TYPE_BTREE]       = &bch2_bkey_btree_ops,
19 };
20
21 /* Returns string indicating reason for being invalid, or NULL if valid: */
22 const char *bch2_bkey_invalid(struct bch_fs *c, enum bkey_type type,
23                          struct bkey_s_c k)
24 {
25         const struct bkey_ops *ops = bch2_bkey_ops[type];
26
27         if (k.k->u64s < BKEY_U64s)
28                 return "u64s too small";
29
30         if (!ops->is_extents) {
31                 if (k.k->size)
32                         return "nonzero size field";
33         } else {
34                 if ((k.k->size == 0) != bkey_deleted(k.k))
35                         return "bad size field";
36         }
37
38         if (ops->is_extents &&
39             !k.k->size &&
40             !bkey_deleted(k.k))
41                 return "zero size field";
42
43         switch (k.k->type) {
44         case KEY_TYPE_DELETED:
45         case KEY_TYPE_DISCARD:
46                 return NULL;
47
48         case KEY_TYPE_ERROR:
49                 return bkey_val_bytes(k.k) != 0
50                         ? "value size should be zero"
51                         : NULL;
52
53         case KEY_TYPE_COOKIE:
54                 return bkey_val_bytes(k.k) != sizeof(struct bch_cookie)
55                         ? "incorrect value size"
56                         : NULL;
57
58         default:
59                 if (k.k->type < KEY_TYPE_GENERIC_NR)
60                         return "invalid type";
61
62                 return ops->key_invalid(c, k);
63         }
64 }
65
66 const char *bch2_btree_bkey_invalid(struct bch_fs *c, struct btree *b,
67                                     struct bkey_s_c k)
68 {
69         if (bkey_cmp(bkey_start_pos(k.k), b->data->min_key) < 0)
70                 return "key before start of btree node";
71
72         if (bkey_cmp(k.k->p, b->data->max_key) > 0)
73                 return "key past end of btree node";
74
75         if (k.k->p.snapshot)
76                 return "nonzero snapshot";
77
78         return bch2_bkey_invalid(c, btree_node_type(b), k);
79 }
80
81 void bch2_bkey_debugcheck(struct bch_fs *c, struct btree *b, struct bkey_s_c k)
82 {
83         enum bkey_type type = btree_node_type(b);
84         const struct bkey_ops *ops = bch2_bkey_ops[type];
85         const char *invalid;
86
87         BUG_ON(!k.k->u64s);
88
89         invalid = bch2_btree_bkey_invalid(c, b, k);
90         if (invalid) {
91                 char buf[160];
92
93                 bch2_bkey_val_to_text(c, type, buf, sizeof(buf), k);
94                 bch2_fs_bug(c, "invalid bkey %s: %s", buf, invalid);
95                 return;
96         }
97
98         if (k.k->type >= KEY_TYPE_GENERIC_NR &&
99             ops->key_debugcheck)
100                 ops->key_debugcheck(c, b, k);
101 }
102
103 char *bch2_val_to_text(struct bch_fs *c, enum bkey_type type,
104                        char *buf, size_t size, struct bkey_s_c k)
105 {
106         const struct bkey_ops *ops = bch2_bkey_ops[type];
107
108         if (k.k->type >= KEY_TYPE_GENERIC_NR &&
109             ops->val_to_text)
110                 ops->val_to_text(c, buf, size, k);
111
112         return buf;
113 }
114
115 char *bch2_bkey_val_to_text(struct bch_fs *c, enum bkey_type type,
116                             char *buf, size_t size, struct bkey_s_c k)
117 {
118         const struct bkey_ops *ops = bch2_bkey_ops[type];
119         char *out = buf, *end = buf + size;
120
121         out += bch2_bkey_to_text(out, end - out, k.k);
122
123         if (k.k->type >= KEY_TYPE_GENERIC_NR &&
124             ops->val_to_text) {
125                 out += scnprintf(out, end - out, ": ");
126                 ops->val_to_text(c, out, end - out, k);
127         }
128
129         return buf;
130 }
131
132 void bch2_bkey_swab(enum bkey_type type,
133                    const struct bkey_format *f,
134                    struct bkey_packed *k)
135 {
136         const struct bkey_ops *ops = bch2_bkey_ops[type];
137
138         bch2_bkey_swab_key(f, k);
139
140         if (ops->swab)
141                 ops->swab(f, k);
142 }