]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Update bcachefs sources to c887148ebf99 thread_with_file: add f_ops.flush
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 20 Feb 2024 21:28:18 +0000 (16:28 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Tue, 20 Feb 2024 21:28:27 +0000 (16:28 -0500)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
17 files changed:
.bcachefs_revision
libbcachefs/alloc_background.c
libbcachefs/alloc_background.h
libbcachefs/bcachefs.h
libbcachefs/bcachefs_format.h
libbcachefs/btree_locking.c
libbcachefs/btree_write_buffer.c
libbcachefs/chardev.c
libbcachefs/fsck.c
libbcachefs/fsck.h
libbcachefs/io_write.c
libbcachefs/journal.c
libbcachefs/journal_io.c
libbcachefs/journal_reclaim.c
libbcachefs/rebalance.c
libbcachefs/recovery_types.h
libbcachefs/sb-errors_types.h

index a0ce33cb9af168c6f43448aefdc410cf7507bf8e..c24264626f74c579f4afb820a7e151924e22f70b 100644 (file)
@@ -1 +1 @@
-9a555a741e807275c320807babd3f42efb8fee90
+c887148ebf9989ce8bdf6f814d4342ba5bf465fa
index c7be6afe89553b154ff8ba1d2899908026c5451a..4de4036ded069cb64fed7a5fc893eeb0262ab9f5 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/sched/task.h>
 #include <linux/sort.h>
 
+static void bch2_discard_one_bucket_fast(struct bch_fs *c, struct bpos bucket);
+
 /* Persistent alloc info: */
 
 static const unsigned BCH_ALLOC_V1_FIELD_BYTES[] = {
@@ -866,14 +868,14 @@ int bch2_trigger_alloc(struct btree_trans *trans,
 #define statechange(expr)              !eval_state(old_a, expr) && eval_state(new_a, expr)
 #define bucket_flushed(a)              (!a->journal_seq || a->journal_seq <= c->journal.flushed_seq_ondisk)
 
-               if (statechange(a->data_type == BCH_DATA_free &&
-                               bucket_flushed(a)))
+               if (statechange(a->data_type == BCH_DATA_free) &&
+                   bucket_flushed(new_a))
                        closure_wake_up(&c->freelist_wait);
 
-               if (statechange(a->data_type == BCH_DATA_need_discard &&
-                               bucket_flushed(a)) &&
-                   !bch2_bucket_is_open(c, new.k->p.inode, new.k->p.offset))
-                       bch2_do_discards(c);
+               if (statechange(a->data_type == BCH_DATA_need_discard) &&
+                   !bch2_bucket_is_open(c, new.k->p.inode, new.k->p.offset) &&
+                   bucket_flushed(new_a))
+                       bch2_discard_one_bucket_fast(c, new.k->p);
 
                if (statechange(a->data_type == BCH_DATA_cached) &&
                    !bch2_bucket_is_open(c, new.k->p.inode, new.k->p.offset) &&
@@ -1609,6 +1611,36 @@ int bch2_check_alloc_to_lru_refs(struct bch_fs *c)
        return ret;
 }
 
+static int discard_in_flight_add(struct bch_fs *c, struct bpos bucket)
+{
+       int ret;
+
+       mutex_lock(&c->discard_buckets_in_flight_lock);
+       darray_for_each(c->discard_buckets_in_flight, i)
+               if (bkey_eq(*i, bucket)) {
+                       ret = -EEXIST;
+                       goto out;
+               }
+
+       ret = darray_push(&c->discard_buckets_in_flight, bucket);
+out:
+       mutex_unlock(&c->discard_buckets_in_flight_lock);
+       return ret;
+}
+
+static void discard_in_flight_remove(struct bch_fs *c, struct bpos bucket)
+{
+       mutex_lock(&c->discard_buckets_in_flight_lock);
+       darray_for_each(c->discard_buckets_in_flight, i)
+               if (bkey_eq(*i, bucket)) {
+                       darray_remove_item(&c->discard_buckets_in_flight, i);
+                       goto found;
+               }
+       BUG();
+found:
+       mutex_unlock(&c->discard_buckets_in_flight_lock);
+}
+
 struct discard_buckets_state {
        u64             seen;
        u64             open;
@@ -1647,6 +1679,7 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
        struct bch_dev *ca;
        struct bkey_i_alloc_v4 *a;
        struct printbuf buf = PRINTBUF;
+       bool discard_locked = false;
        int ret = 0;
 
        ca = bch_dev_bkey_exists(c, pos.inode);
@@ -1714,6 +1747,11 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
                goto out;
        }
 
+       if (discard_in_flight_add(c, SPOS(iter.pos.inode, iter.pos.offset, true)))
+               goto out;
+
+       discard_locked = true;
+
        if (!bkey_eq(*discard_pos_done, iter.pos) &&
            ca->mi.discard && !c->opts.nochanges) {
                /*
@@ -1745,6 +1783,8 @@ write:
        count_event(c, bucket_discard);
        s->discarded++;
 out:
+       if (discard_locked)
+               discard_in_flight_remove(c, iter.pos);
        s->seen++;
        bch2_trans_iter_exit(trans, &iter);
        percpu_ref_put(&ca->io_ref);
@@ -1784,6 +1824,92 @@ void bch2_do_discards(struct bch_fs *c)
                bch2_write_ref_put(c, BCH_WRITE_REF_discard);
 }
 
+static int bch2_clear_bucket_needs_discard(struct btree_trans *trans, struct bpos bucket)
+{
+       struct btree_iter iter;
+       bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc, bucket, BTREE_ITER_INTENT);
+       struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter);
+       int ret = bkey_err(k);
+       if (ret)
+               goto err;
+
+       struct bkey_i_alloc_v4 *a = bch2_alloc_to_v4_mut(trans, k);
+       ret = PTR_ERR_OR_ZERO(a);
+       if (ret)
+               goto err;
+
+       SET_BCH_ALLOC_V4_NEED_DISCARD(&a->v, false);
+       a->v.data_type = alloc_data_type(a->v, a->v.data_type);
+
+       ret = bch2_trans_update(trans, &iter, &a->k_i, 0);
+err:
+       bch2_trans_iter_exit(trans, &iter);
+       return ret;
+}
+
+static void bch2_do_discards_fast_work(struct work_struct *work)
+{
+       struct bch_fs *c = container_of(work, struct bch_fs, discard_fast_work);
+
+       while (1) {
+               bool got_bucket = false;
+               struct bpos bucket;
+               struct bch_dev *ca;
+
+               mutex_lock(&c->discard_buckets_in_flight_lock);
+               darray_for_each(c->discard_buckets_in_flight, i) {
+                       if (i->snapshot)
+                               continue;
+
+                       ca = bch_dev_bkey_exists(c, i->inode);
+
+                       if (!percpu_ref_tryget(&ca->io_ref)) {
+                               darray_remove_item(&c->discard_buckets_in_flight, i);
+                               continue;
+                       }
+
+                       got_bucket = true;
+                       bucket = *i;
+                       i->snapshot = true;
+                       break;
+               }
+               mutex_unlock(&c->discard_buckets_in_flight_lock);
+
+               if (!got_bucket)
+                       break;
+
+               blkdev_issue_discard(ca->disk_sb.bdev,
+                                    bucket.offset * ca->mi.bucket_size,
+                                    ca->mi.bucket_size,
+                                    GFP_KERNEL);
+
+               int ret = bch2_trans_do(c, NULL, NULL,
+                                       BCH_WATERMARK_btree|
+                                       BCH_TRANS_COMMIT_no_enospc,
+                                       bch2_clear_bucket_needs_discard(trans, bucket));
+               bch_err_fn(c, ret);
+
+               percpu_ref_put(&ca->io_ref);
+               discard_in_flight_remove(c, bucket);
+
+               if (ret)
+                       break;
+       }
+
+       bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
+}
+
+static void bch2_discard_one_bucket_fast(struct bch_fs *c, struct bpos bucket)
+{
+       struct bch_dev *ca = bch_dev_bkey_exists(c, bucket.inode);
+
+       if (!percpu_ref_is_dying(&ca->io_ref) &&
+           !discard_in_flight_add(c, bucket) &&
+           bch2_write_ref_tryget(c, BCH_WRITE_REF_discard_fast) &&
+           !queue_work(c->write_ref_wq, &c->discard_fast_work))
+               bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
+}
+
 static int invalidate_one_bucket(struct btree_trans *trans,
                                 struct btree_iter *lru_iter,
                                 struct bkey_s_c lru_k,
@@ -2215,9 +2341,16 @@ void bch2_dev_allocator_add(struct bch_fs *c, struct bch_dev *ca)
                        set_bit(ca->dev_idx, c->rw_devs[i].d);
 }
 
+void bch2_fs_allocator_background_exit(struct bch_fs *c)
+{
+       darray_exit(&c->discard_buckets_in_flight);
+}
+
 void bch2_fs_allocator_background_init(struct bch_fs *c)
 {
        spin_lock_init(&c->freelist_lock);
+       mutex_init(&c->discard_buckets_in_flight_lock);
        INIT_WORK(&c->discard_work, bch2_do_discards_work);
+       INIT_WORK(&c->discard_fast_work, bch2_do_discards_fast_work);
        INIT_WORK(&c->invalidate_work, bch2_do_invalidates_work);
 }
index e7f7e842ee1b725f1373e4782cc34e1c9b83afa7..052b2fac25d693c7dddba5077fc9caeec2d246dd 100644 (file)
@@ -269,6 +269,7 @@ u64 bch2_min_rw_member_capacity(struct bch_fs *);
 void bch2_dev_allocator_remove(struct bch_fs *, struct bch_dev *);
 void bch2_dev_allocator_add(struct bch_fs *, struct bch_dev *);
 
+void bch2_fs_allocator_background_exit(struct bch_fs *);
 void bch2_fs_allocator_background_init(struct bch_fs *);
 
 #endif /* _BCACHEFS_ALLOC_BACKGROUND_H */
index 4d04e9c04dc348d2500031b897c613f7319a474f..13b8a16c18dca7ae4d1908852268463c0df9275c 100644 (file)
@@ -708,6 +708,7 @@ struct btree_trans_buf {
        x(reflink)                                                      \
        x(fallocate)                                                    \
        x(discard)                                                      \
+       x(discard_fast)                                                 \
        x(invalidate)                                                   \
        x(delete_dead_snapshots)                                        \
        x(snapshot_delete_pagecache)                                    \
@@ -943,8 +944,11 @@ struct bch_fs {
        unsigned                write_points_nr;
 
        struct buckets_waiting_for_journal buckets_waiting_for_journal;
-       struct work_struct      discard_work;
        struct work_struct      invalidate_work;
+       struct work_struct      discard_work;
+       struct mutex            discard_buckets_in_flight_lock;
+       DARRAY(struct bpos)     discard_buckets_in_flight;
+       struct work_struct      discard_fast_work;
 
        /* GARBAGE COLLECTION */
        struct task_struct      *gc_thread;
index 8aa5241b5517224fb53248a9d129484ebc518953..bff8750ac0d743aa22f2cbea9effbf77bf6be725 100644 (file)
@@ -189,7 +189,11 @@ struct bversion {
        __u32           hi;
        __u64           lo;
 #endif
-} __packed __aligned(4);
+} __packed
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+__aligned(4)
+#endif
+;
 
 struct bkey {
        /* Size of combined key and value, in u64s */
index 6843974423381029e7a8cf24fd4cd5c6c33627cd..b9b151e693ed60ecc3dc9147cc34902643cfc7aa 100644 (file)
@@ -747,7 +747,8 @@ void bch2_trans_downgrade(struct btree_trans *trans)
                return;
 
        trans_for_each_path(trans, path, i)
-               bch2_btree_path_downgrade(trans, path);
+               if (path->ref)
+                       bch2_btree_path_downgrade(trans, path);
 }
 
 int bch2_trans_relock(struct btree_trans *trans)
index ac7844861966368cdce41efd9e27c898fe8ad6e7..a7d86252690a72e2f5aed466adfba742ae6b85ed 100644 (file)
@@ -590,7 +590,9 @@ static int bch2_journal_keys_to_write_buffer(struct bch_fs *c, struct journal_bu
                entry->type = BCH_JSET_ENTRY_btree_keys;
        }
 
+       spin_lock(&c->journal.lock);
        buf->need_flush_to_write_buffer = false;
+       spin_unlock(&c->journal.lock);
 out:
        bch2_journal_keys_to_write_buffer_end(c, &dst);
        return ret;
index a2f30f45f93f75255a10ca6d1e07ae37a574b0cc..992939152f01909cf5d92cb58504a83fe973fecd 100644 (file)
@@ -155,14 +155,28 @@ static void bch2_fsck_thread_exit(struct thread_with_stdio *_thr)
        kfree(thr);
 }
 
-static void bch2_fsck_offline_thread_fn(struct thread_with_stdio *stdio)
+static int bch2_fsck_offline_thread_fn(struct thread_with_stdio *stdio)
 {
        struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr);
        struct bch_fs *c = bch2_fs_open(thr->devs, thr->nr_devs, thr->opts);
 
-       thr->thr.thr.ret = PTR_ERR_OR_ZERO(c);
-       if (!thr->thr.thr.ret)
-               bch2_fs_stop(c);
+       if (IS_ERR(c))
+               return PTR_ERR(c);
+
+       int ret = 0;
+       if (test_bit(BCH_FS_errors_fixed, &c->flags))
+               ret |= 1;
+       if (test_bit(BCH_FS_error, &c->flags))
+               ret |= 4;
+
+       bch2_fs_stop(c);
+
+       if (ret & 1)
+               stdio_redirect_printf(&stdio->stdio, false, "%s: errors fixed\n", c->name);
+       if (ret & 4)
+               stdio_redirect_printf(&stdio->stdio, false, "%s: still has errors\n", c->name);
+
+       return ret;
 }
 
 static const struct thread_with_stdio_ops bch2_offline_fsck_ops = {
@@ -763,7 +777,7 @@ static long bch2_ioctl_disk_resize_journal(struct bch_fs *c,
        return ret;
 }
 
-static void bch2_fsck_online_thread_fn(struct thread_with_stdio *stdio)
+static int bch2_fsck_online_thread_fn(struct thread_with_stdio *stdio)
 {
        struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr);
        struct bch_fs *c = thr->c;
@@ -795,6 +809,7 @@ static void bch2_fsck_online_thread_fn(struct thread_with_stdio *stdio)
 
        up(&c->online_fsck_mutex);
        bch2_ro_ref_put(c);
+       return ret;
 }
 
 static const struct thread_with_stdio_ops bch2_online_fsck_ops = {
index 3f74b6769a38381468c8e7eaaba1c646b54069aa..144f074bbc6ce71dfdc68b009345c521891af29b 100644 (file)
@@ -342,6 +342,27 @@ static int remove_backpointer(struct btree_trans *trans,
        return ret;
 }
 
+static int reattach_subvol(struct btree_trans *trans, struct bkey_s_c_subvolume s)
+{
+       struct bch_fs *c = trans->c;
+
+       struct bch_inode_unpacked inode;
+       int ret = bch2_inode_find_by_inum_trans(trans,
+                               (subvol_inum) { s.k->p.offset, le64_to_cpu(s.v->inode) },
+                               &inode);
+       if (ret)
+               return ret;
+
+       ret = remove_backpointer(trans, &inode);
+       bch_err_msg(c, ret, "removing dirent");
+       if (ret)
+               return ret;
+
+       ret = reattach_inode(trans, &inode, le32_to_cpu(s.v->snapshot));
+       bch_err_msg(c, ret, "reattaching inode %llu", inode.bi_inum);
+       return ret;
+}
+
 struct snapshots_seen_entry {
        u32                             id;
        u32                             equiv;
@@ -2111,6 +2132,107 @@ int bch2_check_root(struct bch_fs *c)
        return ret;
 }
 
+typedef DARRAY(u32) darray_u32;
+
+static bool darray_u32_has(darray_u32 *d, u32 v)
+{
+       darray_for_each(*d, i)
+               if (*i == v)
+                       return true;
+       return false;
+}
+
+/*
+ * We've checked that inode backpointers point to valid dirents; here, it's
+ * sufficient to check that the subvolume root has a dirent:
+ */
+static int subvol_has_dirent(struct btree_trans *trans, struct bkey_s_c_subvolume s)
+{
+       struct bch_inode_unpacked inode;
+       int ret = bch2_inode_find_by_inum_trans(trans,
+                               (subvol_inum) { s.k->p.offset, le64_to_cpu(s.v->inode) },
+                               &inode);
+       if (ret)
+               return ret;
+
+       return inode.bi_dir != 0;
+}
+
+static int check_subvol_path(struct btree_trans *trans, struct btree_iter *iter, struct bkey_s_c k)
+{
+       struct bch_fs *c = trans->c;
+       struct btree_iter parent_iter = {};
+       darray_u32 subvol_path = {};
+       struct printbuf buf = PRINTBUF;
+       int ret = 0;
+
+       if (k.k->type != KEY_TYPE_subvolume)
+               return 0;
+
+       while (k.k->p.offset != BCACHEFS_ROOT_SUBVOL) {
+               ret = darray_push(&subvol_path, k.k->p.offset);
+               if (ret)
+                       goto err;
+
+               struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k);
+
+               ret = subvol_has_dirent(trans, s);
+               if (ret < 0)
+                       break;
+
+               if (fsck_err_on(!ret,
+                               c, subvol_unreachable,
+                               "unreachable subvolume %s",
+                               (bch2_bkey_val_to_text(&buf, c, s.s_c),
+                                buf.buf))) {
+                       ret = reattach_subvol(trans, s);
+                       break;
+               }
+
+               u32 parent = le32_to_cpu(s.v->fs_path_parent);
+
+               if (darray_u32_has(&subvol_path, parent)) {
+                       if (fsck_err(c, subvol_loop, "subvolume loop"))
+                               ret = reattach_subvol(trans, s);
+                       break;
+               }
+
+               bch2_trans_iter_exit(trans, &parent_iter);
+               bch2_trans_iter_init(trans, &parent_iter,
+                                    BTREE_ID_subvolumes, POS(0, parent), 0);
+               k = bch2_btree_iter_peek_slot(&parent_iter);
+               ret = bkey_err(k);
+               if (ret)
+                       goto err;
+
+               if (fsck_err_on(k.k->type != KEY_TYPE_subvolume,
+                               c, subvol_unreachable,
+                               "unreachable subvolume %s",
+                               (bch2_bkey_val_to_text(&buf, c, s.s_c),
+                                buf.buf))) {
+                       ret = reattach_subvol(trans, s);
+                       break;
+               }
+       }
+fsck_err:
+err:
+       printbuf_exit(&buf);
+       darray_exit(&subvol_path);
+       bch2_trans_iter_exit(trans, &parent_iter);
+       return ret;
+}
+
+int bch2_check_subvolume_structure(struct bch_fs *c)
+{
+       int ret = bch2_trans_run(c,
+               for_each_btree_key_commit(trans, iter,
+                               BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k,
+                               NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
+                       check_subvol_path(trans, &iter, k)));
+       bch_err_fn(c, ret);
+       return ret;
+}
+
 struct pathbuf_entry {
        u64     inum;
        u32     snapshot;
@@ -2127,22 +2249,9 @@ static bool path_is_dup(pathbuf *p, u64 inum, u32 snapshot)
        return false;
 }
 
-static int path_down(struct bch_fs *c, pathbuf *p,
-                    u64 inum, u32 snapshot)
-{
-       int ret = darray_push(p, ((struct pathbuf_entry) {
-               .inum           = inum,
-               .snapshot       = snapshot,
-       }));
-
-       if (ret)
-               bch_err(c, "fsck: error allocating memory for pathbuf, size %zu",
-                       p->size);
-       return ret;
-}
-
 /*
- * Check that a given inode is reachable from the root:
+ * Check that a given inode is reachable from its subvolume root - we already
+ * verified subvolume connectivity:
  *
  * XXX: we should also be verifying that inodes are in the right subvolumes
  */
@@ -2159,8 +2268,7 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
 
        BUG_ON(bch2_inode_unpack(inode_k, &inode));
 
-       while (!(inode.bi_inum == BCACHEFS_ROOT_INO &&
-                inode.bi_subvol == BCACHEFS_ROOT_SUBVOL)) {
+       while (!inode.bi_subvol) {
                struct btree_iter dirent_iter;
                struct bkey_s_c_dirent d;
                u32 parent_snapshot = snapshot;
@@ -2191,11 +2299,12 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
                if (!S_ISDIR(inode.bi_mode))
                        break;
 
-               ret = path_down(c, p, inode.bi_inum, snapshot);
-               if (ret) {
-                       bch_err(c, "memory allocation failure");
+               ret = darray_push(p, ((struct pathbuf_entry) {
+                       .inum           = inode.bi_inum,
+                       .snapshot       = snapshot,
+               }));
+               if (ret)
                        return ret;
-               }
 
                snapshot = parent_snapshot;
 
@@ -2222,18 +2331,15 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
                                pr_err("%llu:%u", i->inum, i->snapshot);
                        pr_err("%llu:%u", inode.bi_inum, snapshot);
 
-                       if (!fsck_err(c, dir_loop, "directory structure loop"))
-                               return 0;
-
-                       ret = remove_backpointer(trans, &inode);
-                       if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
+                       if (fsck_err(c, dir_loop, "directory structure loop")) {
+                               ret = remove_backpointer(trans, &inode);
                                bch_err_msg(c, ret, "removing dirent");
-                       if (ret)
-                               break;
+                               if (ret)
+                                       break;
 
-                       ret = reattach_inode(trans, &inode, snapshot);
-                       if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
+                               ret = reattach_inode(trans, &inode, snapshot);
                                bch_err_msg(c, ret, "reattaching inode %llu", inode.bi_inum);
+                       }
                        break;
                }
        }
index da991e8cf27eb493ed5aac5a3e3da606ae089968..a4ef9427178433bda33d500fe5f7551ff8fd1638 100644 (file)
@@ -8,6 +8,7 @@ int bch2_check_indirect_extents(struct bch_fs *);
 int bch2_check_dirents(struct bch_fs *);
 int bch2_check_xattrs(struct bch_fs *);
 int bch2_check_root(struct bch_fs *);
+int bch2_check_subvolume_structure(struct bch_fs *);
 int bch2_check_directory_structure(struct bch_fs *);
 int bch2_check_nlinks(struct bch_fs *);
 int bch2_fix_reflink_p(struct bch_fs *);
index 3fa2cb1d5b13aa3efeb07571879d3e1cb7ed066a..f7c4a428c17b066a1a44bb1adfc9dcb92bc62eb0 100644 (file)
@@ -530,7 +530,8 @@ static void __bch2_write_index(struct bch_write_op *op)
 
                        bch_err_inum_offset_ratelimited(c,
                                insert->k.p.inode, insert->k.p.offset << 9,
-                               "write error while doing btree update: %s",
+                               "%s write error while doing btree update: %s",
+                               op->flags & BCH_WRITE_MOVE ? "move" : "user",
                                bch2_err_str(ret));
                }
 
@@ -1067,7 +1068,8 @@ do_write:
        *_dst = dst;
        return more;
 csum_err:
-       bch_err(c, "error verifying existing checksum while rewriting existing data (memory corruption?)");
+       bch_err(c, "%s writ error: error verifying existing checksum while rewriting existing data (memory corruption?)",
+               op->flags & BCH_WRITE_MOVE ? "move" : "user");
        ret = -EIO;
 err:
        if (to_wbio(dst)->bounce)
@@ -1169,7 +1171,8 @@ static void bch2_nocow_write_convert_unwritten(struct bch_write_op *op)
 
                        bch_err_inum_offset_ratelimited(c,
                                insert->k.p.inode, insert->k.p.offset << 9,
-                               "write error while doing btree update: %s",
+                               "%s write error while doing btree update: %s",
+                               op->flags & BCH_WRITE_MOVE ? "move" : "user",
                                bch2_err_str(ret));
                }
 
@@ -1449,7 +1452,9 @@ err:
                                        bch_err_inum_offset_ratelimited(c,
                                                op->pos.inode,
                                                op->pos.offset << 9,
-                                               "%s(): error: %s", __func__, bch2_err_str(ret));
+                                               "%s(): %s error: %s", __func__,
+                                               op->flags & BCH_WRITE_MOVE ? "move" : "user",
+                                               bch2_err_str(ret));
                                op->error = ret;
                                break;
                        }
