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>
This commit is contained in:
parent
5b1016e62f
commit
9aa61a992a
@ -474,9 +474,8 @@ out:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bch_extent_invalid(struct btree_keys *bk, const struct bkey *k)
|
bool __bch_extent_invalid(struct cache_set *c, const struct bkey *k)
|
||||||
{
|
{
|
||||||
struct btree *b = container_of(bk, struct btree, keys);
|
|
||||||
char buf[80];
|
char buf[80];
|
||||||
|
|
||||||
if (!KEY_SIZE(k))
|
if (!KEY_SIZE(k))
|
||||||
@ -485,16 +484,22 @@ static bool bch_extent_invalid(struct btree_keys *bk, const struct bkey *k)
|
|||||||
if (KEY_SIZE(k) > KEY_OFFSET(k))
|
if (KEY_SIZE(k) > KEY_OFFSET(k))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
if (__ptr_invalid(b->c, k))
|
if (__ptr_invalid(c, k))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
bad:
|
bad:
|
||||||
bch_extent_to_text(buf, sizeof(buf), k);
|
bch_extent_to_text(buf, sizeof(buf), k);
|
||||||
cache_bug(b->c, "spotted extent %s: %s", buf, bch_ptr_status(b->c, k));
|
cache_bug(c, "spotted extent %s: %s", buf, bch_ptr_status(c, k));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool bch_extent_invalid(struct btree_keys *bk, const struct bkey *k)
|
||||||
|
{
|
||||||
|
struct btree *b = container_of(bk, struct btree, keys);
|
||||||
|
return __bch_extent_invalid(b->c, k);
|
||||||
|
}
|
||||||
|
|
||||||
static bool bch_extent_bad_expensive(struct btree *b, const struct bkey *k,
|
static bool bch_extent_bad_expensive(struct btree *b, const struct bkey *k,
|
||||||
unsigned ptr)
|
unsigned ptr)
|
||||||
{
|
{
|
||||||
|
@ -9,5 +9,6 @@ struct cache_set;
|
|||||||
|
|
||||||
void bch_extent_to_text(char *, size_t, const struct bkey *);
|
void bch_extent_to_text(char *, size_t, const struct bkey *);
|
||||||
bool __bch_btree_ptr_invalid(struct cache_set *, const struct bkey *);
|
bool __bch_btree_ptr_invalid(struct cache_set *, const struct bkey *);
|
||||||
|
bool __bch_extent_invalid(struct cache_set *, const struct bkey *);
|
||||||
|
|
||||||
#endif /* _BCACHE_EXTENTS_H */
|
#endif /* _BCACHE_EXTENTS_H */
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "bcache.h"
|
#include "bcache.h"
|
||||||
#include "btree.h"
|
#include "btree.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "extents.h"
|
||||||
|
|
||||||
#include <trace/events/bcache.h>
|
#include <trace/events/bcache.h>
|
||||||
|
|
||||||
@ -291,15 +292,16 @@ void bch_journal_mark(struct cache_set *c, struct list_head *list)
|
|||||||
|
|
||||||
for (k = i->j.start;
|
for (k = i->j.start;
|
||||||
k < bset_bkey_last(&i->j);
|
k < bset_bkey_last(&i->j);
|
||||||
k = bkey_next(k)) {
|
k = bkey_next(k))
|
||||||
unsigned j;
|
if (!__bch_extent_invalid(c, k)) {
|
||||||
|
unsigned j;
|
||||||
|
|
||||||
for (j = 0; j < KEY_PTRS(k); j++)
|
for (j = 0; j < KEY_PTRS(k); j++)
|
||||||
if (ptr_available(c, k, j))
|
if (ptr_available(c, k, j))
|
||||||
atomic_inc(&PTR_BUCKET(c, k, j)->pin);
|
atomic_inc(&PTR_BUCKET(c, k, j)->pin);
|
||||||
|
|
||||||
bch_initial_mark_key(c, 0, k);
|
bch_initial_mark_key(c, 0, k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user