diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2017-12-23 00:17:48 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2018-05-22 00:44:18 -0400 |
commit | 164fc4218cc02fb8d0a5ec069b9c5b13c632fc0d (patch) | |
tree | 760995c4986b58ba6495d82315bf34e982086d27 | |
parent | e1d8a5857ab0bfe69ca772cf4f698032ad24ad04 (diff) |
bcachefs: kill bucket_data_type, improve disk usage stats
-rw-r--r-- | fs/bcachefs/alloc.c | 10 | ||||
-rw-r--r-- | fs/bcachefs/btree_gc.c | 18 | ||||
-rw-r--r-- | fs/bcachefs/buckets.c | 84 | ||||
-rw-r--r-- | fs/bcachefs/buckets.h | 5 | ||||
-rw-r--r-- | fs/bcachefs/buckets_types.h | 28 | ||||
-rw-r--r-- | fs/bcachefs/chardev.c | 9 | ||||
-rw-r--r-- | fs/bcachefs/extents.c | 22 | ||||
-rw-r--r-- | fs/bcachefs/journal.c | 3 | ||||
-rw-r--r-- | fs/bcachefs/movinggc.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/sysfs.c | 60 |
10 files changed, 89 insertions, 152 deletions
diff --git a/fs/bcachefs/alloc.c b/fs/bcachefs/alloc.c index 29799df65dbc..4b6038db40e1 100644 --- a/fs/bcachefs/alloc.c +++ b/fs/bcachefs/alloc.c @@ -109,7 +109,7 @@ static void pd_controllers_update(struct work_struct *work) u64 size = bucket_to_sector(ca, ca->mi.nbuckets - ca->mi.first_bucket) << 9; u64 dirty = bucket_to_sector(ca, - stats.buckets[S_DIRTY]) << 9; + stats.buckets[BCH_DATA_USER]) << 9; u64 free = bucket_to_sector(ca, __dev_buckets_free(ca, stats)) << 9; /* @@ -117,10 +117,10 @@ static void pd_controllers_update(struct work_struct *work) * reclaimed by copy GC */ s64 fragmented = (bucket_to_sector(ca, - stats.buckets[S_DIRTY] + - stats.buckets_cached) - - (stats.sectors[S_DIRTY] + - stats.sectors_cached)) << 9; + stats.buckets[BCH_DATA_USER] + + stats.buckets[BCH_DATA_CACHED]) - + (stats.sectors[BCH_DATA_USER] + + stats.sectors[BCH_DATA_CACHED])) << 9; fragmented = max(0LL, fragmented); diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c index 14e5e29e76dd..e8e4f6d537b9 100644 --- a/fs/bcachefs/btree_gc.c +++ b/fs/bcachefs/btree_gc.c @@ -293,16 +293,21 @@ static int bch2_gc_btree(struct bch_fs *c, enum btree_id btree_id) static void mark_metadata_sectors(struct bch_fs *c, struct bch_dev *ca, u64 start, u64 end, - enum bucket_data_type type, + enum bch_data_type type, unsigned flags) { u64 b = sector_to_bucket(ca, start); do { - bch2_mark_metadata_bucket(c, ca, ca->buckets + b, type, + unsigned sectors = + min_t(u64, bucket_to_sector(ca, b + 1), end) - start; + + bch2_mark_metadata_bucket(c, ca, ca->buckets + b, + type, sectors, gc_phase(GC_PHASE_SB), flags); b++; - } while (b < sector_to_bucket(ca, end)); + start += sectors; + } while (start < end); } void bch2_mark_dev_superblock(struct bch_fs *c, struct bch_dev *ca, @@ -319,11 +324,11 @@ void bch2_mark_dev_superblock(struct bch_fs *c, struct bch_dev *ca, if (offset == BCH_SB_SECTOR) mark_metadata_sectors(c, ca, 0, BCH_SB_SECTOR, - BUCKET_SB, flags); + BCH_DATA_SB, flags); mark_metadata_sectors(c, ca, offset, offset + (1 << layout->sb_max_size_bits), - BUCKET_SB, flags); + BCH_DATA_SB, flags); } spin_lock(&c->journal.lock); @@ -331,7 +336,8 @@ void bch2_mark_dev_superblock(struct bch_fs *c, struct bch_dev *ca, for (i = 0; i < ca->journal.nr; i++) { b = ca->journal.buckets[i]; bch2_mark_metadata_bucket(c, ca, ca->buckets + b, - BUCKET_JOURNAL, + BCH_DATA_JOURNAL, + ca->mi.bucket_size, gc_phase(GC_PHASE_SB), flags); } diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c index 849668815f17..8899e3c6e284 100644 --- a/fs/bcachefs/buckets.c +++ b/fs/bcachefs/buckets.c @@ -82,7 +82,7 @@ static void bch2_fs_stats_verify(struct bch_fs *c) __bch2_fs_usage_read(c); unsigned i; - for (i = 0; i < BCH_REPLICAS_MAX; i++) { + for (i = 0; i < ARRAY_SIZE(stats.s); i++) { if ((s64) stats.s[i].data[S_META] < 0) panic("replicas %u meta underflow: %lli\n", i + 1, stats.s[i].data[S_META]); @@ -106,10 +106,10 @@ static void bch2_dev_stats_verify(struct bch_dev *ca) struct bch_dev_usage stats = __bch2_dev_usage_read(ca); u64 n = ca->mi.nbuckets - ca->mi.first_bucket; + unsigned i; - BUG_ON(stats.buckets[S_META] > n); - BUG_ON(stats.buckets[S_DIRTY] > n); - BUG_ON(stats.buckets_cached > n); + for (i = 0; i < ARRAY_SIZE(stats.buckets); i++) + BUG_ON(stats.buckets[i] > n); BUG_ON(stats.buckets_alloc > n); BUG_ON(stats.buckets_unavailable > n); } @@ -234,7 +234,7 @@ static inline struct fs_usage_sum __fs_usage_sum(struct bch_fs_usage stats) struct fs_usage_sum sum = { 0 }; unsigned i; - for (i = 0; i < BCH_REPLICAS_MAX; i++) { + for (i = 0; i < ARRAY_SIZE(stats.s); i++) { sum.data += (stats.s[i].data[S_META] + stats.s[i].data[S_DIRTY]) * (i + 1); sum.reserved += stats.s[i].persistent_reserved * (i + 1); @@ -263,30 +263,16 @@ u64 bch2_fs_sectors_used(struct bch_fs *c, struct bch_fs_usage stats) return min(c->capacity, __bch2_fs_sectors_used(c, stats)); } -static inline int is_meta_bucket(struct bucket_mark m) -{ - return m.data_type != BUCKET_DATA; -} - -static inline int is_dirty_bucket(struct bucket_mark m) -{ - return m.data_type == BUCKET_DATA && !!m.dirty_sectors; -} - -static inline int is_cached_bucket(struct bucket_mark m) -{ - return m.data_type == BUCKET_DATA && - !m.dirty_sectors && !!m.cached_sectors; -} - static inline int is_unavailable_bucket(struct bucket_mark m) { return !is_available_bucket(m); } -static inline enum s_alloc bucket_type(struct bucket_mark m) +static inline enum bch_data_type bucket_type(struct bucket_mark m) { - return is_meta_bucket(m) ? S_META : S_DIRTY; + return m.cached_sectors && !m.dirty_sectors + ? BCH_DATA_CACHED + : m.data_type; } static bool bucket_became_unavailable(struct bch_fs *c, @@ -343,26 +329,23 @@ static void bch2_dev_usage_update(struct bch_fs *c, struct bch_dev *ca, bch2_fs_inconsistent_on(old.data_type && new.data_type && old.data_type != new.data_type, c, - "different types of metadata in same bucket: %u, %u", + "different types of data in same bucket: %u, %u", old.data_type, new.data_type); preempt_disable(); dev_usage = this_cpu_ptr(ca->usage_percpu); - dev_usage->buckets[S_META] += - is_meta_bucket(new) - is_meta_bucket(old); - dev_usage->buckets[S_DIRTY] += - is_dirty_bucket(new) - is_dirty_bucket(old); - dev_usage->buckets_cached += - is_cached_bucket(new) - is_cached_bucket(old); + dev_usage->buckets[bucket_type(old)]--; + dev_usage->buckets[bucket_type(new)]++; + dev_usage->buckets_alloc += (int) new.owned_by_allocator - (int) old.owned_by_allocator; dev_usage->buckets_unavailable += is_unavailable_bucket(new) - is_unavailable_bucket(old); - dev_usage->sectors[bucket_type(old)] -= old.dirty_sectors; - dev_usage->sectors[bucket_type(new)] += new.dirty_sectors; - dev_usage->sectors_cached += + dev_usage->sectors[old.data_type] -= old.dirty_sectors; + dev_usage->sectors[new.data_type] += new.dirty_sectors; + dev_usage->sectors[BCH_DATA_CACHED] += (int) new.cached_sectors - (int) old.cached_sectors; preempt_enable(); @@ -465,8 +448,9 @@ do { \ } while (0) void bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca, - struct bucket *g, enum bucket_data_type type, - struct gc_pos pos, unsigned flags) + struct bucket *g, enum bch_data_type type, + unsigned sectors, struct gc_pos pos, + unsigned flags) { struct bucket_mark old, new; @@ -480,20 +464,13 @@ void bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca, } old = bucket_data_cmpxchg(c, ca, g, new, ({ - saturated_add(ca, new.dirty_sectors, ca->mi.bucket_size, + saturated_add(ca, new.dirty_sectors, sectors, GC_MAX_SECTORS_USED); new.data_type = type; new.touched_this_mount = 1; })); lg_local_unlock(&c->usage_lock); - if (old.data_type != type && - (old.data_type || - old.cached_sectors || - old.dirty_sectors)) - bch_err(c, "bucket %zu has multiple types of data (%u, %u)", - g - ca->buckets, old.data_type, new.data_type); - BUG_ON(!(flags & BCH_BUCKET_MARK_MAY_MAKE_UNAVAILABLE) && bucket_became_unavailable(c, old, new)); } @@ -526,8 +503,8 @@ static void bch2_mark_pointer(struct bch_fs *c, unsigned saturated; struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev); struct bucket *g = ca->buckets + PTR_BUCKET_NR(ca, ptr); - unsigned data_type = type == S_META - ? BUCKET_BTREE : BUCKET_DATA; + enum bch_data_type data_type = type == S_META + ? BCH_DATA_BTREE : BCH_DATA_USER; u64 v; if (crc.compression_type) { @@ -609,13 +586,6 @@ static void bch2_mark_pointer(struct bch_fs *c, bch2_dev_usage_update(c, ca, g, old, new); - if (old.data_type != data_type && - (old.data_type || - old.cached_sectors || - old.dirty_sectors)) - bch_err(c, "bucket %zu has multiple types of data (%u, %u)", - g - ca->buckets, old.data_type, new.data_type); - BUG_ON(!(flags & BCH_BUCKET_MARK_MAY_MAKE_UNAVAILABLE) && bucket_became_unavailable(c, old, new)); @@ -687,17 +657,19 @@ void bch2_mark_key(struct bch_fs *c, struct bkey_s_c k, replicas += !ptr->cached; } - BUG_ON(replicas >= BCH_REPLICAS_MAX); - - if (replicas) + if (replicas) { + BUG_ON(replicas - 1 > ARRAY_SIZE(stats->s)); stats->s[replicas - 1].data[type] += sectors; + } break; } case BCH_RESERVATION: { struct bkey_s_c_reservation r = bkey_s_c_to_reservation(k); - if (r.v->nr_replicas) + if (r.v->nr_replicas) { + BUG_ON(r.v->nr_replicas - 1 > ARRAY_SIZE(stats->s)); stats->s[r.v->nr_replicas - 1].persistent_reserved += sectors; + } break; } } diff --git a/fs/bcachefs/buckets.h b/fs/bcachefs/buckets.h index 6b152da91e6a..d0a9ec08d8e8 100644 --- a/fs/bcachefs/buckets.h +++ b/fs/bcachefs/buckets.h @@ -155,7 +155,6 @@ u64 bch2_fs_sectors_used(struct bch_fs *, struct bch_fs_usage); static inline bool is_available_bucket(struct bucket_mark mark) { return (!mark.owned_by_allocator && - mark.data_type == BUCKET_DATA && !mark.dirty_sectors && !mark.nouse); } @@ -177,8 +176,8 @@ void bch2_mark_alloc_bucket(struct bch_fs *, struct bch_dev *, struct bucket *, bool, struct gc_pos, unsigned); void bch2_mark_metadata_bucket(struct bch_fs *, struct bch_dev *, - struct bucket *, enum bucket_data_type, - struct gc_pos, unsigned); + struct bucket *, enum bch_data_type, + unsigned, struct gc_pos, unsigned); #define BCH_BUCKET_MARK_NOATOMIC (1 << 0) #define BCH_BUCKET_MARK_MAY_MAKE_UNAVAILABLE (1 << 1) diff --git a/fs/bcachefs/buckets_types.h b/fs/bcachefs/buckets_types.h index 6f9b12265df3..8a3c8c304beb 100644 --- a/fs/bcachefs/buckets_types.h +++ b/fs/bcachefs/buckets_types.h @@ -3,14 +3,6 @@ #include "util.h" -/* kill, switch to bch_data_type */ -enum bucket_data_type { - BUCKET_DATA = 0, - BUCKET_BTREE, - BUCKET_JOURNAL, - BUCKET_SB, -}; - struct bucket_mark { union { struct { @@ -48,22 +40,20 @@ struct bucket { }; }; -/* kill, switch to bucket_data_type */ -enum s_alloc { - S_META, - S_DIRTY, - S_ALLOC_NR, -}; - struct bch_dev_usage { - u64 buckets[S_ALLOC_NR]; - u64 buckets_cached; + u64 buckets[BCH_DATA_NR]; u64 buckets_alloc; u64 buckets_unavailable; /* _compressed_ sectors: */ - u64 sectors[S_ALLOC_NR]; - u64 sectors_cached; + u64 sectors[BCH_DATA_NR]; +}; + +/* kill, switch to bch_data_type? */ +enum s_alloc { + S_META, + S_DIRTY, + S_ALLOC_NR, }; struct bch_fs_usage { diff --git a/fs/bcachefs/chardev.c b/fs/bcachefs/chardev.c index 4c818bb3cd09..1ab36ac9f519 100644 --- a/fs/bcachefs/chardev.c +++ b/fs/bcachefs/chardev.c @@ -350,14 +350,11 @@ static long bch2_ioctl_usage(struct bch_fs *c, percpu_ref_put(&ca->io_ref); } - for (j = 0; j < S_ALLOC_NR; j++) { - dst.buckets[s_alloc_to_data_type(j)] = src.buckets[j]; - dst.sectors[s_alloc_to_data_type(j)] = src.sectors[j]; + for (j = 0; j < BCH_DATA_NR; j++) { + dst.buckets[j] = src.buckets[j]; + dst.sectors[j] = src.sectors[j]; } - dst.buckets[BCH_DATA_CACHED] = src.buckets_cached; - dst.sectors[BCH_DATA_CACHED] = src.sectors_cached; - ret = copy_to_user(&user_arg->devs[i], &dst, sizeof(dst)); if (ret) return ret; diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c index 176978ca2231..51262d6f5afb 100644 --- a/fs/bcachefs/extents.c +++ b/fs/bcachefs/extents.c @@ -654,7 +654,7 @@ static void btree_ptr_debugcheck(struct bch_fs *c, struct btree *b, do { seq = read_seqcount_begin(&c->gc_pos_lock); bad = gc_pos_cmp(c->gc_pos, gc_pos_btree_node(b)) > 0 && - (g->mark.data_type != BUCKET_BTREE || + (g->mark.data_type != BCH_DATA_BTREE || g->mark.dirty_sectors < c->opts.btree_node_size); } while (read_seqcount_retry(&c->gc_pos_lock, seq)); @@ -1731,6 +1731,7 @@ static void bch2_extent_debugcheck_extent(struct bch_fs *c, struct btree *b, const struct bch_extent_ptr *ptr; struct bch_dev *ca; struct bucket *g; + struct bucket_mark mark; unsigned seq, stale; char buf[160]; bool bad; @@ -1764,8 +1765,6 @@ static void bch2_extent_debugcheck_extent(struct bch_fs *c, struct btree *b, stale = 0; do { - struct bucket_mark mark; - seq = read_seqcount_begin(&c->gc_pos_lock); mark = READ_ONCE(g->mark); @@ -1784,12 +1783,11 @@ static void bch2_extent_debugcheck_extent(struct bch_fs *c, struct btree *b, if (stale) break; - bad = (mark.data_type != BUCKET_DATA || - (gc_pos_cmp(c->gc_pos, gc_pos_btree_node(b)) > 0 && - !mark.owned_by_allocator && - !(ptr->cached - ? mark.cached_sectors - : mark.dirty_sectors))); + bad = gc_pos_cmp(c->gc_pos, gc_pos_btree_node(b)) > 0 && + (mark.data_type != BCH_DATA_USER || + !(ptr->cached + ? mark.cached_sectors + : mark.dirty_sectors)); } while (read_seqcount_retry(&c->gc_pos_lock, seq)); if (bad) @@ -1821,10 +1819,10 @@ bad_ptr: bch2_bkey_val_to_text(c, btree_node_type(b), buf, sizeof(buf), e.s_c); bch2_fs_bug(c, "extent pointer bad gc mark: %s:\nbucket %zu " - "gen %i last_gc %i mark 0x%08x", - buf, PTR_BUCKET_NR(ca, ptr), PTR_BUCKET(ca, ptr)->mark.gen, + "gen %i last_gc %i type %u", + buf, PTR_BUCKET_NR(ca, ptr), mark.gen, ca->oldest_gens[PTR_BUCKET_NR(ca, ptr)], - (unsigned) g->mark.counter); + mark.data_type); return; } diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c index 0f1f32b99f7a..914bc4539523 100644 --- a/fs/bcachefs/journal.c +++ b/fs/bcachefs/journal.c @@ -1631,7 +1631,8 @@ static int bch2_set_nr_journal_buckets(struct bch_fs *c, struct bch_dev *ca, spin_unlock(&j->lock); bch2_mark_metadata_bucket(c, ca, &ca->buckets[bucket], - BUCKET_JOURNAL, + BCH_DATA_JOURNAL, + ca->mi.bucket_size, gc_phase(GC_PHASE_SB), 0); bch2_open_bucket_put(c, ob); diff --git a/fs/bcachefs/movinggc.c b/fs/bcachefs/movinggc.c index 728be2ba1252..c6a9ac24c785 100644 --- a/fs/bcachefs/movinggc.c +++ b/fs/bcachefs/movinggc.c @@ -125,7 +125,7 @@ static void bch2_copygc(struct bch_fs *c, struct bch_dev *ca) struct copygc_heap_entry e; if (m.owned_by_allocator || - m.data_type != BUCKET_DATA || + m.data_type != BCH_DATA_USER || !bucket_sectors_used(m) || bucket_sectors_used(m) >= ca->mi.bucket_size) continue; diff --git a/fs/bcachefs/sysfs.c b/fs/bcachefs/sysfs.c index 3197a2e46166..11112dc3a1ac 100644 --- a/fs/bcachefs/sysfs.c +++ b/fs/bcachefs/sysfs.c @@ -149,16 +149,6 @@ read_attribute(journal_pins); read_attribute(internal_uuid); -read_attribute(available_buckets); -read_attribute(free_buckets); -read_attribute(dirty_data); -read_attribute(dirty_bytes); -read_attribute(dirty_buckets); -read_attribute(cached_data); -read_attribute(cached_bytes); -read_attribute(cached_buckets); -read_attribute(meta_buckets); -read_attribute(alloc_buckets); read_attribute(has_data); read_attribute(alloc_debug); write_attribute(wake_allocator); @@ -712,12 +702,17 @@ static ssize_t show_dev_alloc_debug(struct bch_dev *ca, char *buf) "buckets:\n" " capacity: %llu\n" " alloc: %llu\n" + " sb: %llu\n" + " journal: %llu\n" " meta: %llu\n" - " dirty: %llu\n" + " user: %llu\n" + " cached: %llu\n" " available: %llu\n" "sectors:\n" + " sb: %llu\n" + " journal: %llu\n" " meta: %llu\n" - " dirty: %llu\n" + " user: %llu\n" " cached: %llu\n" "freelist_wait: %s\n" "open buckets: %u/%u (reserved %u)\n" @@ -728,12 +723,17 @@ static ssize_t show_dev_alloc_debug(struct bch_dev *ca, char *buf) fifo_used(&ca->free[RESERVE_NONE]), ca->free[RESERVE_NONE].size, ca->mi.nbuckets - ca->mi.first_bucket, stats.buckets_alloc, - stats.buckets[S_META], - stats.buckets[S_DIRTY], + stats.buckets[BCH_DATA_SB], + stats.buckets[BCH_DATA_JOURNAL], + stats.buckets[BCH_DATA_BTREE], + stats.buckets[BCH_DATA_USER], + stats.buckets[BCH_DATA_CACHED], __dev_buckets_available(ca, stats), - stats.sectors[S_META], - stats.sectors[S_DIRTY], - stats.sectors_cached, + stats.sectors[BCH_DATA_SB], + stats.sectors[BCH_DATA_JOURNAL], + stats.sectors[BCH_DATA_BTREE], + stats.sectors[BCH_DATA_USER], + stats.sectors[BCH_DATA_CACHED], c->freelist_wait.list.first ? "waiting" : "empty", c->open_buckets_nr_free, OPEN_BUCKETS_COUNT, BTREE_NODE_RESERVE, c->open_buckets_wait.list.first ? "waiting" : "empty"); @@ -771,7 +771,6 @@ SHOW(bch2_dev) { struct bch_dev *ca = container_of(kobj, struct bch_dev, kobj); struct bch_fs *c = ca->fs; - struct bch_dev_usage stats = bch2_dev_usage_read(c, ca); char *out = buf, *end = buf + PAGE_SIZE; sysfs_printf(uuid, "%pU\n", ca->uuid.b); @@ -782,17 +781,6 @@ SHOW(bch2_dev) sysfs_print(nbuckets, ca->mi.nbuckets); sysfs_print(discard, ca->mi.discard); - sysfs_hprint(dirty_data, stats.sectors[S_DIRTY] << 9); - sysfs_print(dirty_bytes, stats.sectors[S_DIRTY] << 9); - sysfs_print(dirty_buckets, stats.buckets[S_DIRTY]); - sysfs_hprint(cached_data, stats.sectors_cached << 9); - sysfs_print(cached_bytes, stats.sectors_cached << 9); - sysfs_print(cached_buckets, stats.buckets_cached); - sysfs_print(meta_buckets, stats.buckets[S_META]); - sysfs_print(alloc_buckets, stats.buckets_alloc); - sysfs_print(available_buckets, __dev_buckets_available(ca, stats)); - sysfs_print(free_buckets, __dev_buckets_free(ca, stats)); - if (attr == &sysfs_has_data) { out += bch2_scnprint_flag_list(out, end - out, bch2_data_types, @@ -924,20 +912,6 @@ struct attribute *bch2_dev_files[] = { &sysfs_has_data, &sysfs_iostats, - /* alloc info - data: */ - &sysfs_dirty_data, - &sysfs_dirty_bytes, - &sysfs_cached_data, - &sysfs_cached_bytes, - - /* alloc info - buckets: */ - &sysfs_available_buckets, - &sysfs_free_buckets, - &sysfs_dirty_buckets, - &sysfs_cached_buckets, - &sysfs_meta_buckets, - &sysfs_alloc_buckets, - /* alloc info - other stats: */ &sysfs_read_priority_stats, &sysfs_write_priority_stats, |