bch2_trans_exit(&trans);
 
        if (ret < 0) {
-               bch_err(ca, "error initializing free space: %s", bch2_err_str(ret));
+               bch_err_msg(ca, ret, "initializing free space");
                return ret;
        }
 
 
                        bch2_alloc_write_key(&trans, &iter, k, metadata_only));
 
                if (ret < 0) {
-                       bch_err(c, "error writing alloc info: %s", bch2_err_str(ret));
+                       bch_err_fn(c, ret);
                        percpu_ref_put(&ca->ref);
                        break;
                }
        bch2_trans_exit(&trans);
 
        if (ret)
-               bch_err(c, "error reading alloc info at gc start: %s", bch2_err_str(ret));
+               bch_err_fn(c, ret);
 
        return ret;
 }
                                        BTREE_INSERT_NOFAIL,
                                gc_btree_gens_key(&trans, &iter, k));
                        if (ret && !bch2_err_matches(ret, EROFS))
-                               bch_err(c, "error recalculating oldest_gen: %s", bch2_err_str(ret));
+                               bch_err_fn(c, ret);
                        if (ret)
                                goto err;
                }
                        BTREE_INSERT_NOFAIL,
                bch2_alloc_write_oldest_gen(&trans, &iter, k));
        if (ret && !bch2_err_matches(ret, EROFS))
-               bch_err(c, "error writing oldest_gen: %s", bch2_err_str(ret));
+               bch_err_fn(c, ret);
        if (ret)
                goto err;
 
                ret = bch2_gc_gens(c);
 #endif
                if (ret < 0)
-                       bch_err(c, "btree gc failed: %s", bch2_err_str(ret));
+                       bch_err_fn(c, ret);
 
                debug_check_no_locks_held();
        }
 
        p = kthread_create(bch2_gc_thread, c, "bch-gc/%s", c->name);
        if (IS_ERR(p)) {
-               bch_err(c, "error creating gc thread: %s", bch2_err_str(PTR_ERR(p)));
+               bch_err_fn(c, PTR_ERR(p));
                return PTR_ERR(p);
        }
 
 
        ret = bch2_trans_do(c, NULL, NULL, 0,
                      async_btree_node_rewrite_trans(&trans, a));
        if (ret)
-               bch_err(c, "%s: error %s", __func__, bch2_err_str(ret));
+               bch_err_fn(c, ret);
        bch2_write_ref_put(c, BCH_WRITE_REF_node_rewrite);
        kfree(a);
 }
 
                ret = bch2_fs_read_write_early(c);
                if (ret) {
-                       bch_err(c, "%s: error going read-write: %s",
-                               __func__, bch2_err_str(ret));
+                       bch_err_msg(c, ret, "going read-write");
                        kfree(a);
                        return;
                }
 
 
        ret = ec_stripe_update_extents(c, &s->new_stripe);
        if (ret) {
-               bch_err(c, "error creating stripe: error updating pointers: %s",
-                       bch2_err_str(ret));
+               bch_err_msg(c, ret, "creating stripe: error updating pointers");
                goto err;
        }
 err:
 
        vinode = bch2_vfs_inode_get(c, BCACHEFS_ROOT_SUBVOL_INUM);
        ret = PTR_ERR_OR_ZERO(vinode);
        if (ret) {
-               bch_err(c, "error mounting: error getting root inode: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "mounting: error getting root inode");
                goto err_put_super;
        }
 
 
        if (!ret)
                *subvol = le32_to_cpu(s.subvol);
        else if (bch2_err_matches(ret, ENOENT))
-               bch_err(trans->c, "snapshot %u not fonud", snapshot);
+               bch_err(trans->c, "snapshot %u not found", snapshot);
        return ret;
 
 }
        ret = bch2_inode_unpack(k, inode);
 err:
        if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
-               bch_err(trans->c, "error fetching inode %llu: %s",
-                       inode_nr, bch2_err_str(ret));
+               bch_err_msg(trans->c, ret, "fetching inode %llu", inode_nr);
        bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
                *snapshot = iter.pos.snapshot;
 err:
        if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
-               bch_err(trans->c, "error fetching inode %llu:%u: %s",
-                       inode_nr, *snapshot, bch2_err_str(ret));
+               bch_err_msg(trans->c, ret, "fetching inode %llu:%u", inode_nr, *snapshot);
        bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
                                BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
 }
 
-static int write_inode(struct btree_trans *trans,
-                      struct bch_inode_unpacked *inode,
-                      u32 snapshot)
+static int fsck_write_inode(struct btree_trans *trans,
+                           struct bch_inode_unpacked *inode,
+                           u32 snapshot)
 {
        int ret = commit_do(trans, NULL, NULL,
                                  BTREE_INSERT_NOFAIL|
                                  BTREE_INSERT_LAZY_RW,
                                  __write_inode(trans, inode, snapshot));
        if (ret)
-               bch_err(trans->c, "error in fsck: error updating inode: %s",
-                       bch2_err_str(ret));
+               bch_err_fn(trans->c, ret);
        return ret;
 }
 
        }
 
        if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
