Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bcachefs: Ensure devices are always correctly initialized

We can't mark device superblocks or allocate journal on a device that
isn't online.

That means we may need to do this on every mount, because we may have
formatted a new filesystem and then done the first mount
(bch2_fs_initialize()) in degraded mode.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>

+73 -36
+24 -8
fs/bcachefs/buckets.c
··· 1825 1825 bch2_data_types[type], 1826 1826 bch2_data_types[type]); 1827 1827 ret = -EIO; 1828 - goto out; 1828 + goto err; 1829 1829 } 1830 1830 1831 - a->v.data_type = type; 1832 - a->v.dirty_sectors = sectors; 1833 - 1834 - ret = bch2_trans_update(trans, &iter, &a->k_i, 0); 1835 - if (ret) 1836 - goto out; 1837 - out: 1831 + if (a->v.data_type != type || 1832 + a->v.dirty_sectors != sectors) { 1833 + a->v.data_type = type; 1834 + a->v.dirty_sectors = sectors; 1835 + ret = bch2_trans_update(trans, &iter, &a->k_i, 0); 1836 + } 1837 + err: 1838 1838 bch2_trans_iter_exit(trans, &iter); 1839 1839 return ret; 1840 1840 } ··· 1927 1927 if (ret) 1928 1928 bch_err_fn(c, ret); 1929 1929 return ret; 1930 + } 1931 + 1932 + int bch2_trans_mark_dev_sbs(struct bch_fs *c) 1933 + { 1934 + struct bch_dev *ca; 1935 + unsigned i; 1936 + 1937 + for_each_online_member(ca, c, i) { 1938 + int ret = bch2_trans_mark_dev_sb(c, ca); 1939 + if (ret) { 1940 + percpu_ref_put(&ca->ref); 1941 + return ret; 1942 + } 1943 + } 1944 + 1945 + return 0; 1930 1946 } 1931 1947 1932 1948 /* Disk reservations: */
+1
fs/bcachefs/buckets.h
··· 345 345 int bch2_trans_mark_metadata_bucket(struct btree_trans *, struct bch_dev *, 346 346 size_t, enum bch_data_type, unsigned); 347 347 int bch2_trans_mark_dev_sb(struct bch_fs *, struct bch_dev *); 348 + int bch2_trans_mark_dev_sbs(struct bch_fs *); 348 349 349 350 static inline bool is_superblock_bucket(struct bch_dev *ca, u64 b) 350 351 {
+19
fs/bcachefs/journal.c
··· 1019 1019 return ret; 1020 1020 } 1021 1021 1022 + int bch2_fs_journal_alloc(struct bch_fs *c) 1023 + { 1024 + struct bch_dev *ca; 1025 + unsigned i; 1026 + 1027 + for_each_online_member(ca, c, i) { 1028 + if (ca->journal.nr) 1029 + continue; 1030 + 1031 + int ret = bch2_dev_journal_alloc(ca); 1032 + if (ret) { 1033 + percpu_ref_put(&ca->io_ref); 1034 + return ret; 1035 + } 1036 + } 1037 + 1038 + return 0; 1039 + } 1040 + 1022 1041 /* startup/shutdown: */ 1023 1042 1024 1043 static bool bch2_journal_writing_to_device(struct journal *j, unsigned dev_idx)
+1
fs/bcachefs/journal.h
··· 534 534 int bch2_set_nr_journal_buckets(struct bch_fs *, struct bch_dev *, 535 535 unsigned nr); 536 536 int bch2_dev_journal_alloc(struct bch_dev *); 537 + int bch2_fs_journal_alloc(struct bch_fs *); 537 538 538 539 void bch2_dev_journal_stop(struct journal *, struct bch_dev *); 539 540
+9 -15
fs/bcachefs/recovery.c
··· 946 946 for (i = 0; i < BTREE_ID_NR; i++) 947 947 bch2_btree_root_alloc(c, i); 948 948 949 - for_each_online_member(ca, c, i) 949 + for_each_member_device(ca, c, i) 950 950 bch2_dev_usage_init(ca); 951 951 952 - for_each_online_member(ca, c, i) { 953 - ret = bch2_dev_journal_alloc(ca); 954 - if (ret) { 955 - percpu_ref_put(&ca->io_ref); 956 - goto err; 957 - } 958 - } 952 + ret = bch2_fs_journal_alloc(c); 953 + if (ret) 954 + goto err; 959 955 960 956 /* 961 957 * journal_res_get() will crash if called before this has ··· 969 973 * btree updates 970 974 */ 971 975 bch_verbose(c, "marking superblocks"); 972 - for_each_member_device(ca, c, i) { 973 - ret = bch2_trans_mark_dev_sb(c, ca); 974 - if (ret) { 975 - percpu_ref_put(&ca->ref); 976 - goto err; 977 - } 976 + ret = bch2_trans_mark_dev_sbs(c); 977 + bch_err_msg(c, ret, "marking superblocks"); 978 + if (ret) 979 + goto err; 978 980 981 + for_each_online_member(ca, c, i) 979 982 ca->new_fs_bucket_idx = 0; 980 - } 981 983 982 984 ret = bch2_fs_freespace_init(c); 983 985 if (ret)
+2
fs/bcachefs/recovery_types.h
··· 14 14 x(snapshots_read, PASS_ALWAYS) \ 15 15 x(check_topology, 0) \ 16 16 x(check_allocations, PASS_FSCK) \ 17 + x(trans_mark_dev_sbs, PASS_ALWAYS|PASS_SILENT) \ 18 + x(fs_journal_alloc, PASS_ALWAYS|PASS_SILENT) \ 17 19 x(set_may_go_rw, PASS_ALWAYS|PASS_SILENT) \ 18 20 x(journal_replay, PASS_ALWAYS) \ 19 21 x(check_alloc_info, PASS_FSCK) \
+17 -13
fs/bcachefs/super.c
··· 949 949 } 950 950 951 951 for_each_online_member(ca, c, i) 952 - bch2_sb_from_fs(c, ca); 953 - 954 - for_each_online_member(ca, c, i) 955 952 bch2_members_v2_get_mut(c->disk_sb.sb, i)->last_mount = cpu_to_le64(now); 956 953 957 954 mutex_unlock(&c->sb_lock); ··· 1680 1683 1681 1684 ret = bch2_trans_mark_dev_sb(c, ca); 1682 1685 if (ret) { 1683 - bch_err_msg(c, ret, "marking new superblock"); 1686 + bch_err_msg(ca, ret, "marking new superblock"); 1684 1687 goto err_late; 1685 1688 } 1686 1689 1687 1690 ret = bch2_fs_freespace_init(c); 1688 1691 if (ret) { 1689 - bch_err_msg(c, ret, "initializing free space"); 1692 + bch_err_msg(ca, ret, "initializing free space"); 1690 1693 goto err_late; 1691 1694 } 1692 1695 ··· 1754 1757 if (ca->mi.state == BCH_MEMBER_STATE_rw) 1755 1758 __bch2_dev_read_write(c, ca); 1756 1759 1760 + if (!ca->mi.freespace_initialized) { 1761 + ret = bch2_dev_freespace_init(c, ca, 0, ca->mi.nbuckets); 1762 + bch_err_msg(ca, ret, "initializing free space"); 1763 + if (ret) 1764 + goto err; 1765 + } 1766 + 1767 + if (!ca->journal.nr) { 1768 + ret = bch2_dev_journal_alloc(ca); 1769 + bch_err_msg(ca, ret, "allocating journal"); 1770 + if (ret) 1771 + goto err; 1772 + } 1773 + 1757 1774 mutex_lock(&c->sb_lock); 1758 - struct bch_member *m = bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx); 1759 - 1760 - m->last_mount = 1775 + bch2_members_v2_get_mut(c->disk_sb.sb, ca->dev_idx)->last_mount = 1761 1776 cpu_to_le64(ktime_get_real_seconds()); 1762 - 1763 1777 bch2_write_super(c); 1764 1778 mutex_unlock(&c->sb_lock); 1765 - 1766 - ret = bch2_fs_freespace_init(c); 1767 - if (ret) 1768 - bch_err_msg(c, ret, "initializing free space"); 1769 1779 1770 1780 up_write(&c->state_lock); 1771 1781 return 0;