bcachefs: Write out fs usage
authorKent Overstreet <kent.overstreet@gmail.com>
Thu, 24 Jan 2019 22:54:51 +0000 (17:54 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:15 +0000 (17:08 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/journal_io.c
fs/bcachefs/replicas.c
fs/bcachefs/replicas.h
fs/bcachefs/super-io.c
fs/bcachefs/super-io.h

index 173aecfaebc26227550f311d436bf03312096a92..2f04f0074ec457144bbf0f83d5bdddc829b551c1 100644 (file)
@@ -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);
 
index 991d409b6a86ce92137b7a146c86e5e059d147ee..8495cac29a1435f48fd6fb9e9ed2a58bbc285a28 100644 (file)
@@ -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);
index 4fabe0372ec39796ed792c547b8e905e286be449..35164887dffb8ea5f92b605e7a9da419ee0569ae 100644 (file)
@@ -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)                                       \
index 2ad1266e167d14a95f640baa432cd600bfa0feec..9e991be3d90d52b9e396f90afdc86725b3b4adfc 100644 (file)
@@ -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);
index ac3b704f0540636e22511690ccb71224dc54a908..498a9e887d4eec304fccee61e47d04cc3eed7e48 100644 (file)
@@ -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);