-               bch_err(c, "error looking up lost+found: %s", bch2_err_str(ret));
+               bch_err_fn(c, ret);
        if (ret)
                return ret;
 
                                0, 0, S_IFDIR|0700, 0, NULL, NULL,
                                (subvol_inum) { }, 0);
        if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
-               bch_err(c, "error creating lost+found: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "creating lost+found");
        return ret;
 }
 
                                  BTREE_INSERT_NOFAIL,
                        __reattach_inode(trans, inode, inode_snapshot));
        if (ret) {
-               bch_err(trans->c, "error reattaching inode %llu: %s",
-                       inode->bi_inum, bch2_err_str(ret));
+               bch_err_msg(trans->c, ret, "reattaching inode %llu", inode->bi_inum);
                return ret;
        }
 
                      bch2_bkey_val_to_text(&buf, c, hash_k), buf.buf))) {
                ret = hash_redo_key(trans, desc, hash_info, k_iter, hash_k);
                if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
-                       bch_err(c, "hash_redo_key err %s", bch2_err_str(ret));
+                       bch_err_fn(c, ret);
                if (ret)
                        return ret;
                ret = -BCH_ERR_transaction_restart_nested;
 
                ret = __write_inode(trans, &u, iter->pos.snapshot);
                if (ret) {
-                       bch_err_msg(c, ret, "in fsck: error updating inode");
+                       if (!bch2_err_matches(ret, BCH_ERR_transaction_restart))
+                               bch_err_msg(c, ret, "in fsck updating inode");
                        return ret;
                }
 
 
                ret = bch2_inode_rm_snapshot(trans, u.bi_inum, iter->pos.snapshot);
                if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
-                       bch_err(c, "error in fsck: error while deleting inode: %s",
-                               bch2_err_str(ret));
+                       bch_err_msg(c, ret, "in fsck deleting inode");
                return ret;
        }
 
                                POS(u.bi_inum, U64_MAX),
                                0, NULL);
                if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
-                       bch_err(c, "error in fsck: error truncating inode: %s",
-                               bch2_err_str(ret));
+                       bch_err_msg(c, ret, "in fsck truncating inode");
                if (ret)
                        return ret;
 
 
                sectors = bch2_count_inode_sectors(trans, u.bi_inum, iter->pos.snapshot);
                if (sectors < 0) {
-                       bch_err(c, "error in fsck: error recounting inode sectors: %s",
-                               bch2_err_str(sectors));
+                       bch_err_msg(c, sectors, "fsck recounting inode sectors");
                        return sectors;
                }
 
        if (do_update) {
                ret = __write_inode(trans, &u, iter->pos.snapshot);
                if (ret) {
-                       bch_err_msg(c, ret, "in fsck: error updating inode");
+                       bch_err_msg(c, ret, "in fsck updating inode");
                        return ret;
                }
        }
 err:
 fsck_err:
-       if (ret)
+       if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
                bch_err_fn(c, ret);
        return ret;
 }
                            w->last_pos.inode, i->snapshot,
                            i->inode.bi_sectors, i->count)) {
                        i->inode.bi_sectors = i->count;
-                       ret = write_inode(trans, &i->inode, i->snapshot);
+                       ret = fsck_write_inode(trans, &i->inode, i->snapshot);
                        if (ret)
                                break;
                }
                                "directory %llu:%u with wrong i_nlink: got %u, should be %llu",
                                w->last_pos.inode, i->snapshot, i->inode.bi_nlink, i->count)) {
                        i->inode.bi_nlink = i->count;
-                       ret = write_inode(trans, &i->inode, i->snapshot);
+                       ret = fsck_write_inode(trans, &i->inode, i->snapshot);
                        if (ret)
                                break;
                }
                        __bch2_btree_insert(trans, BTREE_ID_subvolumes,
                                            &root_subvol.k_i, 0));
                if (ret) {
-                       bch_err(c, "error writing root subvol: %s", bch2_err_str(ret));
+                       bch_err_msg(c, ret, "writing root subvol");
                        goto err;
                }
 
 
                ret = __write_inode(trans, &root_inode, snapshot);
                if (ret)