@@ -1573,7 +1578,8 @@ CLOSURE_CALLBACK(bch2_write)
                bch_err_inum_offset_ratelimited(c,
                        op->pos.inode,
                        op->pos.offset << 9,
-                       "misaligned write");
+                       "%s write error: misaligned write",
+                       op->flags & BCH_WRITE_MOVE ? "move" : "user");
                op->error = -EIO;
                goto err;
        }
index 214c8030048292430b07721bd04bac8ea3c44f50..46dc25ad95e7534040c8d96858aa43028c39950b 100644 (file)
@@ -53,33 +53,48 @@ static void bch2_journal_buf_to_text(struct printbuf *out, struct journal *j, u6
        unsigned i = seq & JOURNAL_BUF_MASK;
        struct journal_buf *buf = j->buf + i;
 
-       prt_printf(out, "seq:");
+       prt_str(out, "seq:");
        prt_tab(out);
        prt_printf(out, "%llu", seq);
        prt_newline(out);
        printbuf_indent_add(out, 2);
 
-       prt_printf(out, "refcount:");
+       prt_str(out, "refcount:");
        prt_tab(out);
        prt_printf(out, "%u", journal_state_count(s, i));
        prt_newline(out);
 
-       prt_printf(out, "size:");
+       prt_str(out, "size:");
        prt_tab(out);
        prt_human_readable_u64(out, vstruct_bytes(buf->data));
        prt_newline(out);
 
-       prt_printf(out, "expires");
+       prt_str(out, "expires:");
        prt_tab(out);
        prt_printf(out, "%li jiffies", buf->expires - jiffies);
        prt_newline(out);
 
+       prt_str(out, "flags:");
+       prt_tab(out);
+       if (buf->noflush)
+               prt_str(out, "noflush ");
+       if (buf->must_flush)
+               prt_str(out, "must_flush ");
+       if (buf->separate_flush)
+               prt_str(out, "separate_flush ");
+       if (buf->need_flush_to_write_buffer)
+               prt_str(out, "need_flush_to_write_buffer ");
+       if (buf->need_flush_to_write_buffer)
+               prt_str(out, "need_flush_to_write_buffer ");
+       if (buf->write_done)
+               prt_str(out, "write done ");
+       if (buf->write_started)
+               prt_str(out, "write started ");
+       if (buf->write_allocated)
+               prt_str(out, "write allocated ");
        if (buf->write_done)
-               prt_printf(out, "write done\n");
-       else if (buf->write_allocated)
-               prt_printf(out, "write allocated\n");
-       else if (buf->write_started)
-               prt_printf(out, "write started\n");
+               prt_str(out, "write done");
+       prt_newline(out);
 
        printbuf_indent_sub(out, 2);
 }
