aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorKent Overstreet <kmo@daterainc.com>2013-07-24 21:14:44 -0400
committerKent Overstreet <kmo@daterainc.com>2013-11-11 00:56:33 -0500
commite58ff155034791ed3a5563d24a50fae0a8c1617c (patch)
treedf8019038a66203db7af65fc045d41561a228255 /drivers/md
parent81ab4190ac17df41686a37c97f701623276b652a (diff)
bcache: Fix bch_ptr_bad()
Previously, bch_ptr_bad() could return false when there was a pointer to a nonexistant device... it only filtered out keys with PTR_CHECK_DEV pointers. This behaviour was intended for multiple cache device support; for that, just because the device for one of the pointers has gone away doesn't mean we want to filter out the rest of the pointers. But we don't yet explicitly filter/check individual pointers, so without that this behaviour was wrong - a corrupt bkey with a bad device pointer could cause us to deref a bad pointer. Doh. Signed-off-by: Kent Overstreet <kmo@daterainc.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/bcache/bset.c67
1 files changed, 33 insertions, 34 deletions
diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c
index 7b8713c66050..f32216c75948 100644
--- a/drivers/md/bcache/bset.c
+++ b/drivers/md/bcache/bset.c
@@ -116,47 +116,46 @@ bool bch_ptr_bad(struct btree *b, const struct bkey *k)
116 bch_ptr_invalid(b, k)) 116 bch_ptr_invalid(b, k))
117 return true; 117 return true;
118 118
119 if (KEY_PTRS(k) && PTR_DEV(k, 0) == PTR_CHECK_DEV) 119 for (i = 0; i < KEY_PTRS(k); i++) {
120 return true; 120 if (!ptr_available(b->c, k, i))
121 return true;
121 122
122 for (i = 0; i < KEY_PTRS(k); i++) 123 g = PTR_BUCKET(b->c, k, i);
123 if (ptr_available(b->c, k, i)) { 124 stale = ptr_stale(b->c, k, i);
124 g = PTR_BUCKET(b->c, k, i);
125 stale = ptr_stale(b->c, k, i);
126 125
127 btree_bug_on(stale > 96, b, 126 btree_bug_on(stale > 96, b,
128 "key too stale: %i, need_gc %u", 127 "key too stale: %i, need_gc %u",
129 stale, b->c->need_gc); 128 stale, b->c->need_gc);
130 129
131 btree_bug_on(stale && KEY_DIRTY(k) && KEY_SIZE(k), 130 btree_bug_on(stale && KEY_DIRTY(k) && KEY_SIZE(k),
132 b, "stale dirty pointer"); 131 b, "stale dirty pointer");
133 132
134 if (stale) 133 if (stale)
135 return true; 134 return true;
136 135
137#ifdef CONFIG_BCACHE_EDEBUG 136#ifdef CONFIG_BCACHE_EDEBUG
138 if (!mutex_trylock(&b->c->bucket_lock)) 137 if (!mutex_trylock(&b->c->bucket_lock))
139 continue; 138 continue;
140 139
141 if (b->level) { 140 if (b->level) {
142 if (KEY_DIRTY(k) || 141 if (KEY_DIRTY(k) ||
143 g->prio != BTREE_PRIO || 142 g->prio != BTREE_PRIO ||
144 (b->c->gc_mark_valid && 143 (b->c->gc_mark_valid &&
145 GC_MARK(g) != GC_MARK_METADATA)) 144 GC_MARK(g) != GC_MARK_METADATA))
146 goto bug; 145 goto bug;
147 146
148 } else { 147 } else {
149 if (g->prio == BTREE_PRIO) 148 if (g->prio == BTREE_PRIO)
150 goto bug; 149 goto bug;
151 150
152 if (KEY_DIRTY(k) && 151 if (KEY_DIRTY(k) &&
153 b->c->gc_mark_valid && 152 b->c->gc_mark_valid &&
154 GC_MARK(g) != GC_MARK_DIRTY) 153 GC_MARK(g) != GC_MARK_DIRTY)
155 goto bug; 154 goto bug;
156 }
157 mutex_unlock(&b->c->bucket_lock);
158#endif
159 } 155 }
156 mutex_unlock(&b->c->bucket_lock);
157#endif
158 }
160 159
161 return false; 160 return false;
162#ifdef CONFIG_BCACHE_EDEBUG 161#ifdef CONFIG_BCACHE_EDEBUG