diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/bcachefs.h | 1 | ||||
-rw-r--r-- | fs/bcachefs/fs.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/fsck.c | 53 | ||||
-rw-r--r-- | fs/bcachefs/recovery.c | 3 | ||||
-rw-r--r-- | fs/bcachefs/sb-errors_format.h | 4 | ||||
-rw-r--r-- | fs/bcachefs/sb-members.c | 29 | ||||
-rw-r--r-- | fs/bcachefs/sb-members.h | 1 | ||||
-rw-r--r-- | fs/bcachefs/super-io.c | 5 | ||||
-rw-r--r-- | fs/bcachefs/util.c | 5 |
9 files changed, 88 insertions, 15 deletions
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h index 004044e105ea..41c6d8865a74 100644 --- a/fs/bcachefs/bcachefs.h +++ b/fs/bcachefs/bcachefs.h @@ -819,6 +819,7 @@ struct bch_fs { struct work_struct read_only_work; struct bch_dev __rcu *devs[BCH_SB_MEMBERS_MAX]; + struct bch_devs_mask devs_removed; struct bch_accounting_mem accounting; diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index 28a86bb644f7..f9bc99eb2d02 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -2563,9 +2563,11 @@ got_sb: sb->s_shrink->seeks = 0; +#if IS_ENABLED(CONFIG_UNICODE) if (!bch2_fs_casefold_enabled(c)) sb->s_encoding = c->cf_encoding; generic_set_sb_d_ops(sb); +#endif vinode = bch2_vfs_inode_get(c, BCACHEFS_ROOT_SUBVOL_INUM); ret = PTR_ERR_OR_ZERO(vinode); diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index 62756f465e56..00afe0a3593f 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -1500,6 +1500,10 @@ static int check_key_has_inode(struct btree_trans *trans, SPOS(k.k->p.inode, 0, k.k->p.snapshot), POS(k.k->p.inode, U64_MAX), 0, k2, ret) { + if (k.k->type == KEY_TYPE_error || + k.k->type == KEY_TYPE_hash_whiteout) + continue; + nr_keys++; if (nr_keys <= 10) { bch2_bkey_val_to_text(&buf, c, k2); @@ -1512,9 +1516,11 @@ static int check_key_has_inode(struct btree_trans *trans, if (ret) goto err; + unsigned reconstruct_limit = iter->btree_id == BTREE_ID_extents ? 3 : 0; + if (nr_keys > 100) prt_printf(&buf, "found > %u keys for this missing inode\n", nr_keys); - else if (nr_keys > 10) + else if (nr_keys > reconstruct_limit) prt_printf(&buf, "found %u keys for this missing inode\n", nr_keys); if (!have_inode) { @@ -1572,6 +1578,44 @@ reconstruct: goto out; } +static int maybe_reconstruct_inum_btree(struct btree_trans *trans, + u64 inum, u32 snapshot, + enum btree_id btree) +{ + struct btree_iter iter; + struct bkey_s_c k; + int ret = 0; + + for_each_btree_key_max_norestart(trans, iter, btree, + SPOS(inum, 0, snapshot), + POS(inum, U64_MAX), + 0, k, ret) { + ret = 1; + break; + } + bch2_trans_iter_exit(trans, &iter); + + if (ret <= 0) + return ret; + + if (fsck_err(trans, missing_inode_with_contents, + "inode %llu:%u type %s missing, but contents found: reconstruct?", + inum, snapshot, + btree == BTREE_ID_extents ? "reg" : "dir")) + return reconstruct_inode(trans, btree, snapshot, inum) ?: + bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc) ?: + bch_err_throw(trans->c, transaction_restart_commit); +fsck_err: + return ret; +} + +static int maybe_reconstruct_inum(struct btree_trans *trans, + u64 inum, u32 snapshot) +{ + return maybe_reconstruct_inum_btree(trans, inum, snapshot, BTREE_ID_extents) ?: + maybe_reconstruct_inum_btree(trans, inum, snapshot, BTREE_ID_dirents); +} + static int check_i_sectors_notnested(struct btree_trans *trans, struct inode_walker *w) { struct bch_fs *c = trans->c; @@ -2366,6 +2410,13 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter, if (ret) goto err; + if (!target->inodes.nr) { + ret = maybe_reconstruct_inum(trans, le64_to_cpu(d.v->d_inum), + d.k->p.snapshot); + if (ret) + return ret; + } + if (fsck_err_on(!target->inodes.nr, trans, dirent_to_missing_inode, "dirent points to missing inode:\n%s", diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index d0b7e3a36a54..974f8bf9a574 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -1177,9 +1177,10 @@ int bch2_fs_initialize(struct bch_fs *c) for_each_member_device(c, ca) { m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx); SET_BCH_MEMBER_FREESPACE_INITIALIZED(m, false); - ca->mi = bch2_mi_to_cpu(m); } + bch2_sb_members_to_cpu(c); + bch2_write_super(c); mutex_unlock(&c->sb_lock); diff --git a/fs/bcachefs/sb-errors_format.h b/fs/bcachefs/sb-errors_format.h index 3ecac2524118..dd4ee46606d7 100644 --- a/fs/bcachefs/sb-errors_format.h +++ b/fs/bcachefs/sb-errors_format.h @@ -158,6 +158,7 @@ enum bch_fsck_flags { x(extent_ptrs_unwritten, 140, 0) \ x(extent_ptrs_written_and_unwritten, 141, 0) \ x(ptr_to_invalid_device, 142, 0) \ + x(ptr_to_removed_device, 322, 0) \ x(ptr_to_duplicate_device, 143, 0) \ x(ptr_after_last_bucket, 144, 0) \ x(ptr_before_first_bucket, 145, 0) \ @@ -291,6 +292,7 @@ enum bch_fsck_flags { x(inode_points_to_missing_dirent, 249, FSCK_AUTOFIX) \ x(inode_points_to_wrong_dirent, 250, FSCK_AUTOFIX) \ x(inode_bi_parent_nonzero, 251, 0) \ + x(missing_inode_with_contents, 321, FSCK_AUTOFIX) \ x(dirent_to_missing_parent_subvol, 252, 0) \ x(dirent_not_visible_in_parent_subvol, 253, 0) \ x(subvol_fs_path_parent_wrong, 254, 0) \ @@ -332,7 +334,7 @@ enum bch_fsck_flags { x(dirent_stray_data_after_cf_name, 305, 0) \ x(rebalance_work_incorrectly_set, 309, FSCK_AUTOFIX) \ x(rebalance_work_incorrectly_unset, 310, FSCK_AUTOFIX) \ - x(MAX, 321, 0) + x(MAX, 323, 0) enum bch_sb_error_id { #define x(t, n, ...) BCH_FSCK_ERR_##t = n, diff --git a/fs/bcachefs/sb-members.c b/fs/bcachefs/sb-members.c index 6245e342a8a8..f2abe92ca130 100644 --- a/fs/bcachefs/sb-members.c +++ b/fs/bcachefs/sb-members.c @@ -15,10 +15,15 @@ int bch2_dev_missing_bkey(struct bch_fs *c, struct bkey_s_c k, unsigned dev) struct printbuf buf = PRINTBUF; bch2_log_msg_start(c, &buf); - prt_printf(&buf, "pointer to nonexistent device %u in key\n", dev); + bool removed = test_bit(dev, c->devs_removed.d); + + prt_printf(&buf, "pointer to %s device %u in key\n", + removed ? "removed" : "nonexistent", dev); bch2_bkey_val_to_text(&buf, c, k); - bool print = bch2_count_fsck_err(c, ptr_to_invalid_device, &buf); + bool print = removed + ? bch2_count_fsck_err(c, ptr_to_removed_device, &buf) + : bch2_count_fsck_err(c, ptr_to_invalid_device, &buf); int ret = bch2_run_explicit_recovery_pass(c, &buf, BCH_RECOVERY_PASS_check_allocations, 0); @@ -32,7 +37,9 @@ int bch2_dev_missing_bkey(struct bch_fs *c, struct bkey_s_c k, unsigned dev) void bch2_dev_missing_atomic(struct bch_fs *c, unsigned dev) { if (dev != BCH_SB_MEMBER_INVALID) - bch2_fs_inconsistent(c, "pointer to nonexistent device %u", dev); + bch2_fs_inconsistent(c, "pointer to %s device %u", + test_bit(dev, c->devs_removed.d) + ? "removed" : "nonexistent", dev); } void bch2_dev_bucket_missing(struct bch_dev *ca, u64 bucket) @@ -413,6 +420,22 @@ void bch2_sb_members_from_cpu(struct bch_fs *c) } } +void bch2_sb_members_to_cpu(struct bch_fs *c) +{ + for_each_member_device(c, ca) { + struct bch_member m = bch2_sb_member_get(c->disk_sb.sb, ca->dev_idx); + ca->mi = bch2_mi_to_cpu(&m); + } + + struct bch_sb_field_members_v2 *mi2 = bch2_sb_field_get(c->disk_sb.sb, members_v2); + if (mi2) + for (unsigned i = 0; i < c->sb.nr_devices; i++) { + struct bch_member m = members_v2_get(mi2, i); + bool removed = uuid_equal(&m.uuid, &BCH_SB_MEMBER_DELETED_UUID); + mod_bit(i, c->devs_removed.d, removed); + } +} + void bch2_dev_io_errors_to_text(struct printbuf *out, struct bch_dev *ca) { struct bch_fs *c = ca->fs; diff --git a/fs/bcachefs/sb-members.h b/fs/bcachefs/sb-members.h index 5dcc2017f85b..0d363a1cdd47 100644 --- a/fs/bcachefs/sb-members.h +++ b/fs/bcachefs/sb-members.h @@ -365,6 +365,7 @@ static inline struct bch_member_cpu bch2_mi_to_cpu(struct bch_member *mi) } void bch2_sb_members_from_cpu(struct bch_fs *); +void bch2_sb_members_to_cpu(struct bch_fs *); void bch2_dev_io_errors_to_text(struct printbuf *, struct bch_dev *); void bch2_dev_errors_reset(struct bch_dev *); diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c index 6c2e1d647403..85e460d10e9d 100644 --- a/fs/bcachefs/super-io.c +++ b/fs/bcachefs/super-io.c @@ -632,10 +632,7 @@ static void bch2_sb_update(struct bch_fs *c) c->sb.btrees_lost_data = le64_to_cpu(ext->btrees_lost_data); } - for_each_member_device(c, ca) { - struct bch_member m = bch2_sb_member_get(src, ca->dev_idx); - ca->mi = bch2_mi_to_cpu(&m); - } + bch2_sb_members_to_cpu(c); } static int __copy_super(struct bch_sb_handle *dst_handle, struct bch_sb *src) diff --git a/fs/bcachefs/util.c b/fs/bcachefs/util.c index 05b40debf211..7a4436fd4441 100644 --- a/fs/bcachefs/util.c +++ b/fs/bcachefs/util.c @@ -299,17 +299,12 @@ int bch2_save_backtrace(bch_stacktrace *stack, struct task_struct *task, unsigne if (ret) return ret; - if (!down_read_trylock(&task->signal->exec_update_lock)) - return -1; - do { nr_entries = stack_trace_save_tsk(task, stack->data, stack->size, skipnr + 1); } while (nr_entries == stack->size && !(ret = darray_make_room_gfp(stack, stack->size * 2, gfp))); stack->nr = nr_entries; - up_read(&task->signal->exec_update_lock); - return ret; #else return 0; |