@@ -1420,6 +1435,7 @@ void __bch2_journal_debug_to_text(struct printbuf *out, struct journal *j)
        prt_printf(out, "reclaim kicked:\t\t%u\n",              j->reclaim_kicked);
        prt_printf(out, "reclaim runs in:\t%u ms\n",            time_after(j->next_reclaim, now)
               ? jiffies_to_msecs(j->next_reclaim - jiffies) : 0);
+       prt_printf(out, "blocked:\t\t%u\n",                     j->blocked);
        prt_printf(out, "current entry sectors:\t%u\n",         j->cur_entry_sectors);
        prt_printf(out, "current entry error:\t%s\n",           bch2_journal_errors[j->cur_entry_error]);
        prt_printf(out, "current entry:\t\t");
index 16c1249c84e09ee91529cbae8b0b719f86b2c7b4..f9e5b100a9da5c9f77230cb751ada0f61ae03f24 100644 (file)
@@ -1830,7 +1830,10 @@ static int bch2_journal_write_prep(struct journal *j, struct journal_buf *w)
 
        if (wb.wb)
                bch2_journal_keys_to_write_buffer_end(c, &wb);
+
+       spin_lock(&c->journal.lock);
        w->need_flush_to_write_buffer = false;
+       spin_unlock(&c->journal.lock);
 
        start = end = vstruct_last(jset);
 
