1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 #include "bcachefs.h" 3 #include "bcachefs.h" 4 #include "journal_sb.h" 4 #include "journal_sb.h" 5 #include "darray.h" 5 #include "darray.h" 6 6 7 #include <linux/sort.h> 7 #include <linux/sort.h> 8 8 9 /* BCH_SB_FIELD_journal: */ 9 /* BCH_SB_FIELD_journal: */ 10 10 11 static int u64_cmp(const void *_l, const void 11 static int u64_cmp(const void *_l, const void *_r) 12 { 12 { 13 const u64 *l = _l; 13 const u64 *l = _l; 14 const u64 *r = _r; 14 const u64 *r = _r; 15 15 16 return cmp_int(*l, *r); 16 return cmp_int(*l, *r); 17 } 17 } 18 18 19 static int bch2_sb_journal_validate(struct bch !! 19 static int bch2_sb_journal_validate(struct bch_sb *sb, 20 enum bch_valid !! 20 struct bch_sb_field *f, >> 21 struct printbuf *err) 21 { 22 { 22 struct bch_sb_field_journal *journal = 23 struct bch_sb_field_journal *journal = field_to_type(f, journal); 23 struct bch_member m = bch2_sb_member_g 24 struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx); 24 int ret = -BCH_ERR_invalid_sb_journal; 25 int ret = -BCH_ERR_invalid_sb_journal; 25 unsigned nr; 26 unsigned nr; 26 unsigned i; 27 unsigned i; 27 u64 *b; 28 u64 *b; 28 29 29 nr = bch2_nr_journal_buckets(journal); 30 nr = bch2_nr_journal_buckets(journal); 30 if (!nr) 31 if (!nr) 31 return 0; 32 return 0; 32 33 33 b = kmalloc_array(nr, sizeof(u64), GFP 34 b = kmalloc_array(nr, sizeof(u64), GFP_KERNEL); 34 if (!b) 35 if (!b) 35 return -BCH_ERR_ENOMEM_sb_jour 36 return -BCH_ERR_ENOMEM_sb_journal_validate; 36 37 37 for (i = 0; i < nr; i++) 38 for (i = 0; i < nr; i++) 38 b[i] = le64_to_cpu(journal->bu 39 b[i] = le64_to_cpu(journal->buckets[i]); 39 40 40 sort(b, nr, sizeof(u64), u64_cmp, NULL 41 sort(b, nr, sizeof(u64), u64_cmp, NULL); 41 42 42 if (!b[0]) { 43 if (!b[0]) { 43 prt_printf(err, "journal bucke 44 prt_printf(err, "journal bucket at sector 0"); 44 goto err; 45 goto err; 45 } 46 } 46 47 47 if (b[0] < le16_to_cpu(m.first_bucket) 48 if (b[0] < le16_to_cpu(m.first_bucket)) { 48 prt_printf(err, "journal bucke 49 prt_printf(err, "journal bucket %llu before first bucket %u", 49 b[0], le16_to_cpu(m.fir 50 b[0], le16_to_cpu(m.first_bucket)); 50 goto err; 51 goto err; 51 } 52 } 52 53 53 if (b[nr - 1] >= le64_to_cpu(m.nbucket 54 if (b[nr - 1] >= le64_to_cpu(m.nbuckets)) { 54 prt_printf(err, "journal bucke 55 prt_printf(err, "journal bucket %llu past end of device (nbuckets %llu)", 55 b[nr - 1], le64_to_cpu( 56 b[nr - 1], le64_to_cpu(m.nbuckets)); 56 goto err; 57 goto err; 57 } 58 } 58 59 59 for (i = 0; i + 1 < nr; i++) 60 for (i = 0; i + 1 < nr; i++) 60 if (b[i] == b[i + 1]) { 61 if (b[i] == b[i + 1]) { 61 prt_printf(err, "dupli 62 prt_printf(err, "duplicate journal buckets %llu", b[i]); 62 goto err; 63 goto err; 63 } 64 } 64 65 65 ret = 0; 66 ret = 0; 66 err: 67 err: 67 kfree(b); 68 kfree(b); 68 return ret; 69 return ret; 69 } 70 } 70 71 71 static void bch2_sb_journal_to_text(struct pri 72 static void bch2_sb_journal_to_text(struct printbuf *out, struct bch_sb *sb, 72 struct bch 73 struct bch_sb_field *f) 73 { 74 { 74 struct bch_sb_field_journal *journal = 75 struct bch_sb_field_journal *journal = field_to_type(f, journal); 75 unsigned i, nr = bch2_nr_journal_bucke 76 unsigned i, nr = bch2_nr_journal_buckets(journal); 76 77 77 prt_printf(out, "Buckets: "); 78 prt_printf(out, "Buckets: "); 78 for (i = 0; i < nr; i++) 79 for (i = 0; i < nr; i++) 79 prt_printf(out, " %llu", le64_ 80 prt_printf(out, " %llu", le64_to_cpu(journal->buckets[i])); 80 prt_newline(out); 81 prt_newline(out); 81 } 82 } 82 83 83 const struct bch_sb_field_ops bch_sb_field_ops 84 const struct bch_sb_field_ops bch_sb_field_ops_journal = { 84 .validate = bch2_sb_journal_vali 85 .validate = bch2_sb_journal_validate, 85 .to_text = bch2_sb_journal_to_t 86 .to_text = bch2_sb_journal_to_text, 86 }; 87 }; 87 88 88 struct u64_range { 89 struct u64_range { 89 u64 start; 90 u64 start; 90 u64 end; 91 u64 end; 91 }; 92 }; 92 93 93 static int u64_range_cmp(const void *_l, const 94 static int u64_range_cmp(const void *_l, const void *_r) 94 { 95 { 95 const struct u64_range *l = _l; 96 const struct u64_range *l = _l; 96 const struct u64_range *r = _r; 97 const struct u64_range *r = _r; 97 98 98 return cmp_int(l->start, r->start); 99 return cmp_int(l->start, r->start); 99 } 100 } 100 101 101 static int bch2_sb_journal_v2_validate(struct !! 102 static int bch2_sb_journal_v2_validate(struct bch_sb *sb, 102 enum bch_valid !! 103 struct bch_sb_field *f, >> 104 struct printbuf *err) 103 { 105 { 104 struct bch_sb_field_journal_v2 *journa 106 struct bch_sb_field_journal_v2 *journal = field_to_type(f, journal_v2); 105 struct bch_member m = bch2_sb_member_g 107 struct bch_member m = bch2_sb_member_get(sb, sb->dev_idx); 106 int ret = -BCH_ERR_invalid_sb_journal; 108 int ret = -BCH_ERR_invalid_sb_journal; 107 u64 sum = 0; << 108 unsigned nr; 109 unsigned nr; 109 unsigned i; 110 unsigned i; 110 struct u64_range *b; 111 struct u64_range *b; 111 112 112 nr = bch2_sb_field_journal_v2_nr_entri 113 nr = bch2_sb_field_journal_v2_nr_entries(journal); 113 if (!nr) 114 if (!nr) 114 return 0; 115 return 0; 115 116 116 b = kmalloc_array(nr, sizeof(*b), GFP_ 117 b = kmalloc_array(nr, sizeof(*b), GFP_KERNEL); 117 if (!b) 118 if (!b) 118 return -BCH_ERR_ENOMEM_sb_jour 119 return -BCH_ERR_ENOMEM_sb_journal_v2_validate; 119 120 120 for (i = 0; i < nr; i++) { 121 for (i = 0; i < nr; i++) { 121 b[i].start = le64_to_cpu(journ 122 b[i].start = le64_to_cpu(journal->d[i].start); 122 b[i].end = b[i].start + le64_t 123 b[i].end = b[i].start + le64_to_cpu(journal->d[i].nr); 123 << 124 if (b[i].end <= b[i].start) { << 125 prt_printf(err, "journ << 126 le64_to_cpu << 127 le64_to_cpu << 128 goto err; << 129 } << 130 << 131 sum += le64_to_cpu(journal->d[ << 132 } 124 } 133 125 134 sort(b, nr, sizeof(*b), u64_range_cmp, 126 sort(b, nr, sizeof(*b), u64_range_cmp, NULL); 135 127 136 if (!b[0].start) { 128 if (!b[0].start) { 137 prt_printf(err, "journal bucke 129 prt_printf(err, "journal bucket at sector 0"); 138 goto err; 130 goto err; 139 } 131 } 140 132 141 if (b[0].start < le16_to_cpu(m.first_b 133 if (b[0].start < le16_to_cpu(m.first_bucket)) { 142 prt_printf(err, "journal bucke 134 prt_printf(err, "journal bucket %llu before first bucket %u", 143 b[0].start, le16_to_cpu 135 b[0].start, le16_to_cpu(m.first_bucket)); 144 goto err; 136 goto err; 145 } 137 } 146 138 147 if (b[nr - 1].end > le64_to_cpu(m.nbuc 139 if (b[nr - 1].end > le64_to_cpu(m.nbuckets)) { 148 prt_printf(err, "journal bucke 140 prt_printf(err, "journal bucket %llu past end of device (nbuckets %llu)", 149 b[nr - 1].end - 1, le64 141 b[nr - 1].end - 1, le64_to_cpu(m.nbuckets)); 150 goto err; 142 goto err; 151 } 143 } 152 144 153 for (i = 0; i + 1 < nr; i++) { 145 for (i = 0; i + 1 < nr; i++) { 154 if (b[i].end > b[i + 1].start) 146 if (b[i].end > b[i + 1].start) { 155 prt_printf(err, "dupli 147 prt_printf(err, "duplicate journal buckets in ranges %llu-%llu, %llu-%llu", 156 b[i].start, b[i 148 b[i].start, b[i].end, b[i + 1].start, b[i + 1].end); 157 goto err; 149 goto err; 158 } 150 } 159 } << 160 << 161 if (sum > UINT_MAX) { << 162 prt_printf(err, "too many jour << 163 goto err; << 164 } 151 } 165 152 166 ret = 0; 153 ret = 0; 167 err: 154 err: 168 kfree(b); 155 kfree(b); 169 return ret; 156 return ret; 170 } 157 } 171 158 172 static void bch2_sb_journal_v2_to_text(struct 159 static void bch2_sb_journal_v2_to_text(struct printbuf *out, struct bch_sb *sb, 173 struct bch 160 struct bch_sb_field *f) 174 { 161 { 175 struct bch_sb_field_journal_v2 *journa 162 struct bch_sb_field_journal_v2 *journal = field_to_type(f, journal_v2); 176 unsigned i, nr = bch2_sb_field_journal 163 unsigned i, nr = bch2_sb_field_journal_v2_nr_entries(journal); 177 164 178 prt_printf(out, "Buckets: "); 165 prt_printf(out, "Buckets: "); 179 for (i = 0; i < nr; i++) 166 for (i = 0; i < nr; i++) 180 prt_printf(out, " %llu-%llu", 167 prt_printf(out, " %llu-%llu", 181 le64_to_cpu(journal->d[ 168 le64_to_cpu(journal->d[i].start), 182 le64_to_cpu(journal->d[ 169 le64_to_cpu(journal->d[i].start) + le64_to_cpu(journal->d[i].nr)); 183 prt_newline(out); 170 prt_newline(out); 184 } 171 } 185 172 186 const struct bch_sb_field_ops bch_sb_field_ops 173 const struct bch_sb_field_ops bch_sb_field_ops_journal_v2 = { 187 .validate = bch2_sb_journal_v2_v 174 .validate = bch2_sb_journal_v2_validate, 188 .to_text = bch2_sb_journal_v2_t 175 .to_text = bch2_sb_journal_v2_to_text, 189 }; 176 }; 190 177 191 int bch2_journal_buckets_to_sb(struct bch_fs * 178 int bch2_journal_buckets_to_sb(struct bch_fs *c, struct bch_dev *ca, 192 u64 *buckets, u 179 u64 *buckets, unsigned nr) 193 { 180 { 194 struct bch_sb_field_journal_v2 *j; 181 struct bch_sb_field_journal_v2 *j; 195 unsigned i, dst = 0, nr_compacted = 1; 182 unsigned i, dst = 0, nr_compacted = 1; 196 183 197 if (c) 184 if (c) 198 lockdep_assert_held(&c->sb_loc 185 lockdep_assert_held(&c->sb_lock); 199 186 200 if (!nr) { 187 if (!nr) { 201 bch2_sb_field_delete(&ca->disk 188 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal); 202 bch2_sb_field_delete(&ca->disk 189 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal_v2); 203 return 0; 190 return 0; 204 } 191 } 205 192 206 for (i = 0; i + 1 < nr; i++) 193 for (i = 0; i + 1 < nr; i++) 207 if (buckets[i] + 1 != buckets[ 194 if (buckets[i] + 1 != buckets[i + 1]) 208 nr_compacted++; 195 nr_compacted++; 209 196 210 j = bch2_sb_field_resize(&ca->disk_sb, 197 j = bch2_sb_field_resize(&ca->disk_sb, journal_v2, 211 (sizeof(*j) + sizeof( 198 (sizeof(*j) + sizeof(j->d[0]) * nr_compacted) / sizeof(u64)); 212 if (!j) 199 if (!j) 213 return -BCH_ERR_ENOSPC_sb_jour 200 return -BCH_ERR_ENOSPC_sb_journal; 214 201 215 bch2_sb_field_delete(&ca->disk_sb, BCH 202 bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal); 216 203 217 j->d[dst].start = cpu_to_le64(buckets[ 204 j->d[dst].start = cpu_to_le64(buckets[0]); 218 j->d[dst].nr = cpu_to_le64(1); 205 j->d[dst].nr = cpu_to_le64(1); 219 206 220 for (i = 1; i < nr; i++) { 207 for (i = 1; i < nr; i++) { 221 if (buckets[i] == buckets[i - 208 if (buckets[i] == buckets[i - 1] + 1) { 222 le64_add_cpu(&j->d[dst 209 le64_add_cpu(&j->d[dst].nr, 1); 223 } else { 210 } else { 224 dst++; 211 dst++; 225 j->d[dst].start = cpu_ 212 j->d[dst].start = cpu_to_le64(buckets[i]); 226 j->d[dst].nr = cpu_ 213 j->d[dst].nr = cpu_to_le64(1); 227 } 214 } 228 } 215 } 229 216 230 BUG_ON(dst + 1 != nr_compacted); 217 BUG_ON(dst + 1 != nr_compacted); 231 return 0; 218 return 0; 232 } 219 } 233 220
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.