-                       bch_err(c, "error writing root inode: %s", bch2_err_str(ret));
+                       bch_err_msg(c, ret, "writing root inode");
        }
 err:
 fsck_err:
 
                                                ca->mi.bucket_size));
                        if (ret) {
                                bch2_open_bucket_put(c, ob[nr_got]);
-                               bch_err(c, "error marking new journal buckets: %s", bch2_err_str(ret));
+                               bch_err_msg(c, ret, "marking new journal buckets");
                                break;
                        }
 
 
                           "bch-reclaim/%s", c->name);
        ret = PTR_ERR_OR_ZERO(p);
        if (ret) {
-               bch_err(c, "error creating journal reclaim thread: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "creating journal reclaim thread");
                return ret;
        }
 
 
                        }
 
                        if (ret) {
-                               bch_err(c, "Error updating btree node key: %s",
-                                       bch2_err_str(ret));
+                               bch_err_msg(c, ret, "updating btree node key");
                                break;
                        }
 next:
 
                ret = 0;
 
        if (ret < 0 && !bch2_err_matches(ret, EROFS))
-               bch_err(c, "error from bch2_move_data() in copygc: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "from bch2_move_data()");
 
        moved = atomic64_read(&ctxt->stats->sectors_moved) - moved;
        trace_and_count(c, copygc, c, moved, 0, 0, 0);
 
        ret = rhashtable_init(&move_buckets.table, &bch_move_bucket_params);
        if (ret) {
-               bch_err(c, "error allocating copygc buckets in flight: %s",
-                       bch2_err_str(ret));
+               bch_err_msg(c, ret, "allocating copygc buckets in flight");
                return ret;
        }
 
        t = kthread_create(bch2_copygc_thread, c, "bch-copygc/%s", c->name);
        ret = PTR_ERR_OR_ZERO(t);
        if (ret) {
-               bch_err(c, "error creating copygc thread: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "creating copygc thread");
                return ret;
        }
 
 
        p = kthread_create(bch2_rebalance_thread, c, "bch-rebalance/%s", c->name);
        ret = PTR_ERR_OR_ZERO(p);
        if (ret) {
-               bch_err(c, "error creating rebalance thread: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "creating rebalance thread");
                return ret;
        }
 
 
 
        return ret;
 err:
-       bch_err(c, "error adding replicas entry: %s", bch2_err_str(ret));
+       bch_err_msg(c, ret, "adding replicas entry");
        goto out;
 }
 
 
        if (!test_bit(BCH_FS_STARTED, &c->flags)) {
                ret = bch2_fs_read_write_early(c);
                if (ret) {
-                       bch_err(c, "error deleleting dead snapshots: error going rw: %s", bch2_err_str(ret));
+                       bch_err_msg(c, ret, "error deleleting dead snapshots: error going rw");
                        return ret;
                }
        }
                        NULL, NULL, 0,
                bch2_delete_redundant_snapshot(&trans, &iter, k));
        if (ret) {
-               bch_err(c, "error deleting redundant snapshots: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "deleting redundant snapshots");
                goto err;
        }
 
                           POS_MIN, 0, k,
                bch2_snapshot_set_equiv(&trans, k));
        if (ret) {
-               bch_err(c, "error in bch2_snapshots_set_equiv: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "in bch2_snapshots_set_equiv");
                goto err;
        }
 
 
 
                ret = bch2_subvolume_delete(trans, iter->pos.offset);
                if (ret)
-                       bch_err(c, "error deleting subvolume %llu: %s",
-                               iter->pos.offset, bch2_err_str(ret));
+                       bch_err_msg(c, ret, "deleting subvolume %llu", iter->pos.offset);
                return ret ?: -BCH_ERR_transaction_restart_nested;
        }
 
                for (id = s.data; id < s.data + s.nr; id++) {
                        ret = bch2_trans_run(c, bch2_subvolume_delete(&trans, *id));
                        if (ret) {
-                               bch_err(c, "error deleting subvolume %u: %s", *id, bch2_err_str(ret));
+                               bch_err_msg(c, ret, "deleting subvolume %u", *id);
                                break;
                        }
                }
 
        up_write(&c->state_lock);
        return ret;
 err:
-       bch_err(c, "error starting filesystem: %s", bch2_err_str(ret));
+       bch_err_msg(c, ret, "starting filesystem");
        goto out;
 }
 
                bch2_btree_delete_range(c, BTREE_ID_bucket_gens, start, end,
                                        BTREE_TRIGGER_NORUN, NULL);
        if (ret)
