diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/bcachefs_format.h | 1 | ||||
-rw-r--r-- | fs/bcachefs/buckets.c | 118 | ||||
-rw-r--r-- | fs/bcachefs/buckets.h | 6 | ||||
-rw-r--r-- | fs/bcachefs/extents.c | 12 | ||||
-rw-r--r-- | fs/bcachefs/sysfs.c | 4 |
5 files changed, 99 insertions, 42 deletions
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h index f1814f4caf21..1616ab2678fb 100644 --- a/fs/bcachefs/bcachefs_format.h +++ b/fs/bcachefs/bcachefs_format.h @@ -827,6 +827,7 @@ enum { enum { BCH_ALLOC_FIELD_READ_TIME = 0, BCH_ALLOC_FIELD_WRITE_TIME = 1, + /* XXX last_gc has to be persistent too */ }; struct bch_alloc { diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c index 3a3f6ffee72a..478f7f5b3d58 100644 --- a/fs/bcachefs/buckets.c +++ b/fs/bcachefs/buckets.c @@ -73,6 +73,15 @@ #include <linux/preempt.h> #include <trace/events/bcachefs.h> +#define bch2_usage_add(_acc, _stats) \ +do { \ + typeof(_acc) _a = (_acc), _s = (_stats); \ + unsigned i; \ + \ + for (i = 0; i < sizeof(*_a) / sizeof(u64); i++) \ + ((u64 *) (_a))[i] += ((u64 *) (_s))[i]; \ +} while (0) + static inline u64 __bch2_fs_sectors_used(struct bch_fs *, struct bch_fs_usage); static inline int is_unavailable_bucket(struct bucket_mark m) @@ -121,12 +130,28 @@ static inline void __dev_usage_update(struct bch_dev *ca, is_fragmented_bucket(new, ca) - is_fragmented_bucket(old, ca); } +void bch2_dev_usage_verify_full(struct bch_dev *ca) +{ + struct bch_dev_usage s1 = __bch2_dev_usage_read(ca), s2 = { 0 }; + struct bucket_array *buckets = bucket_array(ca); + struct bucket_mark zero_mark; + struct bucket *g; + + memset(&zero_mark, 0, sizeof(zero_mark)); + + for_each_bucket(g, buckets) + __dev_usage_update(ca, &s2, zero_mark, g->mark); + + BUG_ON(memcmp(&s1, &s2, sizeof(s1))); +} + #ifdef DEBUG_BUCKETS static void bch2_fs_usage_verify(struct bch_fs *c) { - struct bch_fs_usage stats = - __bch2_fs_usage_read(c); + struct bch_fs_usage stats = __bch2_fs_usage_read(c); + struct bch_dev_usage dev_u = { 0 }; + struct bch_dev *ca; unsigned i, j; for (i = 0; i < ARRAY_SIZE(stats.replicas); i++) { @@ -153,21 +178,31 @@ static void bch2_fs_usage_verify(struct bch_fs *c) if ((s64) stats.online_reserved < 0) panic("sectors_online_reserved underflow: %lli\n", stats.online_reserved); -} -static void bch2_dev_usage_verify_full(struct bch_dev *ca) -{ - struct bch_dev_usage s1 = __bch2_dev_usage_read(ca), s2 = { 0 }; - struct bucket_array *buckets = bucket_array(ca); - struct bucket_mark zero_mark; - struct bucket *g; + for_each_member_device(ca, c, i) { + struct bch_dev_usage a = __bch2_dev_usage_read(ca); - memset(&zero_mark, 0, sizeof(zero_mark)); + bch2_usage_add(&dev_u, &a); + } - for_each_bucket(g, buckets) - __dev_usage_update(ca, &s2, zero_mark, g->mark); + /* XXX: not currently correct if compression is enabled */ + for (i = 0; i < BCH_DATA_NR; i++) { + u64 a = 0; - BUG_ON(memcmp(&s1, &s2, sizeof(s1))); + /* + * btree nodes that are pending delete aren't counted under fs + * usage, but are under dev usage... + */ + if (i == BCH_DATA_BTREE) + continue; + + for (j = 0; j < ARRAY_SIZE(stats.replicas); j++) + a += stats.replicas[j].data[i]; + + if (a != dev_u.sectors[i]) + panic("data type %s: got %llu should be %llu\n", + bch2_data_types[i], a, dev_u.sectors[i]); + } } static void bch2_dev_usage_verify(struct bch_dev *ca) @@ -185,8 +220,6 @@ static void bch2_dev_usage_verify(struct bch_dev *ca) if (expensive_debug_checks(ca->fs)) bch2_dev_usage_verify_full(ca); - - bch2_fs_usage_verify(ca->fs); } static void bch2_disk_reservations_verify(struct bch_fs *c, int flags) @@ -251,15 +284,6 @@ void bch2_bucket_seq_cleanup(struct bch_fs *c) } } -#define bch2_usage_add(_acc, _stats) \ -do { \ - typeof(_acc) _a = (_acc), _s = (_stats); \ - unsigned i; \ - \ - for (i = 0; i < sizeof(*_a) / sizeof(u64); i++) \ - ((u64 *) (_a))[i] += ((u64 *) (_s))[i]; \ -} while (0) - #define bch2_usage_read_raw(_stats) \ ({ \ typeof(*this_cpu_ptr(_stats)) _acc; \ @@ -381,10 +405,10 @@ static bool bucket_became_unavailable(struct bch_fs *c, (!c || c->gc_pos.phase == GC_PHASE_DONE); } -void bch2_fs_usage_apply(struct bch_fs *c, - struct bch_fs_usage *stats, - struct disk_reservation *disk_res, - struct gc_pos gc_pos) +void __bch2_fs_usage_apply(struct bch_fs *c, + struct bch_fs_usage *stats, + struct disk_reservation *disk_res, + struct gc_pos gc_pos) { struct fs_usage_sum sum = __fs_usage_sum(*stats); s64 added = sum.data + sum.reserved; @@ -400,8 +424,6 @@ void bch2_fs_usage_apply(struct bch_fs *c, stats->online_reserved -= added; } - percpu_down_read_preempt_disable(&c->usage_lock); - /* online_reserved not subject to gc: */ if (likely(!gc_will_visit(c, gc_pos))) bch2_usage_add(this_cpu_ptr(c->usage_percpu), stats); @@ -409,10 +431,19 @@ void bch2_fs_usage_apply(struct bch_fs *c, this_cpu_ptr(c->usage_percpu)->online_reserved += stats->online_reserved; + memset(stats, 0, sizeof(*stats)); + bch2_fs_usage_verify(c); - percpu_up_read_preempt_enable(&c->usage_lock); +} - memset(stats, 0, sizeof(*stats)); +void bch2_fs_usage_apply(struct bch_fs *c, + struct bch_fs_usage *stats, + struct disk_reservation *disk_res, + struct gc_pos gc_pos) +{ + percpu_down_read_preempt_disable(&c->usage_lock); + __bch2_fs_usage_apply(c, stats, disk_res, gc_pos); + percpu_up_read_preempt_enable(&c->usage_lock); } static void bch2_dev_usage_update(struct bch_fs *c, struct bch_dev *ca, @@ -447,6 +478,7 @@ void bch2_invalidate_bucket(struct bch_fs *c, struct bch_dev *ca, struct bucket *g; struct bucket_mark new; + lockdep_assert_held(&c->gc_lock); percpu_rwsem_assert_held(&c->usage_lock); bch2_dev_usage_verify(ca); @@ -681,11 +713,11 @@ fs_usage: uncompressed_sectors; } -void bch2_mark_key(struct bch_fs *c, struct bkey_s_c k, - s64 sectors, enum bch_data_type data_type, - struct gc_pos pos, - struct bch_fs_usage *stats, - u64 journal_seq, unsigned flags) +void __bch2_mark_key(struct bch_fs *c, struct bkey_s_c k, + s64 sectors, enum bch_data_type data_type, + struct gc_pos pos, + struct bch_fs_usage *stats, + u64 journal_seq, unsigned flags) { unsigned replicas = bch2_extent_nr_dirty_ptrs(k); @@ -719,7 +751,6 @@ void bch2_mark_key(struct bch_fs *c, struct bkey_s_c k, * (e.g. the btree node lock, or the relevant allocator lock). */ - percpu_down_read_preempt_disable(&c->usage_lock); if (!(flags & BCH_BUCKET_MARK_GC_LOCK_HELD) && gc_will_visit(c, pos)) flags |= BCH_BUCKET_MARK_GC_WILL_VISIT; @@ -747,6 +778,17 @@ void bch2_mark_key(struct bch_fs *c, struct bkey_s_c k, sectors * replicas; break; } +} + +void bch2_mark_key(struct bch_fs *c, struct bkey_s_c k, + s64 sectors, enum bch_data_type data_type, + struct gc_pos pos, + struct bch_fs_usage *stats, + u64 journal_seq, unsigned flags) +{ + percpu_down_read_preempt_disable(&c->usage_lock); + __bch2_mark_key(c, k, sectors, data_type, pos, + stats, journal_seq, flags); percpu_up_read_preempt_enable(&c->usage_lock); } diff --git a/fs/bcachefs/buckets.h b/fs/bcachefs/buckets.h index 3a6b31d40b73..e37a6207fac5 100644 --- a/fs/bcachefs/buckets.h +++ b/fs/bcachefs/buckets.h @@ -144,6 +144,8 @@ static inline bool bucket_unused(struct bucket_mark mark) /* Device usage: */ +void bch2_dev_usage_verify_full(struct bch_dev *); + struct bch_dev_usage __bch2_dev_usage_read(struct bch_dev *); struct bch_dev_usage bch2_dev_usage_read(struct bch_fs *, struct bch_dev *); @@ -185,6 +187,8 @@ static inline u64 dev_buckets_free(struct bch_fs *c, struct bch_dev *ca) struct bch_fs_usage __bch2_fs_usage_read(struct bch_fs *); struct bch_fs_usage bch2_fs_usage_read(struct bch_fs *); +void __bch2_fs_usage_apply(struct bch_fs *, struct bch_fs_usage *, + struct disk_reservation *, struct gc_pos); void bch2_fs_usage_apply(struct bch_fs *, struct bch_fs_usage *, struct disk_reservation *, struct gc_pos); @@ -219,6 +223,8 @@ void bch2_mark_metadata_bucket(struct bch_fs *, struct bch_dev *, #define BCH_BUCKET_MARK_GC_WILL_VISIT (1 << 2) #define BCH_BUCKET_MARK_GC_LOCK_HELD (1 << 3) +void __bch2_mark_key(struct bch_fs *, struct bkey_s_c, s64, enum bch_data_type, + struct gc_pos, struct bch_fs_usage *, u64, unsigned); void bch2_mark_key(struct bch_fs *, struct bkey_s_c, s64, enum bch_data_type, struct gc_pos, struct bch_fs_usage *, u64, unsigned); diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c index be4dd2307a43..28de20cccd92 100644 --- a/fs/bcachefs/extents.c +++ b/fs/bcachefs/extents.c @@ -1071,8 +1071,8 @@ static void bch2_add_sectors(struct extent_insert_state *s, if (!sectors) return; - bch2_mark_key(c, k, sectors, BCH_DATA_USER, gc_pos_btree_node(b), - &s->stats, s->trans->journal_res.seq, 0); + __bch2_mark_key(c, k, sectors, BCH_DATA_USER, gc_pos_btree_node(b), + &s->stats, s->trans->journal_res.seq, 0); } static void bch2_subtract_sectors(struct extent_insert_state *s, @@ -1650,6 +1650,8 @@ bch2_insert_fixup_extent(struct btree_insert *trans, */ EBUG_ON(bkey_cmp(iter->pos, bkey_start_pos(&insert->k->k))); + percpu_down_read_preempt_disable(&c->usage_lock); + if (!s.deleting && !(trans->flags & BTREE_INSERT_JOURNAL_REPLAY)) bch2_add_sectors(&s, bkey_i_to_s_c(insert->k), @@ -1680,8 +1682,10 @@ bch2_insert_fixup_extent(struct btree_insert *trans, bkey_start_offset(&insert->k->k), insert->k->k.size); - bch2_fs_usage_apply(c, &s.stats, trans->disk_res, - gc_pos_btree_node(b)); + __bch2_fs_usage_apply(c, &s.stats, trans->disk_res, + gc_pos_btree_node(b)); + + percpu_up_read_preempt_enable(&c->usage_lock); EBUG_ON(bkey_cmp(iter->pos, bkey_start_pos(&insert->k->k))); EBUG_ON(bkey_cmp(iter->pos, s.committed)); diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c index b353d7cdb6cd..6ebaf1136aa7 100644 --- a/fs/bcachefs/sysfs.c +++ b/fs/bcachefs/sysfs.c @@ -767,6 +767,10 @@ static ssize_t show_dev_alloc_debug(struct bch_dev *ca, char *buf) struct bch_fs *c = ca->fs; struct bch_dev_usage stats = bch2_dev_usage_read(c, ca); + percpu_down_write(&c->usage_lock); + bch2_dev_usage_verify_full(ca); + percpu_up_write(&c->usage_lock); + return scnprintf(buf, PAGE_SIZE, "free_inc: %zu/%zu\n" "free[RESERVE_BTREE]: %zu/%zu\n" |