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