aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKent Overstreet <kmo@daterainc.com>2014-04-10 20:58:49 -0400
committerKent Overstreet <kmo@daterainc.com>2014-08-04 18:23:02 -0400
commit9aa61a992acceeec0d1de2cd99938421498659d5 (patch)
treed414fdba809e0193f0d19d5ea80180ef96f3a23e
parent5b1016e62f74c53e0330403025954c8d95384c03 (diff)
bcache: Fix a journal replay bug
journal replay wansn't validating pointers with bch_extent_invalid() before derefing, fixed Signed-off-by: Kent Overstreet <kmo@daterainc.com>
-rw-r--r--drivers/md/bcache/extents.c13
-rw-r--r--drivers/md/bcache/extents.h1
-rw-r--r--drivers/md/bcache/journal.c16
3 files changed, 19 insertions, 11 deletions
diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c
index 3a0de4cf9771..243de0bf15cd 100644
--- a/drivers/md/bcache/extents.c
+++ b/drivers/md/bcache/extents.c
@@ -474,9 +474,8 @@ out:
474 return false; 474 return false;
475} 475}
476 476
477static bool bch_extent_invalid(struct btree_keys *bk, const struct bkey *k) 477bool __bch_extent_invalid(struct cache_set *c, const struct bkey *k)
478{ 478{
479 struct btree *b = container_of(bk, struct btree, keys);
480 char buf[80]; 479 char buf[80];
481 480
482 if (!KEY_SIZE(k)) 481 if (!KEY_SIZE(k))
@@ -485,16 +484,22 @@ static bool bch_extent_invalid(struct btree_keys *bk, const struct bkey *k)
485 if (KEY_SIZE(k) > KEY_OFFSET(k)) 484 if (KEY_SIZE(k) > KEY_OFFSET(k))
486 goto bad; 485 goto bad;
487 486
488 if (__ptr_invalid(b->c, k)) 487 if (__ptr_invalid(c, k))
489 goto bad; 488 goto bad;
490 489
491 return false; 490 return false;
492bad: 491bad:
493 bch_extent_to_text(buf, sizeof(buf), k); 492 bch_extent_to_text(buf, sizeof(buf), k);
494 cache_bug(b->c, "spotted extent %s: %s", buf, bch_ptr_status(b->c, k)); 493 cache_bug(c, "spotted extent %s: %s", buf, bch_ptr_status(c, k));
495 return true; 494 return true;
496} 495}
497 496
497static bool bch_extent_invalid(struct btree_keys *bk, const struct bkey *k)
498{
499 struct btree *b = container_of(bk, struct btree, keys);
500 return __bch_extent_invalid(b->c, k);
501}
502
498static bool bch_extent_bad_expensive(struct btree *b, const struct bkey *k, 503static bool bch_extent_bad_expensive(struct btree *b, const struct bkey *k,
499 unsigned ptr) 504 unsigned ptr)
500{ 505{
diff --git a/drivers/md/bcache/extents.h b/drivers/md/bcache/extents.h
index e4e23409782d..e2ed54054e7a 100644
--- a/drivers/md/bcache/extents.h
+++ b/drivers/md/bcache/extents.h
@@ -9,5 +9,6 @@ struct cache_set;
9 9
10void bch_extent_to_text(char *, size_t, const struct bkey *); 10void bch_extent_to_text(char *, size_t, const struct bkey *);
11bool __bch_btree_ptr_invalid(struct cache_set *, const struct bkey *); 11bool __bch_btree_ptr_invalid(struct cache_set *, const struct bkey *);
12bool __bch_extent_invalid(struct cache_set *, const struct bkey *);
12 13
13#endif /* _BCACHE_EXTENTS_H */ 14#endif /* _BCACHE_EXTENTS_H */
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index 59e82021b5bb..363b88131f01 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -7,6 +7,7 @@
7#include "bcache.h" 7#include "bcache.h"
8#include "btree.h" 8#include "btree.h"
9#include "debug.h" 9#include "debug.h"
10#include "extents.h"
10 11
11#include <trace/events/bcache.h> 12#include <trace/events/bcache.h>
12 13
@@ -291,15 +292,16 @@ void bch_journal_mark(struct cache_set *c, struct list_head *list)
291 292
292 for (k = i->j.start; 293 for (k = i->j.start;
293 k < bset_bkey_last(&i->j); 294 k < bset_bkey_last(&i->j);
294 k = bkey_next(k)) { 295 k = bkey_next(k))
295 unsigned j; 296 if (!__bch_extent_invalid(c, k)) {
297 unsigned j;
296 298
297 for (j = 0; j < KEY_PTRS(k); j++) 299 for (j = 0; j < KEY_PTRS(k); j++)
298 if (ptr_available(c, k, j)) 300 if (ptr_available(c, k, j))
299 atomic_inc(&PTR_BUCKET(c, k, j)->pin); 301 atomic_inc(&PTR_BUCKET(c, k, j)->pin);
300 302
301 bch_initial_mark_key(c, 0, k); 303 bch_initial_mark_key(c, 0, k);
302 } 304 }
303 } 305 }
304} 306}
305 307