summaryrefslogtreecommitdiff
path: root/libbcachefs/buckets.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/buckets.c')
-rw-r--r--libbcachefs/buckets.c286
1 files changed, 155 insertions, 131 deletions
diff --git a/libbcachefs/buckets.c b/libbcachefs/buckets.c
index 9f09e5be..3cfe684a 100644
--- a/libbcachefs/buckets.c
+++ b/libbcachefs/buckets.c
@@ -495,9 +495,11 @@ void bch2_dev_usage_from_buckets(struct bch_fs *c)
buckets = bucket_array(ca);
+ preempt_disable();
for_each_bucket(g, buckets)
bch2_dev_usage_update(c, ca, c->usage_base,
old, g->mark, false);
+ preempt_enable();
}
}
@@ -544,6 +546,67 @@ static inline void update_cached_sectors(struct bch_fs *c,
update_replicas(c, fs_usage, &r.e, sectors);
}
+static struct replicas_delta_list *
+replicas_deltas_realloc(struct btree_trans *trans, unsigned more)
+{
+ struct replicas_delta_list *d = trans->fs_usage_deltas;
+ unsigned new_size = d ? (d->size + more) * 2 : 128;
+
+ if (!d || d->used + more > d->size) {
+ d = krealloc(d, sizeof(*d) + new_size, GFP_NOIO|__GFP_ZERO);
+ BUG_ON(!d);
+
+ d->size = new_size;
+ trans->fs_usage_deltas = d;
+ }
+ return d;
+}
+
+static inline void update_replicas_list(struct btree_trans *trans,
+ struct bch_replicas_entry *r,
+ s64 sectors)
+{
+ struct replicas_delta_list *d;
+ struct replicas_delta *n;
+ unsigned b = replicas_entry_bytes(r) + 8;
+
+ d = replicas_deltas_realloc(trans, b);
+
+ n = (void *) d->d + d->used;
+ n->delta = sectors;
+ memcpy(&n->r, r, replicas_entry_bytes(r));
+ d->used += b;
+}
+
+static inline void update_cached_sectors_list(struct btree_trans *trans,
+ unsigned dev, s64 sectors)
+{
+ struct bch_replicas_padded r;
+
+ bch2_replicas_entry_cached(&r.e, dev);
+
+ update_replicas_list(trans, &r.e, sectors);
+}
+
+void bch2_replicas_delta_list_apply(struct bch_fs *c,
+ struct bch_fs_usage *fs_usage,
+ struct replicas_delta_list *r)
+{
+ struct replicas_delta *d = r->d;
+ struct replicas_delta *top = (void *) r->d + r->used;
+
+ acc_u64s((u64 *) fs_usage,
+ (u64 *) &r->fs_usage, sizeof(*fs_usage) / sizeof(u64));
+
+ while (d != top) {
+ BUG_ON((void *) d > (void *) top);
+
+ update_replicas(c, fs_usage, &d->r, d->delta);
+
+ d = (void *) d + replicas_entry_bytes(&d->r) + 8;
+ }
+}
+
#define do_mark_fn(fn, c, pos, flags, ...) \
({ \
int gc, ret = 0; \
@@ -623,23 +686,20 @@ void bch2_mark_alloc_bucket(struct bch_fs *c, struct bch_dev *ca,
}
static int bch2_mark_alloc(struct bch_fs *c, struct bkey_s_c k,
- bool inserting,
struct bch_fs_usage *fs_usage,
- unsigned journal_seq, unsigned flags,
- bool gc)
+ u64 journal_seq, unsigned flags)
{
+ bool gc = flags & BCH_BUCKET_MARK_GC;
struct bkey_alloc_unpacked u;
struct bch_dev *ca;
struct bucket *g;
struct bucket_mark old, m;
- if (!inserting)
- return 0;
-
/*
* alloc btree is read in by bch2_alloc_read, not gc:
*/
- if (flags & BCH_BUCKET_MARK_GC)
+ if ((flags & BCH_BUCKET_MARK_GC) &&
+ !(flags & BCH_BUCKET_MARK_BUCKET_INVALIDATE))
return 0;
ca = bch_dev_bkey_exists(c, k.k->p.inode);
@@ -650,18 +710,21 @@ static int bch2_mark_alloc(struct bch_fs *c, struct bkey_s_c k,
g = __bucket(ca, k.k->p.offset, gc);
u = bch2_alloc_unpack(k);
- old = bucket_data_cmpxchg(c, ca, fs_usage, g, m, ({
+ old = bucket_cmpxchg(g, m, ({
m.gen = u.gen;
m.data_type = u.data_type;
m.dirty_sectors = u.dirty_sectors;
m.cached_sectors = u.cached_sectors;
- if (!(flags & BCH_BUCKET_MARK_GC)) {
+ if (journal_seq) {
m.journal_seq_valid = 1;
m.journal_seq = journal_seq;
}
}));
+ if (!(flags & BCH_BUCKET_MARK_ALLOC_READ))
+ bch2_dev_usage_update(c, ca, fs_usage, old, m, gc);
+
g->io_time[READ] = u.read_time;
g->io_time[WRITE] = u.write_time;
g->oldest_gen = u.oldest_gen;
@@ -672,7 +735,8 @@ static int bch2_mark_alloc(struct bch_fs *c, struct bkey_s_c k,
* not:
*/
- if (old.cached_sectors) {
+ if ((flags & BCH_BUCKET_MARK_BUCKET_INVALIDATE) &&
+ old.cached_sectors) {
update_cached_sectors(c, fs_usage, ca->dev_idx,
-old.cached_sectors);
trace_invalidate(ca, bucket_to_sector(ca, k.k->p.offset),
@@ -759,11 +823,12 @@ static s64 ptr_disk_sectors_delta(struct extent_ptr_decoded p,
static void bucket_set_stripe(struct bch_fs *c,
const struct bch_stripe *v,
- bool enabled,
struct bch_fs_usage *fs_usage,
u64 journal_seq,
- bool gc)
+ unsigned flags)
{
+ bool enabled = !(flags & BCH_BUCKET_MARK_OVERWRITE);
+ bool gc = flags & BCH_BUCKET_MARK_GC;
unsigned i;
for (i = 0; i < v->nr_blocks; i++) {
@@ -789,9 +854,9 @@ static bool bch2_mark_pointer(struct bch_fs *c,
struct extent_ptr_decoded p,
s64 sectors, enum bch_data_type data_type,
struct bch_fs_usage *fs_usage,
- unsigned journal_seq, unsigned flags,
- bool gc)
+ u64 journal_seq, unsigned flags)
{
+ bool gc = flags & BCH_BUCKET_MARK_GC;
struct bucket_mark old, new;
struct bch_dev *ca = bch_dev_bkey_exists(c, p.ptr.dev);
struct bucket *g = PTR_BUCKET(ca, &p.ptr, gc);
@@ -858,9 +923,9 @@ static int bch2_mark_stripe_ptr(struct bch_fs *c,
struct bch_extent_stripe_ptr p,
enum bch_data_type data_type,
struct bch_fs_usage *fs_usage,
- s64 sectors, unsigned flags,
- bool gc)
+ s64 sectors, unsigned flags)
{
+ bool gc = flags & BCH_BUCKET_MARK_GC;
struct stripe *m;
unsigned old, new, nr_data;
int blocks_nonempty_delta;
@@ -913,8 +978,7 @@ static int bch2_mark_stripe_ptr(struct bch_fs *c,
static int bch2_mark_extent(struct bch_fs *c, struct bkey_s_c k,
s64 sectors, enum bch_data_type data_type,
struct bch_fs_usage *fs_usage,
- unsigned journal_seq, unsigned flags,
- bool gc)
+ unsigned journal_seq, unsigned flags)
{
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
const union bch_extent_entry *entry;
@@ -935,7 +999,7 @@ static int bch2_mark_extent(struct bch_fs *c, struct bkey_s_c k,
? sectors
: ptr_disk_sectors_delta(p, sectors);
bool stale = bch2_mark_pointer(c, p, disk_sectors, data_type,
- fs_usage, journal_seq, flags, gc);
+ fs_usage, journal_seq, flags);
if (p.ptr.cached) {
if (disk_sectors && !stale)
@@ -948,7 +1012,7 @@ static int bch2_mark_extent(struct bch_fs *c, struct bkey_s_c k,
for (i = 0; i < p.ec_nr; i++) {
ret = bch2_mark_stripe_ptr(c, p.ec[i],
data_type, fs_usage,
- disk_sectors, flags, gc);
+ disk_sectors, flags);
if (ret)
return ret;
}
@@ -964,11 +1028,10 @@ static int bch2_mark_extent(struct bch_fs *c, struct bkey_s_c k,
}
static int bch2_mark_stripe(struct bch_fs *c, struct bkey_s_c k,
- bool inserting,
struct bch_fs_usage *fs_usage,
- u64 journal_seq, unsigned flags,
- bool gc)
+ u64 journal_seq, unsigned flags)
{
+ bool gc = flags & BCH_BUCKET_MARK_GC;
struct bkey_s_c_stripe s = bkey_s_c_to_stripe(k);
size_t idx = s.k->p.offset;
struct stripe *m = genradix_ptr(&c->stripes[gc], idx);
@@ -976,19 +1039,14 @@ static int bch2_mark_stripe(struct bch_fs *c, struct bkey_s_c k,
spin_lock(&c->ec_stripes_heap_lock);
- if (!m || (!inserting && !m->alive)) {
+ if (!m || ((flags & BCH_BUCKET_MARK_OVERWRITE) && !m->alive)) {
spin_unlock(&c->ec_stripes_heap_lock);
bch_err_ratelimited(c, "error marking nonexistent stripe %zu",
idx);
return -1;
}
- if (!gc && m->alive)
- bch2_stripes_heap_del(c, m, idx);
-
- memset(m, 0, sizeof(*m));
-
- if (inserting) {
+ if (!(flags & BCH_BUCKET_MARK_OVERWRITE)) {
m->sectors = le16_to_cpu(s.v->sectors);
m->algorithm = s.v->algorithm;
m->nr_blocks = s.v->nr_blocks;
@@ -996,11 +1054,11 @@ static int bch2_mark_stripe(struct bch_fs *c, struct bkey_s_c k,
bch2_bkey_to_replicas(&m->r.e, k);
- /*
- * XXX: account for stripes somehow here
- */
+ /*
+ * XXX: account for stripes somehow here
+ */
#if 0
- update_replicas(c, fs_usage, &m->r.e, stripe_sectors);
+ update_replicas(c, fs_usage, &m->r.e, stripe_sectors);
#endif
/* gc recalculates these fields: */
@@ -1013,53 +1071,54 @@ static int bch2_mark_stripe(struct bch_fs *c, struct bkey_s_c k,
}
if (!gc)
- bch2_stripes_heap_insert(c, m, idx);
- else
- m->alive = true;
+ bch2_stripes_heap_update(c, m, idx);
+ m->alive = true;
+ } else {
+ if (!gc)
+ bch2_stripes_heap_del(c, m, idx);
+ memset(m, 0, sizeof(*m));
}
spin_unlock(&c->ec_stripes_heap_lock);
- bucket_set_stripe(c, s.v, inserting, fs_usage, 0, gc);
+ bucket_set_stripe(c, s.v, fs_usage, 0, flags);
return 0;
}
int bch2_mark_key_locked(struct bch_fs *c,
- struct bkey_s_c k,
- bool inserting, s64 sectors,
+ struct bkey_s_c k, s64 sectors,
struct bch_fs_usage *fs_usage,
u64 journal_seq, unsigned flags)
{
- bool gc = flags & BCH_BUCKET_MARK_GC;
int ret = 0;
preempt_disable();
- if (!fs_usage || gc)
- fs_usage = fs_usage_ptr(c, journal_seq, gc);
+ if (!fs_usage || (flags & BCH_BUCKET_MARK_GC))
+ fs_usage = fs_usage_ptr(c, journal_seq,
+ flags & BCH_BUCKET_MARK_GC);
switch (k.k->type) {
case KEY_TYPE_alloc:
- ret = bch2_mark_alloc(c, k, inserting,
- fs_usage, journal_seq, flags, gc);
+ ret = bch2_mark_alloc(c, k, fs_usage, journal_seq, flags);
break;
case KEY_TYPE_btree_ptr:
- ret = bch2_mark_extent(c, k, inserting
- ? c->opts.btree_node_size
- : -c->opts.btree_node_size,
- BCH_DATA_BTREE,
- fs_usage, journal_seq, flags, gc);
+ sectors = !(flags & BCH_BUCKET_MARK_OVERWRITE)
+ ? c->opts.btree_node_size
+ : -c->opts.btree_node_size;
+
+ ret = bch2_mark_extent(c, k, sectors, BCH_DATA_BTREE,
+ fs_usage, journal_seq, flags);
break;
case KEY_TYPE_extent:
ret = bch2_mark_extent(c, k, sectors, BCH_DATA_USER,
- fs_usage, journal_seq, flags, gc);
+ fs_usage, journal_seq, flags);
break;
case KEY_TYPE_stripe:
- ret = bch2_mark_stripe(c, k, inserting,
- fs_usage, journal_seq, flags, gc);
+ ret = bch2_mark_stripe(c, k, fs_usage, journal_seq, flags);
break;
case KEY_TYPE_inode:
- if (inserting)
+ if (!(flags & BCH_BUCKET_MARK_OVERWRITE))
fs_usage->nr_inodes++;
else
fs_usage->nr_inodes--;
@@ -1083,14 +1142,14 @@ int bch2_mark_key_locked(struct bch_fs *c,
}
int bch2_mark_key(struct bch_fs *c, struct bkey_s_c k,
- bool inserting, s64 sectors,
+ s64 sectors,
struct bch_fs_usage *fs_usage,
u64 journal_seq, unsigned flags)
{
int ret;
percpu_down_read_preempt_disable(&c->mark_lock);
- ret = bch2_mark_key_locked(c, k, inserting, sectors,
+ ret = bch2_mark_key_locked(c, k, sectors,
fs_usage, journal_seq, flags);
percpu_up_read_preempt_enable(&c->mark_lock);
@@ -1130,9 +1189,9 @@ inline int bch2_mark_overwrite(struct btree_trans *trans,
sectors = old.k->p.offset - new->k.p.offset;
BUG_ON(sectors <= 0);
- bch2_mark_key_locked(c, old, true, sectors,
+ bch2_mark_key_locked(c, old, sectors,
fs_usage, trans->journal_res.seq,
- flags);
+ BCH_BUCKET_MARK_INSERT|flags);
sectors = bkey_start_offset(&new->k) -
old.k->p.offset;
@@ -1142,8 +1201,9 @@ inline int bch2_mark_overwrite(struct btree_trans *trans,
BUG_ON(sectors >= 0);
}
- return bch2_mark_key_locked(c, old, false, sectors, fs_usage,
- trans->journal_res.seq, flags) ?: 1;
+ return bch2_mark_key_locked(c, old, sectors, fs_usage,
+ trans->journal_res.seq,
+ BCH_BUCKET_MARK_OVERWRITE|flags) ?: 1;
}
int bch2_mark_update(struct btree_trans *trans,
@@ -1162,10 +1222,11 @@ int bch2_mark_update(struct btree_trans *trans,
return 0;
if (!(trans->flags & BTREE_INSERT_NOMARK_INSERT))
- bch2_mark_key_locked(c, bkey_i_to_s_c(insert->k), true,
+ bch2_mark_key_locked(c, bkey_i_to_s_c(insert->k),
bpos_min(insert->k->k.p, b->key.k.p).offset -
bkey_start_offset(&insert->k->k),
- fs_usage, trans->journal_res.seq, flags);
+ fs_usage, trans->journal_res.seq,
+ BCH_BUCKET_MARK_INSERT|flags);
if (unlikely(trans->flags & BTREE_INSERT_NOMARK_OVERWRITES))
return 0;
@@ -1246,46 +1307,6 @@ void bch2_trans_fs_usage_apply(struct btree_trans *trans,
/* trans_mark: */
-static inline void update_replicas_list(struct replicas_delta_list *d,
- struct bch_replicas_entry *r,
- s64 sectors)
-{
- d->top->delta = sectors;
- memcpy(&d->top->r, r, replicas_entry_bytes(r));
-
- d->top = (void *) d->top + replicas_entry_bytes(r) + 8;
-
- BUG_ON((void *) d->top > (void *) d->d + sizeof(d->pad));
-}
-
-static inline void update_cached_sectors_list(struct replicas_delta_list *d,
- unsigned dev, s64 sectors)
-{
- struct bch_replicas_padded r;
-
- bch2_replicas_entry_cached(&r.e, dev);
-
- update_replicas_list(d, &r.e, sectors);
-}
-
-void bch2_replicas_delta_list_apply(struct bch_fs *c,
- struct bch_fs_usage *fs_usage,
- struct replicas_delta_list *r)
-{
- struct replicas_delta *d = r->d;
-
- acc_u64s((u64 *) fs_usage,
- (u64 *) &r->fs_usage, sizeof(*fs_usage) / sizeof(u64));
-
- while (d != r->top) {
- BUG_ON((void *) d > (void *) r->top);
-
- update_replicas(c, fs_usage, &d->r, d->delta);
-
- d = (void *) d + replicas_entry_bytes(&d->r) + 8;
- }
-}
-
static int trans_get_key(struct btree_trans *trans,
enum btree_id btree_id, struct bpos pos,
struct btree_insert_entry **insert,
@@ -1347,8 +1368,7 @@ static int trans_update_key(struct btree_trans *trans,
static int bch2_trans_mark_pointer(struct btree_trans *trans,
struct extent_ptr_decoded p,
- s64 sectors, enum bch_data_type data_type,
- struct replicas_delta_list *d)
+ s64 sectors, enum bch_data_type data_type)
{
struct bch_fs *c = trans->c;
struct bch_dev *ca = bch_dev_bkey_exists(c, p.ptr.dev);
@@ -1409,8 +1429,7 @@ out:
static int bch2_trans_mark_stripe_ptr(struct btree_trans *trans,
struct bch_extent_stripe_ptr p,
- s64 sectors, enum bch_data_type data_type,
- struct replicas_delta_list *d)
+ s64 sectors, enum bch_data_type data_type)
{
struct bch_replicas_padded r;
struct btree_insert_entry *insert;
@@ -1455,7 +1474,7 @@ static int bch2_trans_mark_stripe_ptr(struct btree_trans *trans,
bch2_bkey_to_replicas(&r.e, s.s_c);
- update_replicas_list(d, &r.e, sectors);
+ update_replicas_list(trans, &r.e, sectors);
out:
bch2_trans_iter_put(trans, iter);
return ret;
@@ -1463,8 +1482,7 @@ out:
static int bch2_trans_mark_extent(struct btree_trans *trans,
struct bkey_s_c k,
- s64 sectors, enum bch_data_type data_type,
- struct replicas_delta_list *d)
+ s64 sectors, enum bch_data_type data_type)
{
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
const union bch_extent_entry *entry;
@@ -1487,7 +1505,7 @@ static int bch2_trans_mark_extent(struct btree_trans *trans,
: ptr_disk_sectors_delta(p, sectors);
ret = bch2_trans_mark_pointer(trans, p, disk_sectors,
- data_type, d);
+ data_type);
if (ret < 0)
return ret;
@@ -1495,7 +1513,7 @@ static int bch2_trans_mark_extent(struct btree_trans *trans,
if (p.ptr.cached) {
if (disk_sectors && !stale)
- update_cached_sectors_list(d, p.ptr.dev,
+ update_cached_sectors_list(trans, p.ptr.dev,
disk_sectors);
} else if (!p.ec_nr) {
dirty_sectors += disk_sectors;
@@ -1503,7 +1521,7 @@ static int bch2_trans_mark_extent(struct btree_trans *trans,
} else {
for (i = 0; i < p.ec_nr; i++) {
ret = bch2_trans_mark_stripe_ptr(trans, p.ec[i],
- disk_sectors, data_type, d);
+ disk_sectors, data_type);
if (ret)
return ret;
}
@@ -1513,29 +1531,32 @@ static int bch2_trans_mark_extent(struct btree_trans *trans,
}
if (dirty_sectors)
- update_replicas_list(d, &r.e, dirty_sectors);
+ update_replicas_list(trans, &r.e, dirty_sectors);
return 0;
}
-int bch2_trans_mark_key(struct btree_trans *trans,
- struct bkey_s_c k,
- bool inserting, s64 sectors,
- struct replicas_delta_list *d)
+int bch2_trans_mark_key(struct btree_trans *trans, struct bkey_s_c k,
+ s64 sectors, unsigned flags)
{
+ struct replicas_delta_list *d;
struct bch_fs *c = trans->c;
switch (k.k->type) {
case KEY_TYPE_btree_ptr:
- return bch2_trans_mark_extent(trans, k, inserting
- ? c->opts.btree_node_size
- : -c->opts.btree_node_size,
- BCH_DATA_BTREE, d);
+ sectors = !(flags & BCH_BUCKET_MARK_OVERWRITE)
+ ? c->opts.btree_node_size
+ : -c->opts.btree_node_size;
+
+ return bch2_trans_mark_extent(trans, k, sectors,
+ BCH_DATA_BTREE);
case KEY_TYPE_extent:
- return bch2_trans_mark_extent(trans, k,
- sectors, BCH_DATA_USER, d);
+ return bch2_trans_mark_extent(trans, k, sectors,
+ BCH_DATA_USER);
case KEY_TYPE_inode:
- if (inserting)
+ d = replicas_deltas_realloc(trans, 0);
+
+ if (!(flags & BCH_BUCKET_MARK_OVERWRITE))
d->fs_usage.nr_inodes++;
else
d->fs_usage.nr_inodes--;
@@ -1543,6 +1564,8 @@ int bch2_trans_mark_key(struct btree_trans *trans,
case KEY_TYPE_reservation: {
unsigned replicas = bkey_s_c_to_reservation(k).v->nr_replicas;
+ d = replicas_deltas_realloc(trans, 0);
+
sectors *= replicas;
replicas = clamp_t(unsigned, replicas, 1,
ARRAY_SIZE(d->fs_usage.persistent_reserved));
@@ -1557,8 +1580,7 @@ int bch2_trans_mark_key(struct btree_trans *trans,
}
int bch2_trans_mark_update(struct btree_trans *trans,
- struct btree_insert_entry *insert,
- struct replicas_delta_list *d)
+ struct btree_insert_entry *insert)
{
struct btree_iter *iter = insert->iter;
struct btree *b = iter->l[0].b;
@@ -1570,9 +1592,10 @@ int bch2_trans_mark_update(struct btree_trans *trans,
return 0;
ret = bch2_trans_mark_key(trans,
- bkey_i_to_s_c(insert->k), true,
+ bkey_i_to_s_c(insert->k),
bpos_min(insert->k->k.p, b->key.k.p).offset -
- bkey_start_offset(&insert->k->k), d);
+ bkey_start_offset(&insert->k->k),
+ BCH_BUCKET_MARK_INSERT);
if (ret)
return ret;
@@ -1606,8 +1629,8 @@ int bch2_trans_mark_update(struct btree_trans *trans,
sectors = k.k->p.offset - insert->k->k.p.offset;
BUG_ON(sectors <= 0);
- ret = bch2_trans_mark_key(trans, k, true,
- sectors, d);
+ ret = bch2_trans_mark_key(trans, k, sectors,
+ BCH_BUCKET_MARK_INSERT);
if (ret)
return ret;
@@ -1619,7 +1642,8 @@ int bch2_trans_mark_update(struct btree_trans *trans,
BUG_ON(sectors >= 0);
}
- ret = bch2_trans_mark_key(trans, k, false, sectors, d);
+ ret = bch2_trans_mark_key(trans, k, sectors,
+ BCH_BUCKET_MARK_OVERWRITE);
if (ret)
return ret;