Merge branch 'for-jens' of http://evilpiepirate.org/git/linux-bcache into for-3.17/drivers
Kent writes: Hey Jens, here's the pull request for 3.17 - typically late, but lots of tasty fixes in this one.
This commit is contained in:
commit
99d540018c
|
@ -331,7 +331,7 @@ static int bch_allocator_thread(void *arg)
|
||||||
mutex_unlock(&ca->set->bucket_lock);
|
mutex_unlock(&ca->set->bucket_lock);
|
||||||
blkdev_issue_discard(ca->bdev,
|
blkdev_issue_discard(ca->bdev,
|
||||||
bucket_to_sector(ca->set, bucket),
|
bucket_to_sector(ca->set, bucket),
|
||||||
ca->sb.block_size, GFP_KERNEL, 0);
|
ca->sb.bucket_size, GFP_KERNEL, 0);
|
||||||
mutex_lock(&ca->set->bucket_lock);
|
mutex_lock(&ca->set->bucket_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -477,9 +477,13 @@ struct gc_stat {
|
||||||
* CACHE_SET_STOPPING always gets set first when we're closing down a cache set;
|
* CACHE_SET_STOPPING always gets set first when we're closing down a cache set;
|
||||||
* we'll continue to run normally for awhile with CACHE_SET_STOPPING set (i.e.
|
* we'll continue to run normally for awhile with CACHE_SET_STOPPING set (i.e.
|
||||||
* flushing dirty data).
|
* flushing dirty data).
|
||||||
|
*
|
||||||
|
* CACHE_SET_RUNNING means all cache devices have been registered and journal
|
||||||
|
* replay is complete.
|
||||||
*/
|
*/
|
||||||
#define CACHE_SET_UNREGISTERING 0
|
#define CACHE_SET_UNREGISTERING 0
|
||||||
#define CACHE_SET_STOPPING 1
|
#define CACHE_SET_STOPPING 1
|
||||||
|
#define CACHE_SET_RUNNING 2
|
||||||
|
|
||||||
struct cache_set {
|
struct cache_set {
|
||||||
struct closure cl;
|
struct closure cl;
|
||||||
|
|
|
@ -1182,7 +1182,7 @@ static void __btree_sort(struct btree_keys *b, struct btree_iter *iter,
|
||||||
{
|
{
|
||||||
uint64_t start_time;
|
uint64_t start_time;
|
||||||
bool used_mempool = false;
|
bool used_mempool = false;
|
||||||
struct bset *out = (void *) __get_free_pages(__GFP_NOWARN|GFP_NOIO,
|
struct bset *out = (void *) __get_free_pages(__GFP_NOWARN|GFP_NOWAIT,
|
||||||
order);
|
order);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
struct page *outp;
|
struct page *outp;
|
||||||
|
|
|
@ -453,7 +453,7 @@ static inline bool bch_bkey_equal_header(const struct bkey *l,
|
||||||
{
|
{
|
||||||
return (KEY_DIRTY(l) == KEY_DIRTY(r) &&
|
return (KEY_DIRTY(l) == KEY_DIRTY(r) &&
|
||||||
KEY_PTRS(l) == KEY_PTRS(r) &&
|
KEY_PTRS(l) == KEY_PTRS(r) &&
|
||||||
KEY_CSUM(l) == KEY_CSUM(l));
|
KEY_CSUM(l) == KEY_CSUM(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keylists */
|
/* Keylists */
|
||||||
|
|
|
@ -117,9 +117,9 @@
|
||||||
({ \
|
({ \
|
||||||
int _r, l = (b)->level - 1; \
|
int _r, l = (b)->level - 1; \
|
||||||
bool _w = l <= (op)->lock; \
|
bool _w = l <= (op)->lock; \
|
||||||
struct btree *_child = bch_btree_node_get((b)->c, op, key, l, _w);\
|
struct btree *_child = bch_btree_node_get((b)->c, op, key, l, \
|
||||||
|
_w, b); \
|
||||||
if (!IS_ERR(_child)) { \
|
if (!IS_ERR(_child)) { \
|
||||||
_child->parent = (b); \
|
|
||||||
_r = bch_btree_ ## fn(_child, op, ##__VA_ARGS__); \
|
_r = bch_btree_ ## fn(_child, op, ##__VA_ARGS__); \
|
||||||
rw_unlock(_w, _child); \
|
rw_unlock(_w, _child); \
|
||||||
} else \
|
} else \
|
||||||
|
@ -142,7 +142,6 @@
|
||||||
rw_lock(_w, _b, _b->level); \
|
rw_lock(_w, _b, _b->level); \
|
||||||
if (_b == (c)->root && \
|
if (_b == (c)->root && \
|
||||||
_w == insert_lock(op, _b)) { \
|
_w == insert_lock(op, _b)) { \
|
||||||
_b->parent = NULL; \
|
|
||||||
_r = bch_btree_ ## fn(_b, op, ##__VA_ARGS__); \
|
_r = bch_btree_ ## fn(_b, op, ##__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
rw_unlock(_w, _b); \
|
rw_unlock(_w, _b); \
|
||||||
|
@ -202,7 +201,7 @@ void bch_btree_node_read_done(struct btree *b)
|
||||||
struct bset *i = btree_bset_first(b);
|
struct bset *i = btree_bset_first(b);
|
||||||
struct btree_iter *iter;
|
struct btree_iter *iter;
|
||||||
|
|
||||||
iter = mempool_alloc(b->c->fill_iter, GFP_NOWAIT);
|
iter = mempool_alloc(b->c->fill_iter, GFP_NOIO);
|
||||||
iter->size = b->c->sb.bucket_size / b->c->sb.block_size;
|
iter->size = b->c->sb.bucket_size / b->c->sb.block_size;
|
||||||
iter->used = 0;
|
iter->used = 0;
|
||||||
|
|
||||||
|
@ -421,7 +420,7 @@ static void do_btree_node_write(struct btree *b)
|
||||||
SET_PTR_OFFSET(&k.key, 0, PTR_OFFSET(&k.key, 0) +
|
SET_PTR_OFFSET(&k.key, 0, PTR_OFFSET(&k.key, 0) +
|
||||||
bset_sector_offset(&b->keys, i));
|
bset_sector_offset(&b->keys, i));
|
||||||
|
|
||||||
if (!bio_alloc_pages(b->bio, GFP_NOIO)) {
|
if (!bio_alloc_pages(b->bio, __GFP_NOWARN|GFP_NOWAIT)) {
|
||||||
int j;
|
int j;
|
||||||
struct bio_vec *bv;
|
struct bio_vec *bv;
|
||||||
void *base = (void *) ((unsigned long) i & ~(PAGE_SIZE - 1));
|
void *base = (void *) ((unsigned long) i & ~(PAGE_SIZE - 1));
|
||||||
|
@ -967,7 +966,8 @@ err:
|
||||||
* level and op->lock.
|
* level and op->lock.
|
||||||
*/
|
*/
|
||||||
struct btree *bch_btree_node_get(struct cache_set *c, struct btree_op *op,
|
struct btree *bch_btree_node_get(struct cache_set *c, struct btree_op *op,
|
||||||
struct bkey *k, int level, bool write)
|
struct bkey *k, int level, bool write,
|
||||||
|
struct btree *parent)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
struct btree *b;
|
struct btree *b;
|
||||||
|
@ -1002,6 +1002,7 @@ retry:
|
||||||
BUG_ON(b->level != level);
|
BUG_ON(b->level != level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b->parent = parent;
|
||||||
b->accessed = 1;
|
b->accessed = 1;
|
||||||
|
|
||||||
for (; i <= b->keys.nsets && b->keys.set[i].size; i++) {
|
for (; i <= b->keys.nsets && b->keys.set[i].size; i++) {
|
||||||
|
@ -1022,15 +1023,16 @@ retry:
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void btree_node_prefetch(struct cache_set *c, struct bkey *k, int level)
|
static void btree_node_prefetch(struct btree *parent, struct bkey *k)
|
||||||
{
|
{
|
||||||
struct btree *b;
|
struct btree *b;
|
||||||
|
|
||||||
mutex_lock(&c->bucket_lock);
|
mutex_lock(&parent->c->bucket_lock);
|
||||||
b = mca_alloc(c, NULL, k, level);
|
b = mca_alloc(parent->c, NULL, k, parent->level - 1);
|
||||||
mutex_unlock(&c->bucket_lock);
|
mutex_unlock(&parent->c->bucket_lock);
|
||||||
|
|
||||||
if (!IS_ERR_OR_NULL(b)) {
|
if (!IS_ERR_OR_NULL(b)) {
|
||||||
|
b->parent = parent;
|
||||||
bch_btree_node_read(b);
|
bch_btree_node_read(b);
|
||||||
rw_unlock(true, b);
|
rw_unlock(true, b);
|
||||||
}
|
}
|
||||||
|
@ -1060,15 +1062,16 @@ static void btree_node_free(struct btree *b)
|
||||||
mutex_unlock(&b->c->bucket_lock);
|
mutex_unlock(&b->c->bucket_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct btree *bch_btree_node_alloc(struct cache_set *c, struct btree_op *op,
|
struct btree *__bch_btree_node_alloc(struct cache_set *c, struct btree_op *op,
|
||||||
int level)
|
int level, bool wait,
|
||||||
|
struct btree *parent)
|
||||||
{
|
{
|
||||||
BKEY_PADDED(key) k;
|
BKEY_PADDED(key) k;
|
||||||
struct btree *b = ERR_PTR(-EAGAIN);
|
struct btree *b = ERR_PTR(-EAGAIN);
|
||||||
|
|
||||||
mutex_lock(&c->bucket_lock);
|
mutex_lock(&c->bucket_lock);
|
||||||
retry:
|
retry:
|
||||||
if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, op != NULL))
|
if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, wait))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
bkey_put(c, &k.key);
|
bkey_put(c, &k.key);
|
||||||
|
@ -1085,6 +1088,7 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
b->accessed = 1;
|
b->accessed = 1;
|
||||||
|
b->parent = parent;
|
||||||
bch_bset_init_next(&b->keys, b->keys.set->data, bset_magic(&b->c->sb));
|
bch_bset_init_next(&b->keys, b->keys.set->data, bset_magic(&b->c->sb));
|
||||||
|
|
||||||
mutex_unlock(&c->bucket_lock);
|
mutex_unlock(&c->bucket_lock);
|
||||||
|
@ -1096,14 +1100,21 @@ err_free:
|
||||||
err:
|
err:
|
||||||
mutex_unlock(&c->bucket_lock);
|
mutex_unlock(&c->bucket_lock);
|
||||||
|
|
||||||
trace_bcache_btree_node_alloc_fail(b);
|
trace_bcache_btree_node_alloc_fail(c);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct btree *bch_btree_node_alloc(struct cache_set *c,
|
||||||
|
struct btree_op *op, int level,
|
||||||
|
struct btree *parent)
|
||||||
|
{
|
||||||
|
return __bch_btree_node_alloc(c, op, level, op != NULL, parent);
|
||||||
|
}
|
||||||
|
|
||||||
static struct btree *btree_node_alloc_replacement(struct btree *b,
|
static struct btree *btree_node_alloc_replacement(struct btree *b,
|
||||||
struct btree_op *op)
|
struct btree_op *op)
|
||||||
{
|
{
|
||||||
struct btree *n = bch_btree_node_alloc(b->c, op, b->level);
|
struct btree *n = bch_btree_node_alloc(b->c, op, b->level, b->parent);
|
||||||
if (!IS_ERR_OR_NULL(n)) {
|
if (!IS_ERR_OR_NULL(n)) {
|
||||||
mutex_lock(&n->write_lock);
|
mutex_lock(&n->write_lock);
|
||||||
bch_btree_sort_into(&b->keys, &n->keys, &b->c->sort);
|
bch_btree_sort_into(&b->keys, &n->keys, &b->c->sort);
|
||||||
|
@ -1403,6 +1414,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
|
||||||
BUG_ON(btree_bset_first(new_nodes[0])->keys);
|
BUG_ON(btree_bset_first(new_nodes[0])->keys);
|
||||||
btree_node_free(new_nodes[0]);
|
btree_node_free(new_nodes[0]);
|
||||||
rw_unlock(true, new_nodes[0]);
|
rw_unlock(true, new_nodes[0]);
|
||||||
|
new_nodes[0] = NULL;
|
||||||
|
|
||||||
for (i = 0; i < nodes; i++) {
|
for (i = 0; i < nodes; i++) {
|
||||||
if (__bch_keylist_realloc(&keylist, bkey_u64s(&r[i].b->key)))
|
if (__bch_keylist_realloc(&keylist, bkey_u64s(&r[i].b->key)))
|
||||||
|
@ -1516,7 +1528,7 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
|
||||||
k = bch_btree_iter_next_filter(&iter, &b->keys, bch_ptr_bad);
|
k = bch_btree_iter_next_filter(&iter, &b->keys, bch_ptr_bad);
|
||||||
if (k) {
|
if (k) {
|
||||||
r->b = bch_btree_node_get(b->c, op, k, b->level - 1,
|
r->b = bch_btree_node_get(b->c, op, k, b->level - 1,
|
||||||
true);
|
true, b);
|
||||||
if (IS_ERR(r->b)) {
|
if (IS_ERR(r->b)) {
|
||||||
ret = PTR_ERR(r->b);
|
ret = PTR_ERR(r->b);
|
||||||
break;
|
break;
|
||||||
|
@ -1811,7 +1823,7 @@ static int bch_btree_check_recurse(struct btree *b, struct btree_op *op)
|
||||||
k = bch_btree_iter_next_filter(&iter, &b->keys,
|
k = bch_btree_iter_next_filter(&iter, &b->keys,
|
||||||
bch_ptr_bad);
|
bch_ptr_bad);
|
||||||
if (k)
|
if (k)
|
||||||
btree_node_prefetch(b->c, k, b->level - 1);
|
btree_node_prefetch(b, k);
|
||||||
|
|
||||||
if (p)
|
if (p)
|
||||||
ret = btree(check_recurse, p, b, op);
|
ret = btree(check_recurse, p, b, op);
|
||||||
|
@ -1976,12 +1988,12 @@ static int btree_split(struct btree *b, struct btree_op *op,
|
||||||
|
|
||||||
trace_bcache_btree_node_split(b, btree_bset_first(n1)->keys);
|
trace_bcache_btree_node_split(b, btree_bset_first(n1)->keys);
|
||||||
|
|
||||||
n2 = bch_btree_node_alloc(b->c, op, b->level);
|
n2 = bch_btree_node_alloc(b->c, op, b->level, b->parent);
|
||||||
if (IS_ERR(n2))
|
if (IS_ERR(n2))
|
||||||
goto err_free1;
|
goto err_free1;
|
||||||
|
|
||||||
if (!b->parent) {
|
if (!b->parent) {
|
||||||
n3 = bch_btree_node_alloc(b->c, op, b->level + 1);
|
n3 = bch_btree_node_alloc(b->c, op, b->level + 1, NULL);
|
||||||
if (IS_ERR(n3))
|
if (IS_ERR(n3))
|
||||||
goto err_free2;
|
goto err_free2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,9 +242,10 @@ void __bch_btree_node_write(struct btree *, struct closure *);
|
||||||
void bch_btree_node_write(struct btree *, struct closure *);
|
void bch_btree_node_write(struct btree *, struct closure *);
|
||||||
|
|
||||||
void bch_btree_set_root(struct btree *);
|
void bch_btree_set_root(struct btree *);
|
||||||
struct btree *bch_btree_node_alloc(struct cache_set *, struct btree_op *, int);
|
struct btree *__bch_btree_node_alloc(struct cache_set *, struct btree_op *,
|
||||||
|
int, bool, struct btree *);
|
||||||
struct btree *bch_btree_node_get(struct cache_set *, struct btree_op *,
|
struct btree *bch_btree_node_get(struct cache_set *, struct btree_op *,
|
||||||
struct bkey *, int, bool);
|
struct bkey *, int, bool, struct btree *);
|
||||||
|
|
||||||
int bch_btree_insert_check_key(struct btree *, struct btree_op *,
|
int bch_btree_insert_check_key(struct btree *, struct btree_op *,
|
||||||
struct bkey *);
|
struct bkey *);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
@ -189,11 +190,15 @@ int bch_journal_read(struct cache_set *c, struct list_head *list)
|
||||||
if (read_bucket(l))
|
if (read_bucket(l))
|
||||||
goto bsearch;
|
goto bsearch;
|
||||||
|
|
||||||
if (list_empty(list))
|
/* no journal entries on this device? */
|
||||||
|
if (l == ca->sb.njournal_buckets)
|
||||||
continue;
|
continue;
|
||||||
bsearch:
|
bsearch:
|
||||||
|
BUG_ON(list_empty(list));
|
||||||
|
|
||||||
/* Binary search */
|
/* Binary search */
|
||||||
m = r = find_next_bit(bitmap, ca->sb.njournal_buckets, l + 1);
|
m = l;
|
||||||
|
r = find_next_bit(bitmap, ca->sb.njournal_buckets, l + 1);
|
||||||
pr_debug("starting binary search, l %u r %u", l, r);
|
pr_debug("starting binary search, l %u r %u", l, r);
|
||||||
|
|
||||||
while (l + 1 < r) {
|
while (l + 1 < r) {
|
||||||
|
@ -291,15 +296,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -311,7 +311,8 @@ void bch_data_insert(struct closure *cl)
|
||||||
{
|
{
|
||||||
struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
|
struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
|
||||||
|
|
||||||
trace_bcache_write(op->bio, op->writeback, op->bypass);
|
trace_bcache_write(op->c, op->inode, op->bio,
|
||||||
|
op->writeback, op->bypass);
|
||||||
|
|
||||||
bch_keylist_init(&op->insert_keys);
|
bch_keylist_init(&op->insert_keys);
|
||||||
bio_get(op->bio);
|
bio_get(op->bio);
|
||||||
|
|
|
@ -733,8 +733,6 @@ static void bcache_device_detach(struct bcache_device *d)
|
||||||
static void bcache_device_attach(struct bcache_device *d, struct cache_set *c,
|
static void bcache_device_attach(struct bcache_device *d, struct cache_set *c,
|
||||||
unsigned id)
|
unsigned id)
|
||||||
{
|
{
|
||||||
BUG_ON(test_bit(CACHE_SET_STOPPING, &c->flags));
|
|
||||||
|
|
||||||
d->id = id;
|
d->id = id;
|
||||||
d->c = c;
|
d->c = c;
|
||||||
c->devices[id] = d;
|
c->devices[id] = d;
|
||||||
|
@ -927,6 +925,7 @@ static void cached_dev_detach_finish(struct work_struct *w)
|
||||||
list_move(&dc->list, &uncached_devices);
|
list_move(&dc->list, &uncached_devices);
|
||||||
|
|
||||||
clear_bit(BCACHE_DEV_DETACHING, &dc->disk.flags);
|
clear_bit(BCACHE_DEV_DETACHING, &dc->disk.flags);
|
||||||
|
clear_bit(BCACHE_DEV_UNLINK_DONE, &dc->disk.flags);
|
||||||
|
|
||||||
mutex_unlock(&bch_register_lock);
|
mutex_unlock(&bch_register_lock);
|
||||||
|
|
||||||
|
@ -1041,6 +1040,9 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c)
|
||||||
*/
|
*/
|
||||||
atomic_set(&dc->count, 1);
|
atomic_set(&dc->count, 1);
|
||||||
|
|
||||||
|
if (bch_cached_dev_writeback_start(dc))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) {
|
if (BDEV_STATE(&dc->sb) == BDEV_STATE_DIRTY) {
|
||||||
bch_sectors_dirty_init(dc);
|
bch_sectors_dirty_init(dc);
|
||||||
atomic_set(&dc->has_dirty, 1);
|
atomic_set(&dc->has_dirty, 1);
|
||||||
|
@ -1070,7 +1072,8 @@ static void cached_dev_free(struct closure *cl)
|
||||||
struct cached_dev *dc = container_of(cl, struct cached_dev, disk.cl);
|
struct cached_dev *dc = container_of(cl, struct cached_dev, disk.cl);
|
||||||
|
|
||||||
cancel_delayed_work_sync(&dc->writeback_rate_update);
|
cancel_delayed_work_sync(&dc->writeback_rate_update);
|
||||||
kthread_stop(dc->writeback_thread);
|
if (!IS_ERR_OR_NULL(dc->writeback_thread))
|
||||||
|
kthread_stop(dc->writeback_thread);
|
||||||
|
|
||||||
mutex_lock(&bch_register_lock);
|
mutex_lock(&bch_register_lock);
|
||||||
|
|
||||||
|
@ -1081,12 +1084,8 @@ static void cached_dev_free(struct closure *cl)
|
||||||
|
|
||||||
mutex_unlock(&bch_register_lock);
|
mutex_unlock(&bch_register_lock);
|
||||||
|
|
||||||
if (!IS_ERR_OR_NULL(dc->bdev)) {
|
if (!IS_ERR_OR_NULL(dc->bdev))
|
||||||
if (dc->bdev->bd_disk)
|
|
||||||
blk_sync_queue(bdev_get_queue(dc->bdev));
|
|
||||||
|
|
||||||
blkdev_put(dc->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
|
blkdev_put(dc->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
|
||||||
}
|
|
||||||
|
|
||||||
wake_up(&unregister_wait);
|
wake_up(&unregister_wait);
|
||||||
|
|
||||||
|
@ -1213,7 +1212,9 @@ void bch_flash_dev_release(struct kobject *kobj)
|
||||||
static void flash_dev_free(struct closure *cl)
|
static void flash_dev_free(struct closure *cl)
|
||||||
{
|
{
|
||||||
struct bcache_device *d = container_of(cl, struct bcache_device, cl);
|
struct bcache_device *d = container_of(cl, struct bcache_device, cl);
|
||||||
|
mutex_lock(&bch_register_lock);
|
||||||
bcache_device_free(d);
|
bcache_device_free(d);
|
||||||
|
mutex_unlock(&bch_register_lock);
|
||||||
kobject_put(&d->kobj);
|
kobject_put(&d->kobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1221,7 +1222,9 @@ static void flash_dev_flush(struct closure *cl)
|
||||||
{
|
{
|
||||||
struct bcache_device *d = container_of(cl, struct bcache_device, cl);
|
struct bcache_device *d = container_of(cl, struct bcache_device, cl);
|
||||||
|
|
||||||
|
mutex_lock(&bch_register_lock);
|
||||||
bcache_device_unlink(d);
|
bcache_device_unlink(d);
|
||||||
|
mutex_unlock(&bch_register_lock);
|
||||||
kobject_del(&d->kobj);
|
kobject_del(&d->kobj);
|
||||||
continue_at(cl, flash_dev_free, system_wq);
|
continue_at(cl, flash_dev_free, system_wq);
|
||||||
}
|
}
|
||||||
|
@ -1277,6 +1280,9 @@ int bch_flash_dev_create(struct cache_set *c, uint64_t size)
|
||||||
if (test_bit(CACHE_SET_STOPPING, &c->flags))
|
if (test_bit(CACHE_SET_STOPPING, &c->flags))
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
|
|
||||||
|
if (!test_bit(CACHE_SET_RUNNING, &c->flags))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
u = uuid_find_empty(c);
|
u = uuid_find_empty(c);
|
||||||
if (!u) {
|
if (!u) {
|
||||||
pr_err("Can't create volume, no room for UUID");
|
pr_err("Can't create volume, no room for UUID");
|
||||||
|
@ -1346,8 +1352,11 @@ static void cache_set_free(struct closure *cl)
|
||||||
bch_journal_free(c);
|
bch_journal_free(c);
|
||||||
|
|
||||||
for_each_cache(ca, c, i)
|
for_each_cache(ca, c, i)
|
||||||
if (ca)
|
if (ca) {
|
||||||
|
ca->set = NULL;
|
||||||
|
c->cache[ca->sb.nr_this_dev] = NULL;
|
||||||
kobject_put(&ca->kobj);
|
kobject_put(&ca->kobj);
|
||||||
|
}
|
||||||
|
|
||||||
bch_bset_sort_state_free(&c->sort);
|
bch_bset_sort_state_free(&c->sort);
|
||||||
free_pages((unsigned long) c->uuids, ilog2(bucket_pages(c)));
|
free_pages((unsigned long) c->uuids, ilog2(bucket_pages(c)));
|
||||||
|
@ -1405,9 +1414,11 @@ static void cache_set_flush(struct closure *cl)
|
||||||
if (ca->alloc_thread)
|
if (ca->alloc_thread)
|
||||||
kthread_stop(ca->alloc_thread);
|
kthread_stop(ca->alloc_thread);
|
||||||
|
|
||||||
cancel_delayed_work_sync(&c->journal.work);
|
if (c->journal.cur) {
|
||||||
/* flush last journal entry if needed */
|
cancel_delayed_work_sync(&c->journal.work);
|
||||||
c->journal.work.work.func(&c->journal.work.work);
|
/* flush last journal entry if needed */
|
||||||
|
c->journal.work.work.func(&c->journal.work.work);
|
||||||
|
}
|
||||||
|
|
||||||
closure_return(cl);
|
closure_return(cl);
|
||||||
}
|
}
|
||||||
|
@ -1586,7 +1597,7 @@ static void run_cache_set(struct cache_set *c)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
err = "error reading btree root";
|
err = "error reading btree root";
|
||||||
c->root = bch_btree_node_get(c, NULL, k, j->btree_level, true);
|
c->root = bch_btree_node_get(c, NULL, k, j->btree_level, true, NULL);
|
||||||
if (IS_ERR_OR_NULL(c->root))
|
if (IS_ERR_OR_NULL(c->root))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -1661,7 +1672,7 @@ static void run_cache_set(struct cache_set *c)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
err = "cannot allocate new btree root";
|
err = "cannot allocate new btree root";
|
||||||
c->root = bch_btree_node_alloc(c, NULL, 0);
|
c->root = __bch_btree_node_alloc(c, NULL, 0, true, NULL);
|
||||||
if (IS_ERR_OR_NULL(c->root))
|
if (IS_ERR_OR_NULL(c->root))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -1697,6 +1708,7 @@ static void run_cache_set(struct cache_set *c)
|
||||||
|
|
||||||
flash_devs_run(c);
|
flash_devs_run(c);
|
||||||
|
|
||||||
|
set_bit(CACHE_SET_RUNNING, &c->flags);
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
closure_sync(&cl);
|
closure_sync(&cl);
|
||||||
|
@ -1760,6 +1772,7 @@ found:
|
||||||
pr_debug("set version = %llu", c->sb.version);
|
pr_debug("set version = %llu", c->sb.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kobject_get(&ca->kobj);
|
||||||
ca->set = c;
|
ca->set = c;
|
||||||
ca->set->cache[ca->sb.nr_this_dev] = ca;
|
ca->set->cache[ca->sb.nr_this_dev] = ca;
|
||||||
c->cache_by_alloc[c->caches_loaded++] = ca;
|
c->cache_by_alloc[c->caches_loaded++] = ca;
|
||||||
|
@ -1780,8 +1793,10 @@ void bch_cache_release(struct kobject *kobj)
|
||||||
struct cache *ca = container_of(kobj, struct cache, kobj);
|
struct cache *ca = container_of(kobj, struct cache, kobj);
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
if (ca->set)
|
if (ca->set) {
|
||||||
|
BUG_ON(ca->set->cache[ca->sb.nr_this_dev] != ca);
|
||||||
ca->set->cache[ca->sb.nr_this_dev] = NULL;
|
ca->set->cache[ca->sb.nr_this_dev] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bio_split_pool_free(&ca->bio_split_hook);
|
bio_split_pool_free(&ca->bio_split_hook);
|
||||||
|
|
||||||
|
@ -1798,10 +1813,8 @@ void bch_cache_release(struct kobject *kobj)
|
||||||
if (ca->sb_bio.bi_inline_vecs[0].bv_page)
|
if (ca->sb_bio.bi_inline_vecs[0].bv_page)
|
||||||
put_page(ca->sb_bio.bi_io_vec[0].bv_page);
|
put_page(ca->sb_bio.bi_io_vec[0].bv_page);
|
||||||
|
|
||||||
if (!IS_ERR_OR_NULL(ca->bdev)) {
|
if (!IS_ERR_OR_NULL(ca->bdev))
|
||||||
blk_sync_queue(bdev_get_queue(ca->bdev));
|
|
||||||
blkdev_put(ca->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
|
blkdev_put(ca->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
|
||||||
}
|
|
||||||
|
|
||||||
kfree(ca);
|
kfree(ca);
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
|
@ -1844,7 +1857,7 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_cache(struct cache_sb *sb, struct page *sb_page,
|
static void register_cache(struct cache_sb *sb, struct page *sb_page,
|
||||||
struct block_device *bdev, struct cache *ca)
|
struct block_device *bdev, struct cache *ca)
|
||||||
{
|
{
|
||||||
char name[BDEVNAME_SIZE];
|
char name[BDEVNAME_SIZE];
|
||||||
const char *err = "cannot allocate memory";
|
const char *err = "cannot allocate memory";
|
||||||
|
@ -1877,10 +1890,12 @@ static void register_cache(struct cache_sb *sb, struct page *sb_page,
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
pr_info("registered cache device %s", bdevname(bdev, name));
|
pr_info("registered cache device %s", bdevname(bdev, name));
|
||||||
|
out:
|
||||||
|
kobject_put(&ca->kobj);
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
pr_notice("error opening %s: %s", bdevname(bdev, name), err);
|
pr_notice("error opening %s: %s", bdevname(bdev, name), err);
|
||||||
kobject_put(&ca->kobj);
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Global interfaces/init */
|
/* Global interfaces/init */
|
||||||
|
@ -1945,10 +1960,12 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
|
||||||
if (IS_ERR(bdev)) {
|
if (IS_ERR(bdev)) {
|
||||||
if (bdev == ERR_PTR(-EBUSY)) {
|
if (bdev == ERR_PTR(-EBUSY)) {
|
||||||
bdev = lookup_bdev(strim(path));
|
bdev = lookup_bdev(strim(path));
|
||||||
|
mutex_lock(&bch_register_lock);
|
||||||
if (!IS_ERR(bdev) && bch_is_open(bdev))
|
if (!IS_ERR(bdev) && bch_is_open(bdev))
|
||||||
err = "device already registered";
|
err = "device already registered";
|
||||||
else
|
else
|
||||||
err = "device busy";
|
err = "device busy";
|
||||||
|
mutex_unlock(&bch_register_lock);
|
||||||
}
|
}
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -416,8 +416,8 @@ do { \
|
||||||
average_frequency, frequency_units); \
|
average_frequency, frequency_units); \
|
||||||
__print_time_stat(stats, name, \
|
__print_time_stat(stats, name, \
|
||||||
average_duration, duration_units); \
|
average_duration, duration_units); \
|
||||||
__print_time_stat(stats, name, \
|
sysfs_print(name ## _ ##max_duration ## _ ## duration_units, \
|
||||||
max_duration, duration_units); \
|
div_u64((stats)->max_duration, NSEC_PER_ ## duration_units));\
|
||||||
\
|
\
|
||||||
sysfs_print(name ## _last_ ## frequency_units, (stats)->last \
|
sysfs_print(name ## _last_ ## frequency_units, (stats)->last \
|
||||||
? div_s64(local_clock() - (stats)->last, \
|
? div_s64(local_clock() - (stats)->last, \
|
||||||
|
|
|
@ -239,7 +239,7 @@ static void read_dirty(struct cached_dev *dc)
|
||||||
if (KEY_START(&w->key) != dc->last_read ||
|
if (KEY_START(&w->key) != dc->last_read ||
|
||||||
jiffies_to_msecs(delay) > 50)
|
jiffies_to_msecs(delay) > 50)
|
||||||
while (!kthread_should_stop() && delay)
|
while (!kthread_should_stop() && delay)
|
||||||
delay = schedule_timeout_uninterruptible(delay);
|
delay = schedule_timeout_interruptible(delay);
|
||||||
|
|
||||||
dc->last_read = KEY_OFFSET(&w->key);
|
dc->last_read = KEY_OFFSET(&w->key);
|
||||||
|
|
||||||
|
@ -436,7 +436,7 @@ static int bch_writeback_thread(void *arg)
|
||||||
while (delay &&
|
while (delay &&
|
||||||
!kthread_should_stop() &&
|
!kthread_should_stop() &&
|
||||||
!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags))
|
!test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags))
|
||||||
delay = schedule_timeout_uninterruptible(delay);
|
delay = schedule_timeout_interruptible(delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,7 +478,7 @@ void bch_sectors_dirty_init(struct cached_dev *dc)
|
||||||
dc->disk.sectors_dirty_last = bcache_dev_sectors_dirty(&dc->disk);
|
dc->disk.sectors_dirty_last = bcache_dev_sectors_dirty(&dc->disk);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch_cached_dev_writeback_init(struct cached_dev *dc)
|
void bch_cached_dev_writeback_init(struct cached_dev *dc)
|
||||||
{
|
{
|
||||||
sema_init(&dc->in_flight, 64);
|
sema_init(&dc->in_flight, 64);
|
||||||
init_rwsem(&dc->writeback_lock);
|
init_rwsem(&dc->writeback_lock);
|
||||||
|
@ -494,14 +494,20 @@ int bch_cached_dev_writeback_init(struct cached_dev *dc)
|
||||||
dc->writeback_rate_d_term = 30;
|
dc->writeback_rate_d_term = 30;
|
||||||
dc->writeback_rate_p_term_inverse = 6000;
|
dc->writeback_rate_p_term_inverse = 6000;
|
||||||
|
|
||||||
|
INIT_DELAYED_WORK(&dc->writeback_rate_update, update_writeback_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bch_cached_dev_writeback_start(struct cached_dev *dc)
|
||||||
|
{
|
||||||
dc->writeback_thread = kthread_create(bch_writeback_thread, dc,
|
dc->writeback_thread = kthread_create(bch_writeback_thread, dc,
|
||||||
"bcache_writeback");
|
"bcache_writeback");
|
||||||
if (IS_ERR(dc->writeback_thread))
|
if (IS_ERR(dc->writeback_thread))
|
||||||
return PTR_ERR(dc->writeback_thread);
|
return PTR_ERR(dc->writeback_thread);
|
||||||
|
|
||||||
INIT_DELAYED_WORK(&dc->writeback_rate_update, update_writeback_rate);
|
|
||||||
schedule_delayed_work(&dc->writeback_rate_update,
|
schedule_delayed_work(&dc->writeback_rate_update,
|
||||||
dc->writeback_rate_update_seconds * HZ);
|
dc->writeback_rate_update_seconds * HZ);
|
||||||
|
|
||||||
|
bch_writeback_queue(dc);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ static inline void bch_writeback_add(struct cached_dev *dc)
|
||||||
void bcache_dev_sectors_dirty_add(struct cache_set *, unsigned, uint64_t, int);
|
void bcache_dev_sectors_dirty_add(struct cache_set *, unsigned, uint64_t, int);
|
||||||
|
|
||||||
void bch_sectors_dirty_init(struct cached_dev *dc);
|
void bch_sectors_dirty_init(struct cached_dev *dc);
|
||||||
int bch_cached_dev_writeback_init(struct cached_dev *);
|
void bch_cached_dev_writeback_init(struct cached_dev *);
|
||||||
|
int bch_cached_dev_writeback_start(struct cached_dev *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -148,11 +148,13 @@ TRACE_EVENT(bcache_read,
|
||||||
);
|
);
|
||||||
|
|
||||||
TRACE_EVENT(bcache_write,
|
TRACE_EVENT(bcache_write,
|
||||||
TP_PROTO(struct bio *bio, bool writeback, bool bypass),
|
TP_PROTO(struct cache_set *c, u64 inode, struct bio *bio,
|
||||||
TP_ARGS(bio, writeback, bypass),
|
bool writeback, bool bypass),
|
||||||
|
TP_ARGS(c, inode, bio, writeback, bypass),
|
||||||
|
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__field(dev_t, dev )
|
__array(char, uuid, 16 )
|
||||||
|
__field(u64, inode )
|
||||||
__field(sector_t, sector )
|
__field(sector_t, sector )
|
||||||
__field(unsigned int, nr_sector )
|
__field(unsigned int, nr_sector )
|
||||||
__array(char, rwbs, 6 )
|
__array(char, rwbs, 6 )
|
||||||
|
@ -161,7 +163,8 @@ TRACE_EVENT(bcache_write,
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
__entry->dev = bio->bi_bdev->bd_dev;
|
memcpy(__entry->uuid, c->sb.set_uuid, 16);
|
||||||
|
__entry->inode = inode;
|
||||||
__entry->sector = bio->bi_iter.bi_sector;
|
__entry->sector = bio->bi_iter.bi_sector;
|
||||||
__entry->nr_sector = bio->bi_iter.bi_size >> 9;
|
__entry->nr_sector = bio->bi_iter.bi_size >> 9;
|
||||||
blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
|
blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
|
||||||
|
@ -169,8 +172,8 @@ TRACE_EVENT(bcache_write,
|
||||||
__entry->bypass = bypass;
|
__entry->bypass = bypass;
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk("%d,%d %s %llu + %u hit %u bypass %u",
|
TP_printk("%pU inode %llu %s %llu + %u hit %u bypass %u",
|
||||||
MAJOR(__entry->dev), MINOR(__entry->dev),
|
__entry->uuid, __entry->inode,
|
||||||
__entry->rwbs, (unsigned long long)__entry->sector,
|
__entry->rwbs, (unsigned long long)__entry->sector,
|
||||||
__entry->nr_sector, __entry->writeback, __entry->bypass)
|
__entry->nr_sector, __entry->writeback, __entry->bypass)
|
||||||
);
|
);
|
||||||
|
@ -258,9 +261,9 @@ DEFINE_EVENT(btree_node, bcache_btree_node_alloc,
|
||||||
TP_ARGS(b)
|
TP_ARGS(b)
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_EVENT(btree_node, bcache_btree_node_alloc_fail,
|
DEFINE_EVENT(cache_set, bcache_btree_node_alloc_fail,
|
||||||
TP_PROTO(struct btree *b),
|
TP_PROTO(struct cache_set *c),
|
||||||
TP_ARGS(b)
|
TP_ARGS(c)
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_EVENT(btree_node, bcache_btree_node_free,
|
DEFINE_EVENT(btree_node, bcache_btree_node_free,
|
||||||
|
|
Loading…
Reference in New Issue