@@ -1948,12 +1951,20 @@ CLOSURE_CALLBACK(bch2_journal_write)
        unsigned nr_rw_members = 0;
        int ret;
 
+       for_each_rw_member(c, ca)
+               nr_rw_members++;
+
        BUG_ON(BCH_SB_CLEAN(c->disk_sb.sb));
+       BUG_ON(!w->write_started);
        BUG_ON(w->write_allocated);
+       BUG_ON(w->write_done);
 
        j->write_start_time = local_clock();
 
        spin_lock(&j->lock);
+       if (nr_rw_members > 1)
+               w->separate_flush = true;
+
        ret = bch2_journal_write_pick_flush(j, w);
        spin_unlock(&j->lock);
        if (ret)
@@ -2008,12 +2019,6 @@ CLOSURE_CALLBACK(bch2_journal_write)
        if (c->opts.nochanges)
                goto no_io;
 
-       for_each_rw_member(c, ca)
-               nr_rw_members++;
-
-       if (nr_rw_members > 1)
-               w->separate_flush = true;
-
        /*
         * Mark journal replicas before we submit the write to guarantee
         * recovery will find the journal entries after a crash.
index a71550816c30407ba3b86332e1ed8c08b208e068..ab811c0dad26accfb4924eaef4cccb3ab957087c 100644 (file)
@@ -887,9 +887,11 @@ int bch2_journal_flush_device_pins(struct journal *j, int dev_idx)
                                         journal_seq_pin(j, seq)->devs);
                seq++;
 
-               spin_unlock(&j->lock);
-               ret = bch2_mark_replicas(c, &replicas.e);
-               spin_lock(&j->lock);
+               if (replicas.e.nr_devs) {
+                       spin_unlock(&j->lock);
+                       ret = bch2_mark_replicas(c, &replicas.e);
+                       spin_lock(&j->lock);
+               }
        }
        spin_unlock(&j->lock);
 err:
index 22d1017aa49b975756905a9a69ce8bcd82416ca3..56336f3dd1d0771b94c30aaa78d2c6b0d00617e7 100644 (file)
@@ -412,11 +412,11 @@ void bch2_rebalance_status_to_text(struct printbuf *out, struct bch_fs *c)
                u64 now = atomic64_read(&c->io_clock[WRITE].now);
 
                prt_str(out, "io wait duration:  ");
-               bch2_prt_human_readable_s64(out, r->wait_iotime_end - r->wait_iotime_start);
+               bch2_prt_human_readable_s64(out, (r->wait_iotime_end - r->wait_iotime_start) << 9);
                prt_newline(out);
 
                prt_str(out, "io wait remaining: ");
-               bch2_prt_human_readable_s64(out, r->wait_iotime_end - now);
+               bch2_prt_human_readable_s64(out, (r->wait_iotime_end - now) << 9);
                prt_newline(out);
 
                prt_str(out, "duration waited:   ");
index f0fc1dbb7239296af6712bb0ecc6cc666cf9d36b..1361e34d4e64c2939fc0b7af8c9df9e5d9dfc7cf 100644 (file)
@@ -44,6 +44,7 @@
        x(check_dirents,                        27, PASS_FSCK)                  \
        x(check_xattrs,                         28, PASS_FSCK)                  \
        x(check_root,                           29, PASS_ONLINE|PASS_FSCK)      \
+       x(check_subvolume_structure,            36, PASS_ONLINE|PASS_FSCK)      \
        x(check_directory_structure,            30, PASS_ONLINE|PASS_FSCK)      \
        x(check_nlinks,                         31, PASS_FSCK)                  \
        x(delete_dead_inodes,                   32, PASS_FSCK|PASS_UNCLEAN)     \
index 1530bd35b94572c85314e031b42aca38395f8dcd..0df4b0e7071ae421ce1f8035934c0020de4b0f58 100644 (file)
        x(subvol_fs_path_parent_wrong,                          254)    \
        x(subvol_root_fs_path_parent_nonzero,                   255)    \
        x(subvol_children_not_set,                              256)    \
-       x(subvol_children_bad,                                  257)
+       x(subvol_children_bad,                                  257)    \
+       x(subvol_loop,                                          258)    \
+       x(subvol_unreachable,                                   259)
 
 enum bch_sb_error_id {
 #define x(t, n) BCH_FSCK_ERR_##t = n,