From: Kent Overstreet Date: Thu, 24 Jan 2019 22:54:51 +0000 (-0500) Subject: bcachefs: Write out fs usage X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=3ccc5c50f29fb6934fb71e12983f1f2beabe29b9;p=linux.git bcachefs: Write out fs usage Signed-off-by: Kent Overstreet --- diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index 173aecfaebc26..2f04f0074ec45 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -863,19 +863,6 @@ err: /* journal write: */ -static void bch2_journal_add_btree_root(struct journal_buf *buf, - enum btree_id id, struct bkey_i *k, - unsigned level) -{ - struct jset_entry *entry; - - entry = bch2_journal_add_entry_noreservation(buf, k->k.u64s); - entry->type = BCH_JSET_ENTRY_btree_root; - entry->btree_id = id; - entry->level = level; - memcpy_u64s(entry->_data, k, k->k.u64s); -} - static unsigned journal_dev_buckets_available(struct journal *j, struct journal_device *ja) { @@ -1206,25 +1193,27 @@ void bch2_journal_write(struct closure *cl) struct bch_fs *c = container_of(j, struct bch_fs, journal); struct bch_dev *ca; struct journal_buf *w = journal_prev_buf(j); + struct jset_entry *start, *end; struct jset *jset; struct bio *bio; struct bch_extent_ptr *ptr; bool validate_before_checksum = false; - unsigned i, sectors, bytes; + unsigned i, sectors, bytes, u64s; journal_buf_realloc(j, w); jset = w->data; j->write_start_time = local_clock(); - mutex_lock(&c->btree_root_lock); - for (i = 0; i < BTREE_ID_NR; i++) { - struct btree_root *r = &c->btree_roots[i]; - if (r->alive) - bch2_journal_add_btree_root(w, i, &r->key, r->level); - } - c->btree_roots_dirty = false; - mutex_unlock(&c->btree_root_lock); + start = vstruct_last(w->data); + end = bch2_journal_super_entries_add_common(c, start, + le64_to_cpu(jset->seq)); + u64s = (u64 *) end - (u64 *) start; + BUG_ON(u64s > j->entry_u64s_reserved); + + le32_add_cpu(&w->data->u64s, u64s); + BUG_ON(vstruct_sectors(jset, c->block_bits) > + w->disk_sectors); journal_write_compact(jset); diff --git a/fs/bcachefs/replicas.c b/fs/bcachefs/replicas.c index 991d409b6a86c..8495cac29a143 100644 --- a/fs/bcachefs/replicas.c +++ b/fs/bcachefs/replicas.c @@ -30,11 +30,6 @@ static void replicas_entry_sort(struct bch_replicas_entry *e) bubble_sort(e->devs, e->nr_devs, u8_cmp); } -#define for_each_cpu_replicas_entry(_r, _i) \ - for (_i = (_r)->entries; \ - (void *) (_i) < (void *) (_r)->entries + (_r)->nr * (_r)->entry_size;\ - _i = (void *) (_i) + (_r)->entry_size) - static void bch2_cpu_replicas_sort(struct bch_replicas_cpu *r) { eytzinger0_sort(r->entries, r->nr, r->entry_size, memcmp, NULL); diff --git a/fs/bcachefs/replicas.h b/fs/bcachefs/replicas.h index 4fabe0372ec39..35164887dffb8 100644 --- a/fs/bcachefs/replicas.h +++ b/fs/bcachefs/replicas.h @@ -57,6 +57,11 @@ unsigned bch2_dev_has_data(struct bch_fs *, struct bch_dev *); int bch2_replicas_gc_end(struct bch_fs *, int); int bch2_replicas_gc_start(struct bch_fs *, unsigned); +#define for_each_cpu_replicas_entry(_r, _i) \ + for (_i = (_r)->entries; \ + (void *) (_i) < (void *) (_r)->entries + (_r)->nr * (_r)->entry_size;\ + _i = (void *) (_i) + (_r)->entry_size) + /* iterate over superblock replicas - used by userspace tools: */ #define replicas_entry_bytes(_i) \ diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c index 2ad1266e167d1..9e991be3d90d5 100644 --- a/fs/bcachefs/super-io.c +++ b/fs/bcachefs/super-io.c @@ -885,29 +885,112 @@ void bch2_sb_clean_renumber(struct bch_sb_field_clean *clean, int write) bch2_bkey_renumber(BKEY_TYPE_BTREE, bkey_to_packed(entry->start), write); } -void bch2_fs_mark_clean(struct bch_fs *c, bool clean) +static void bch2_fs_mark_dirty(struct bch_fs *c) { - struct bch_sb_field_clean *sb_clean; - unsigned u64s = sizeof(*sb_clean) / sizeof(u64); - struct jset_entry *entry; - struct btree_root *r; - mutex_lock(&c->sb_lock); - if (clean == BCH_SB_CLEAN(c->disk_sb.sb)) - goto out; - - SET_BCH_SB_CLEAN(c->disk_sb.sb, clean); + if (BCH_SB_CLEAN(c->disk_sb.sb)) { + SET_BCH_SB_CLEAN(c->disk_sb.sb, false); + bch2_write_super(c); + } + mutex_unlock(&c->sb_lock); +} - if (!clean) - goto write_super; +struct jset_entry * +bch2_journal_super_entries_add_common(struct bch_fs *c, + struct jset_entry *entry, + u64 journal_seq) +{ + struct jset_entry_usage *u; + struct btree_root *r; + unsigned i; mutex_lock(&c->btree_root_lock); for (r = c->btree_roots; r < c->btree_roots + BTREE_ID_NR; r++) - if (r->alive) - u64s += jset_u64s(r->key.u64s); + if (r->alive) { + entry->u64s = r->key.u64s; + entry->btree_id = r - c->btree_roots; + entry->level = r->level; + entry->type = BCH_JSET_ENTRY_btree_root; + bkey_copy(&entry->start[0], &r->key); + + entry = vstruct_next(entry); + } + c->btree_roots_dirty = false; + + mutex_unlock(&c->btree_root_lock); + + if (journal_seq) + return entry; + + percpu_down_write(&c->mark_lock); + + { + u64 nr_inodes = percpu_u64_get(&c->usage[0]->s.nr_inodes); + + u = container_of(entry, struct jset_entry_usage, entry); + memset(u, 0, sizeof(*u)); + u->entry.u64s = DIV_ROUND_UP(sizeof(*u), sizeof(u64)) - 1; + u->entry.type = BCH_JSET_ENTRY_usage; + u->sectors = cpu_to_le64(nr_inodes); + u->type = FS_USAGE_INODES; + + entry = vstruct_next(entry); + } + + { + u = container_of(entry, struct jset_entry_usage, entry); + memset(u, 0, sizeof(*u)); + u->entry.u64s = DIV_ROUND_UP(sizeof(*u), sizeof(u64)) - 1; + u->entry.type = BCH_JSET_ENTRY_usage; + u->sectors = cpu_to_le64(atomic64_read(&c->key_version)); + u->type = FS_USAGE_KEY_VERSION; + + entry = vstruct_next(entry); + } + + for (i = 0; i < c->replicas.nr; i++) { + struct bch_replicas_entry *e = + cpu_replicas_entry(&c->replicas, i); + u64 sectors = percpu_u64_get(&c->usage[0]->data[i]); + + u = container_of(entry, struct jset_entry_usage, entry); + u->entry.u64s = DIV_ROUND_UP(sizeof(*u) + e->nr_devs, + sizeof(u64)) - 1; + u->entry.type = BCH_JSET_ENTRY_usage; + u->sectors = cpu_to_le64(sectors); + u->type = FS_USAGE_REPLICAS; + unsafe_memcpy(&u->r, e, replicas_entry_bytes(e), + "embedded variable length struct"); + + entry = vstruct_next(entry); + } + + percpu_up_write(&c->mark_lock); + + return entry; +} + +void bch2_fs_mark_clean(struct bch_fs *c, bool clean) +{ + struct bch_sb_field_clean *sb_clean; + struct jset_entry *entry; + unsigned u64s; + + if (!clean) { + bch2_fs_mark_dirty(c); + return; + } + + mutex_lock(&c->sb_lock); + if (BCH_SB_CLEAN(c->disk_sb.sb)) + goto out; + + SET_BCH_SB_CLEAN(c->disk_sb.sb, true); + + u64s = sizeof(*sb_clean) / sizeof(u64) + c->journal.entry_u64s_reserved; sb_clean = bch2_sb_resize_clean(&c->disk_sb, u64s); if (!sb_clean) { @@ -921,30 +1004,16 @@ void bch2_fs_mark_clean(struct bch_fs *c, bool clean) sb_clean->journal_seq = journal_cur_seq(&c->journal) - 1; entry = sb_clean->start; + entry = bch2_journal_super_entries_add_common(c, entry, 0); + BUG_ON((void *) entry > vstruct_end(&sb_clean->field)); + memset(entry, 0, vstruct_end(&sb_clean->field) - (void *) entry); - for (r = c->btree_roots; - r < c->btree_roots + BTREE_ID_NR; - r++) - if (r->alive) { - entry->u64s = r->key.u64s; - entry->btree_id = r - c->btree_roots; - entry->level = r->level; - entry->type = BCH_JSET_ENTRY_btree_root; - bkey_copy(&entry->start[0], &r->key); - entry = vstruct_next(entry); - BUG_ON((void *) entry > vstruct_end(&sb_clean->field)); - } - - BUG_ON(entry != vstruct_end(&sb_clean->field)); - if (le16_to_cpu(c->disk_sb.sb->version) < bcachefs_metadata_version_bkey_renumber) bch2_sb_clean_renumber(sb_clean, WRITE); - mutex_unlock(&c->btree_root_lock); -write_super: bch2_write_super(c); out: mutex_unlock(&c->sb_lock); diff --git a/fs/bcachefs/super-io.h b/fs/bcachefs/super-io.h index ac3b704f05406..498a9e887d4ee 100644 --- a/fs/bcachefs/super-io.h +++ b/fs/bcachefs/super-io.h @@ -135,6 +135,10 @@ static inline struct bch_member_cpu bch2_mi_to_cpu(struct bch_member *mi) /* BCH_SB_FIELD_clean: */ +struct jset_entry * +bch2_journal_super_entries_add_common(struct bch_fs *, + struct jset_entry *, u64); + void bch2_sb_clean_renumber(struct bch_sb_field_clean *, int); void bch2_fs_mark_clean(struct bch_fs *, bool);