Commit 92c7789a authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Validate bch_sb.offset field



This was missed - but it needs to be correct for the superblock recovery
tool that scans the start and end of the device for backup superblocks:
we don't want to pick up superblocks that belong to a different
partition that starts at a different offset.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 8bd875ae
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -231,6 +231,7 @@
	x(BCH_ERR_invalid_sb,		invalid_sb_csum)			\
	x(BCH_ERR_invalid_sb,		invalid_sb_block_size)			\
	x(BCH_ERR_invalid_sb,		invalid_sb_uuid)			\
	x(BCH_ERR_invalid_sb,		invalid_sb_offset)			\
	x(BCH_ERR_invalid_sb,		invalid_sb_too_many_members)		\
	x(BCH_ERR_invalid_sb,		invalid_sb_dev_idx)			\
	x(BCH_ERR_invalid_sb,		invalid_sb_time_precision)		\
+11 −3
Original line number Diff line number Diff line
@@ -365,7 +365,8 @@ static int bch2_sb_compatible(struct bch_sb *sb, struct printbuf *out)
	return 0;
}

int bch2_sb_validate(struct bch_sb *sb, enum bch_validate_flags flags, struct printbuf *out)
int bch2_sb_validate(struct bch_sb *sb, u64 read_offset,
		     enum bch_validate_flags flags, struct printbuf *out)
{
	struct bch_sb_field_members_v1 *mi;
	enum bch_opt_id opt_id;
@@ -409,6 +410,13 @@ int bch2_sb_validate(struct bch_sb *sb, enum bch_validate_flags flags, struct pr
		return -BCH_ERR_invalid_sb_uuid;
	}

	if (!(flags & BCH_VALIDATE_write) &&
	    le64_to_cpu(sb->offset) != read_offset) {
		prt_printf(out, "Bad sb offset (got %llu, read from %llu)",
			   le64_to_cpu(sb->offset), read_offset);
		return -BCH_ERR_invalid_sb_offset;
	}

	if (!sb->nr_devices ||
	    sb->nr_devices > BCH_SB_MEMBERS_MAX) {
		prt_printf(out, "Bad number of member devices %u (max %u)",
@@ -888,7 +896,7 @@ static int __bch2_read_super(const char *path, struct bch_opts *opts,

	sb->have_layout = true;

	ret = bch2_sb_validate(sb->sb, 0, &err);
	ret = bch2_sb_validate(sb->sb, offset, 0, &err);
	if (ret) {
		bch2_print_opts(opts, KERN_ERR "bcachefs (%s): error validating superblock: %s\n",
				path, err.buf);
@@ -1045,7 +1053,7 @@ int bch2_write_super(struct bch_fs *c)
	darray_for_each(online_devices, ca) {
		printbuf_reset(&err);

		ret = bch2_sb_validate((*ca)->disk_sb.sb, BCH_VALIDATE_write, &err);
		ret = bch2_sb_validate((*ca)->disk_sb.sb, 0, BCH_VALIDATE_write, &err);
		if (ret) {
			bch2_fs_inconsistent(c, "sb invalid before write: %s", err.buf);
			goto out;
+1 −1
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ int bch2_sb_from_fs(struct bch_fs *, struct bch_dev *);
void bch2_free_super(struct bch_sb_handle *);
int bch2_sb_realloc(struct bch_sb_handle *, unsigned);

int bch2_sb_validate(struct bch_sb *, enum bch_validate_flags, struct printbuf *);
int bch2_sb_validate(struct bch_sb *, u64, enum bch_validate_flags, struct printbuf *);

int bch2_read_super(const char *, struct bch_opts *, struct bch_sb_handle *);
int bch2_read_super_silent(const char *, struct bch_opts *, struct bch_sb_handle *);