Commit db42549d authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Add a better limit for maximum number of buckets



The bucket_gens array is a single array allocation (one byte per
bucket), and kernel allocations are still limited to INT_MAX.

Check this limit to avoid failing the bucket_gens array allocation.

Reported-by: default avatar <syzbot+b29f436493184ea42e2b@syzkaller.appspotmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 18b4abce
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -591,6 +591,12 @@ struct bch_member {
	__le64			btree_allocated_bitmap;
};

/*
 * This limit comes from the bucket_gens array - it's a single allocation, and
 * kernel allocation are limited to INT_MAX
 */
#define BCH_MEMBER_NBUCKETS_MAX	(INT_MAX - 64)

#define BCH_MEMBER_V1_BYTES	56

LE64_BITMASK(BCH_MEMBER_STATE,		struct bch_member, flags,  0,  4)
+1 −0
Original line number Diff line number Diff line
@@ -175,6 +175,7 @@
	x(EINVAL,			block_size_too_small)			\
	x(EINVAL,			bucket_size_too_small)			\
	x(EINVAL,			device_size_too_small)			\
	x(EINVAL,			device_size_too_big)			\
	x(EINVAL,			device_not_a_member_of_filesystem)	\
	x(EINVAL,			device_has_been_removed)		\
	x(EINVAL,			device_splitbrain)			\
+3 −3
Original line number Diff line number Diff line
@@ -124,9 +124,9 @@ static int validate_member(struct printbuf *err,
			   struct bch_sb *sb,
			   int i)
{
	if (le64_to_cpu(m.nbuckets) > LONG_MAX) {
		prt_printf(err, "device %u: too many buckets (got %llu, max %lu)",
			   i, le64_to_cpu(m.nbuckets), LONG_MAX);
	if (le64_to_cpu(m.nbuckets) > BCH_MEMBER_NBUCKETS_MAX) {
		prt_printf(err, "device %u: too many buckets (got %llu, max %u)",
			   i, le64_to_cpu(m.nbuckets), BCH_MEMBER_NBUCKETS_MAX);
		return -BCH_ERR_invalid_sb_members;
	}

+7 −0
Original line number Diff line number Diff line
@@ -1959,6 +1959,13 @@ int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
		goto err;
	}

	if (nbuckets > BCH_MEMBER_NBUCKETS_MAX) {
		bch_err(ca, "New device size too big (%llu greater than max %u)",
			nbuckets, BCH_MEMBER_NBUCKETS_MAX);
		ret = -BCH_ERR_device_size_too_big;
		goto err;
	}

	if (bch2_dev_is_online(ca) &&
	    get_capacity(ca->disk_sb.bdev->bd_disk) <
	    ca->mi.bucket_size * nbuckets) {