summaryrefslogtreecommitdiff
path: root/drivers/md/bcache/bkey_methods.c
blob: 44da385c9b0963564b6e4148e35ca49a4bbdf565 (plain)
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

#include "bcache.h"
#include "bkey_methods.h"
#include "btree.h"
#include "dirent.h"
#include "extents.h"
#include "inode.h"
#include "xattr.h"

static 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,
};

bool 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 true;

	if (k.k->size &&
	    (bkey_deleted(k.k) || !ops->is_extents))
		return true;

	switch (k.k->type) {
	case KEY_TYPE_DELETED:
		return false;

	case KEY_TYPE_DISCARD:
	case KEY_TYPE_ERROR:
		return bkey_val_bytes(k.k) != 0;

	case KEY_TYPE_COOKIE:
		return (bkey_val_bytes(k.k) != sizeof(struct bch_cookie));

	default:
		if (k.k->type < KEY_TYPE_GENERIC_NR)
			return true;

		return ops->key_invalid(c, k);
	}
}

void bkey_debugcheck(struct btree *b, struct bkey_s_c k)
{
	enum bkey_type type = b->level ? BKEY_TYPE_BTREE : b->btree_id;
	const struct bkey_ops *ops = bch_bkey_ops[type];

	BUG_ON(!k.k->u64s);

	cache_set_bug_on(bkey_cmp(bkey_start_pos(k.k),
				  b->data->min_key) < 0,
			 b->c, "key before start of btree node");

	cache_set_bug_on(bkey_cmp(k.k->p,
				  b->data->max_key) > 0,
			 b->c, "key past end of btree node");

	if (bkey_invalid(b->c, type, k)) {
		char buf[160];

		bch_bkey_val_to_text(b, buf, sizeof(buf), k);
		cache_set_bug(b->c, "invalid bkey %s", buf);
		return;
	}

	if (k.k->type >= KEY_TYPE_GENERIC_NR &&
	    ops->key_debugcheck)
		ops->key_debugcheck(b, k);
}

void bch_bkey_val_to_text(struct btree *b, char *buf,
			  size_t size, struct bkey_s_c k)
{
	enum bkey_type type = b->level ? BKEY_TYPE_BTREE : b->btree_id;
	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(b, out, end - out, k);
	}
}