-               bch_err(c, "error removing dev alloc info: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "removing dev alloc info");
 
        return ret;
 }
 
        ret = bch2_dev_data_drop(c, ca->dev_idx, flags);
        if (ret) {
-               bch_err(ca, "Remove failed: error dropping data: %s", bch2_err_str(ret));
+               bch_err_msg(ca, ret, "dropping data");
                goto err;
        }
 
        ret = bch2_dev_remove_alloc(c, ca);
        if (ret) {
-               bch_err(ca, "Remove failed, error deleting alloc info");
+               bch_err_msg(ca, ret, "deleting alloc info");
                goto err;
        }
 
        ret = bch2_journal_flush_device_pins(&c->journal, ca->dev_idx);
        if (ret) {
-               bch_err(ca, "Remove failed: error flushing journal: %s", bch2_err_str(ret));
+               bch_err_msg(ca, ret, "flushing journal");
                goto err;
        }
 
        ret = bch2_journal_flush(&c->journal);
        if (ret) {
-               bch_err(ca, "Remove failed, journal error");
+               bch_err(ca, "journal error");
                goto err;
        }
 
        ret = bch2_replicas_gc2(c);
        if (ret) {
-               bch_err(ca, "Remove failed: error from replicas gc: %s", bch2_err_str(ret));
+               bch_err_msg(ca, ret, "in replicas_gc2()");
                goto err;
        }
 
 
        ret = bch2_read_super(path, &opts, &sb);
        if (ret) {
-               bch_err(c, "device add error: error reading super: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "reading super");
                goto err;
        }
 
 
        ret = bch2_dev_may_add(sb.sb, c);
        if (ret) {
-               bch_err(c, "device add error: %s", bch2_err_str(ret));
+               bch_err_fn(c, ret);
                goto err;
        }
 
 
        ret = bch2_dev_journal_alloc(ca);
        if (ret) {
-               bch_err(c, "device add error: journal alloc failed");
+               bch_err_msg(c, ret, "allocating journal");
                goto err;
        }
 
 
        ret = bch2_sb_from_fs(c, ca);
        if (ret) {
-               bch_err(c, "device add error: new device superblock too small");
+               bch_err_msg(c, ret, "setting up new superblock");
                goto err_unlock;
        }
 
        if (!bch2_sb_resize_members(&ca->disk_sb,
                                le32_to_cpu(mi->field.u64s) +
                                sizeof(dev_mi) / sizeof(u64))) {
-               bch_err(c, "device add error: new device superblock too small");
                ret = -BCH_ERR_ENOSPC_sb_members;
+               bch_err_msg(c, ret, "setting up new superblock");
                goto err_unlock;
        }
 
                if (!bch2_dev_exists(c->disk_sb.sb, mi, dev_idx))
                        goto have_slot;
 no_slot:
-       bch_err(c, "device add error: already have maximum number of devices");
        ret = -BCH_ERR_ENOSPC_sb_members;
+       bch_err_msg(c, ret, "setting up new superblock");
        goto err_unlock;
 
 have_slot:
 
        mi = bch2_sb_resize_members(&c->disk_sb, u64s);
        if (!mi) {
-               bch_err(c, "device add error: no room in superblock for member info");
                ret = -BCH_ERR_ENOSPC_sb_members;
+               bch_err_msg(c, ret, "setting up new superblock");
                goto err_unlock;
        }
 
        if (BCH_MEMBER_GROUP(&dev_mi)) {
                ret = __bch2_dev_group_set(c, ca, label.buf);
                if (ret) {
-                       bch_err(c, "device add error: error setting label");
+                       bch_err_msg(c, ret, "creating new label");
                        goto err_unlock;
                }
        }
 
        ret = bch2_trans_mark_dev_sb(c, ca);
        if (ret) {
-               bch_err(c, "device add error: error marking new superblock: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "marking new superblock");
                goto err_late;
        }
 
        ret = bch2_fs_freespace_init(c);
        if (ret) {
-               bch_err(c, "device add error: error initializing free space: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "initializing free space");
                goto err_late;
        }
 
 
        ret = bch2_dev_in_fs(c->disk_sb.sb, sb.sb);
        if (ret) {
-               bch_err(c, "error bringing %s online: %s", path, bch2_err_str(ret));
+               bch_err_msg(c, ret, "bringing %s online", path);
                goto err;
        }
 
 
        ret = bch2_trans_mark_dev_sb(c, ca);
        if (ret) {
-               bch_err(c, "error bringing %s online: error from bch2_trans_mark_dev_sb: %s",
-                       path, bch2_err_str(ret));
+               bch_err_msg(c, ret, "bringing %s online: error from bch2_trans_mark_dev_sb", path);
                goto err;
        }
 
 
        ret = bch2_fs_freespace_init(c);
        if (ret)
-               bch_err(c, "device add error: error initializing free space: %s", bch2_err_str(ret));
+               bch_err_msg(c, ret, "initializing free space");
 
        up_write(&c->state_lock);
        return 0;
 
        ret = bch2_dev_buckets_resize(c, ca, nbuckets);
        if (ret) {
-               bch_err(ca, "Resize error: %s", bch2_err_str(ret));
+               bch_err_msg(ca, ret, "resizing buckets");
                goto err;
        }