brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · 62b910f Raw
233 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include "bcachefs.h"4#include "journal_sb.h"5#include "darray.h"6 7#include <linux/sort.h>8 9/* BCH_SB_FIELD_journal: */10 11static int u64_cmp(const void *_l, const void *_r)12{13	const u64 *l = _l;14	const u64 *r = _r;15 16	return cmp_int(*l, *r);17}18 19static int bch2_sb_journal_validate(struct bch_sb *sb, struct bch_sb_field *f,20				enum bch_validate_flags flags, struct printbuf *err)21{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;25	unsigned nr;26	unsigned i;27	u64 *b;28 29	nr = bch2_nr_journal_buckets(journal);30	if (!nr)31		return 0;32 33	b = kmalloc_array(nr, sizeof(u64), GFP_KERNEL);34	if (!b)35		return -BCH_ERR_ENOMEM_sb_journal_validate;36 37	for (i = 0; i < nr; i++)38		b[i] = le64_to_cpu(journal->buckets[i]);39 40	sort(b, nr, sizeof(u64), u64_cmp, NULL);41 42	if (!b[0]) {43		prt_printf(err, "journal bucket at sector 0");44		goto err;45	}46 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));50		goto err;51	}52 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));56		goto err;57	}58 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]);62			goto err;63		}64 65	ret = 0;66err:67	kfree(b);68	return ret;69}70 71static void bch2_sb_journal_to_text(struct printbuf *out, struct bch_sb *sb,72				    struct bch_sb_field *f)73{74	struct bch_sb_field_journal *journal = field_to_type(f, journal);75	unsigned i, nr = bch2_nr_journal_buckets(journal);76 77	prt_printf(out, "Buckets: ");78	for (i = 0; i < nr; i++)79		prt_printf(out, " %llu", le64_to_cpu(journal->buckets[i]));80	prt_newline(out);81}82 83const struct bch_sb_field_ops bch_sb_field_ops_journal = {84	.validate	= bch2_sb_journal_validate,85	.to_text	= bch2_sb_journal_to_text,86};87 88struct u64_range {89	u64	start;90	u64	end;91};92 93static int u64_range_cmp(const void *_l, const void *_r)94{95	const struct u64_range *l = _l;96	const struct u64_range *r = _r;97 98	return cmp_int(l->start, r->start);99}100 101static int bch2_sb_journal_v2_validate(struct bch_sb *sb, struct bch_sb_field *f,102				enum bch_validate_flags flags, struct printbuf *err)103{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;107	u64 sum = 0;108	unsigned nr;109	unsigned i;110	struct u64_range *b;111 112	nr = bch2_sb_field_journal_v2_nr_entries(journal);113	if (!nr)114		return 0;115 116	b = kmalloc_array(nr, sizeof(*b), GFP_KERNEL);117	if (!b)118		return -BCH_ERR_ENOMEM_sb_journal_v2_validate;119 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);123 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));128			goto err;129		}130 131		sum += le64_to_cpu(journal->d[i].nr);132	}133 134	sort(b, nr, sizeof(*b), u64_range_cmp, NULL);135 136	if (!b[0].start) {137		prt_printf(err, "journal bucket at sector 0");138		goto err;139	}140 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));144		goto err;145	}146 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));150		goto err;151	}152 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);157			goto err;158		}159	}160 161	if (sum > UINT_MAX) {162		prt_printf(err, "too many journal buckets: %llu > %u", sum, UINT_MAX);163		goto err;164	}165 166	ret = 0;167err:168	kfree(b);169	return ret;170}171 172static void bch2_sb_journal_v2_to_text(struct printbuf *out, struct bch_sb *sb,173				    struct bch_sb_field *f)174{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);177 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));183	prt_newline(out);184}185 186const 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,189};190 191int bch2_journal_buckets_to_sb(struct bch_fs *c, struct bch_dev *ca,192			       u64 *buckets, unsigned nr)193{194	struct bch_sb_field_journal_v2 *j;195	unsigned i, dst = 0, nr_compacted = 1;196 197	if (c)198		lockdep_assert_held(&c->sb_lock);199 200	if (!nr) {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);203		return 0;204	}205 206	for (i = 0; i + 1 < nr; i++)207		if (buckets[i] + 1 != buckets[i + 1])208			nr_compacted++;209 210	j = bch2_sb_field_resize(&ca->disk_sb, journal_v2,211			 (sizeof(*j) + sizeof(j->d[0]) * nr_compacted) / sizeof(u64));212	if (!j)213		return -BCH_ERR_ENOSPC_sb_journal;214 215	bch2_sb_field_delete(&ca->disk_sb, BCH_SB_FIELD_journal);216 217	j->d[dst].start = cpu_to_le64(buckets[0]);218	j->d[dst].nr	= cpu_to_le64(1);219 220	for (i = 1; i < nr; i++) {221		if (buckets[i] == buckets[i - 1] + 1) {222			le64_add_cpu(&j->d[dst].nr, 1);223		} else {224			dst++;225			j->d[dst].start = cpu_to_le64(buckets[i]);226			j->d[dst].nr	= cpu_to_le64(1);227		}228	}229 230	BUG_ON(dst + 1 != nr_compacted);231	return 0;232}233