1 // SPDX-License-Identifier: GPL-2.0
4 #include "journal_sb.h"
7 #include <linux/sort.h>
9 /* BCH_SB_FIELD_journal: */
11 static int u64_cmp(const void *_l
, const void *_r
)
16 return cmp_int(*l
, *r
);
19 static int bch2_sb_journal_validate(struct bch_sb
*sb
, struct bch_sb_field
*f
,
20 enum bch_validate_flags flags
, struct printbuf
*err
)
22 struct bch_sb_field_journal
*journal
= field_to_type(f
, journal
);
23 struct bch_member m
= bch2_sb_member_get(sb
, sb
->dev_idx
);
24 int ret
= -BCH_ERR_invalid_sb_journal
;
29 nr
= bch2_nr_journal_buckets(journal
);
33 b
= kmalloc_array(nr
, sizeof(u64
), GFP_KERNEL
);
35 return -BCH_ERR_ENOMEM_sb_journal_validate
;
37 for (i
= 0; i
< nr
; i
++)
38 b
[i
] = le64_to_cpu(journal
->buckets
[i
]);
40 sort(b
, nr
, sizeof(u64
), u64_cmp
, NULL
);
43 prt_printf(err
, "journal bucket at sector 0");
47 if (b
[0] < le16_to_cpu(m
.first_bucket
)) {
48 prt_printf(err
, "journal bucket %llu before first bucket %u",
49 b
[0], le16_to_cpu(m
.first_bucket
));
53 if (b
[nr
- 1] >= le64_to_cpu(m
.nbuckets
)) {
54 prt_printf(err
, "journal bucket %llu past end of device (nbuckets %llu)",
55 b
[nr
- 1], le64_to_cpu(m
.nbuckets
));
59 for (i
= 0; i
+ 1 < nr
; i
++)
60 if (b
[i
] == b
[i
+ 1]) {
61 prt_printf(err
, "duplicate journal buckets %llu", b
[i
]);
71 static void bch2_sb_journal_to_text(struct printbuf
*out
, struct bch_sb
*sb
,
72 struct bch_sb_field
*f
)
74 struct bch_sb_field_journal
*journal
= field_to_type(f
, journal
);
75 unsigned i
, nr
= bch2_nr_journal_buckets(journal
);
77 prt_printf(out
, "Buckets: ");
78 for (i
= 0; i
< nr
; i
++)
79 prt_printf(out
, " %llu", le64_to_cpu(journal
->buckets
[i
]));
83 const struct bch_sb_field_ops bch_sb_field_ops_journal
= {
84 .validate
= bch2_sb_journal_validate
,
85 .to_text
= bch2_sb_journal_to_text
,
93 static int u64_range_cmp(const void *_l
, const void *_r
)
95 const struct u64_range
*l
= _l
;
96 const struct u64_range
*r
= _r
;
98 return cmp_int(l
->start
, r
->start
);
101 static int bch2_sb_journal_v2_validate(struct bch_sb
*sb
, struct bch_sb_field
*f
,
102 enum bch_validate_flags flags
, struct printbuf
*err
)
104 struct bch_sb_field_journal_v2
*journal
= field_to_type(f
, journal_v2
);
105 struct bch_member m
= bch2_sb_member_get(sb
, sb
->dev_idx
);
106 int ret
= -BCH_ERR_invalid_sb_journal
;
112 nr
= bch2_sb_field_journal_v2_nr_entries(journal
);
116 b
= kmalloc_array(nr
, sizeof(*b
), GFP_KERNEL
);
118 return -BCH_ERR_ENOMEM_sb_journal_v2_validate
;
120 for (i
= 0; i
< nr
; i
++) {
121 b
[i
].start
= le64_to_cpu(journal
->d
[i
].start
);
122 b
[i
].end
= b
[i
].start
+ le64_to_cpu(journal
->d
[i
].nr
);
124 if (b
[i
].end
<= b
[i
].start
) {
125 prt_printf(err
, "journal buckets entry with bad nr: %llu+%llu",
126 le64_to_cpu(journal
->d
[i
].start
),
127 le64_to_cpu(journal
->d
[i
].nr
));
131 sum
+= le64_to_cpu(journal
->d
[i
].nr
);
134 sort(b
, nr
, sizeof(*b
), u64_range_cmp
, NULL
);
137 prt_printf(err
, "journal bucket at sector 0");
141 if (b
[0].start
< le16_to_cpu(m
.first_bucket
)) {
142 prt_printf(err
, "journal bucket %llu before first bucket %u",
143 b
[0].start
, le16_to_cpu(m
.first_bucket
));
147 if (b
[nr
- 1].end
> le64_to_cpu(m
.nbuckets
)) {
148 prt_printf(err
, "journal bucket %llu past end of device (nbuckets %llu)",
149 b
[nr
- 1].end
- 1, le64_to_cpu(m
.nbuckets
));
153 for (i
= 0; i
+ 1 < nr
; i
++) {
154 if (b
[i
].end
> b
[i
+ 1].start
) {
155 prt_printf(err
, "duplicate journal buckets in ranges %llu-%llu, %llu-%llu",
156 b
[i
].start
, b
[i
].end
, b
[i
+ 1].start
, b
[i
+ 1].end
);
161 if (sum
> UINT_MAX
) {
162 prt_printf(err
, "too many journal buckets: %llu > %u", sum
, UINT_MAX
);
172 static void bch2_sb_journal_v2_to_text(struct printbuf
*out
, struct bch_sb
*sb
,
173 struct bch_sb_field
*f
)
175 struct bch_sb_field_journal_v2
*journal
= field_to_type(f
, journal_v2
);
176 unsigned i
, nr
= bch2_sb_field_journal_v2_nr_entries(journal
);
178 prt_printf(out
, "Buckets: ");
179 for (i
= 0; i
< nr
; i
++)
180 prt_printf(out
, " %llu-%llu",
181 le64_to_cpu(journal
->d
[i
].start
),
182 le64_to_cpu(journal
->d
[i
].start
) + le64_to_cpu(journal
->d
[i
].nr
));
186 const struct bch_sb_field_ops bch_sb_field_ops_journal_v2
= {
187 .validate
= bch2_sb_journal_v2_validate
,
188 .to_text
= bch2_sb_journal_v2_to_text
,
191 int bch2_journal_buckets_to_sb(struct bch_fs
*c
, struct bch_dev
*ca
,
192 u64
*buckets
, unsigned nr
)
194 struct bch_sb_field_journal_v2
*j
;
195 unsigned i
, dst
= 0, nr_compacted
= 1;
198 lockdep_assert_held(&c
->sb_lock
);
201 bch2_sb_field_delete(&ca
->disk_sb
, BCH_SB_FIELD_journal
);
202 bch2_sb_field_delete(&ca
->disk_sb
, BCH_SB_FIELD_journal_v2
);
206 for (i
= 0; i
+ 1 < nr
; i
++)
207 if (buckets
[i
] + 1 != buckets
[i
+ 1])
210 j
= bch2_sb_field_resize(&ca
->disk_sb
, journal_v2
,
211 (sizeof(*j
) + sizeof(j
->d
[0]) * nr_compacted
) / sizeof(u64
));
213 return -BCH_ERR_ENOSPC_sb_journal
;
215 bch2_sb_field_delete(&ca
->disk_sb
, BCH_SB_FIELD_journal
);
217 j
->d
[dst
].start
= cpu_to_le64(buckets
[0]);
218 j
->d
[dst
].nr
= cpu_to_le64(1);
220 for (i
= 1; i
< nr
; i
++) {
221 if (buckets
[i
] == buckets
[i
- 1] + 1) {
222 le64_add_cpu(&j
->d
[dst
].nr
, 1);
225 j
->d
[dst
].start
= cpu_to_le64(buckets
[i
]);
226 j
->d
[dst
].nr
= cpu_to_le64(1);
230 BUG_ON(dst
+ 1 != nr_compacted
);