Commit 828552ca authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Kill bch2_bucket_alloc_new_fs()



The early-early allocation path, bch2_bucket_alloc_new_fs(), is no
longer needed - and inconsistencies around new_fs_bucket_idx have been a
frequent source of bugs.

Reported-by: default avatar <syzbot+592425844580a6598410@syzkaller.appspotmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent abf23afa
Loading
Loading
Loading
Loading
+16 −24
Original line number Diff line number Diff line
@@ -156,6 +156,14 @@ static struct open_bucket *bch2_open_bucket_alloc(struct bch_fs *c)
	return ob;
}

static inline bool is_superblock_bucket(struct bch_fs *c, struct bch_dev *ca, u64 b)
{
	if (c->curr_recovery_pass > BCH_RECOVERY_PASS_trans_mark_dev_sbs)
		return false;

	return bch2_is_superblock_bucket(ca, b);
}

static void open_bucket_free_unused(struct bch_fs *c, struct open_bucket *ob)
{
	BUG_ON(c->open_buckets_partial_nr >=
@@ -175,20 +183,6 @@ static void open_bucket_free_unused(struct bch_fs *c, struct open_bucket *ob)
	closure_wake_up(&c->freelist_wait);
}

/* _only_ for allocating the journal on a new device: */
long bch2_bucket_alloc_new_fs(struct bch_dev *ca)
{
	while (ca->new_fs_bucket_idx < ca->mi.nbuckets) {
		u64 b = ca->new_fs_bucket_idx++;

		if (!is_superblock_bucket(ca, b) &&
		    (!ca->buckets_nouse || !test_bit(b, ca->buckets_nouse)))
			return b;
	}

	return -1;
}

static inline unsigned open_buckets_reserved(enum bch_watermark watermark)
{
	switch (watermark) {
@@ -214,6 +208,9 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
{
	struct open_bucket *ob;

	if (unlikely(is_superblock_bucket(c, ca, bucket)))
		return NULL;

	if (unlikely(ca->buckets_nouse && test_bit(bucket, ca->buckets_nouse))) {
		s->skipped_nouse++;
		return NULL;
@@ -295,9 +292,6 @@ static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bc

/*
 * This path is for before the freespace btree is initialized:
 *
 * If ca->new_fs_bucket_idx is nonzero, we haven't yet marked superblock &
 * journal buckets - journal buckets will be < ca->new_fs_bucket_idx
 */
static noinline struct open_bucket *
bch2_bucket_alloc_early(struct btree_trans *trans,
@@ -309,7 +303,7 @@ bch2_bucket_alloc_early(struct btree_trans *trans,
	struct btree_iter iter, citer;
	struct bkey_s_c k, ck;
	struct open_bucket *ob = NULL;
	u64 first_bucket = max_t(u64, ca->mi.first_bucket, ca->new_fs_bucket_idx);
	u64 first_bucket = ca->mi.first_bucket;
	u64 *dev_alloc_cursor = &ca->alloc_cursor[s->btree_bitmap];
	u64 alloc_start = max(first_bucket, *dev_alloc_cursor);
	u64 alloc_cursor = alloc_start;
@@ -332,10 +326,6 @@ bch2_bucket_alloc_early(struct btree_trans *trans,
		if (bkey_ge(k.k->p, POS(ca->dev_idx, ca->mi.nbuckets)))
			break;

		if (ca->new_fs_bucket_idx &&
		    is_superblock_bucket(ca, k.k->p.offset))
			continue;

		if (s->btree_bitmap != BTREE_BITMAP_ANY &&
		    s->btree_bitmap != bch2_dev_btree_bitmap_marked_sectors(ca,
				bucket_to_sector(ca, bucket), ca->mi.bucket_size)) {
@@ -406,8 +396,6 @@ static struct open_bucket *bch2_bucket_alloc_freelist(struct btree_trans *trans,
	u64 alloc_start = max_t(u64, ca->mi.first_bucket, READ_ONCE(*dev_alloc_cursor));
	u64 alloc_cursor = alloc_start;
	int ret;

	BUG_ON(ca->new_fs_bucket_idx);
again:
	for_each_btree_key_max_norestart(trans, iter, BTREE_ID_freespace,
					 POS(ca->dev_idx, alloc_cursor),
@@ -551,6 +539,10 @@ static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
		bch2_dev_do_invalidates(ca);

	if (!avail) {
		if (watermark > BCH_WATERMARK_normal &&
		    c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_allocations)
			goto alloc;

		if (cl && !waiting) {
			closure_wait(&c->freelist_wait, cl);
			waiting = true;
+0 −2
Original line number Diff line number Diff line
@@ -28,8 +28,6 @@ struct dev_alloc_list bch2_dev_alloc_list(struct bch_fs *,
					  struct bch_devs_mask *);
void bch2_dev_stripe_increment(struct bch_dev *, struct dev_stripe_state *);

long bch2_bucket_alloc_new_fs(struct bch_dev *);

static inline struct bch_dev *ob_dev(struct bch_fs *c, struct open_bucket *ob)
{
	return bch2_dev_have_ref(c, ob->dev);
+0 −1
Original line number Diff line number Diff line
@@ -560,7 +560,6 @@ struct bch_dev {
	struct bch_dev_usage __percpu	*usage;

	/* Allocator: */
	u64			new_fs_bucket_idx;
	u64			alloc_cursor[3];

	unsigned		nr_open_buckets;
+25 −0
Original line number Diff line number Diff line
@@ -1161,6 +1161,31 @@ int bch2_trans_mark_dev_sbs(struct bch_fs *c)
	return bch2_trans_mark_dev_sbs_flags(c, BTREE_TRIGGER_transactional);
}

bool bch2_is_superblock_bucket(struct bch_dev *ca, u64 b)
{
	struct bch_sb_layout *layout = &ca->disk_sb.sb->layout;
	u64 b_offset	= bucket_to_sector(ca, b);
	u64 b_end	= bucket_to_sector(ca, b + 1);
	unsigned i;

	if (!b)
		return true;

	for (i = 0; i < layout->nr_superblocks; i++) {
		u64 offset = le64_to_cpu(layout->sb_offset[i]);
		u64 end = offset + (1 << layout->sb_max_size_bits);

		if (!(offset >= b_end || end <= b_offset))
			return true;
	}

	for (i = 0; i < ca->journal.nr; i++)
		if (b == ca->journal.buckets[i])
			return true;

	return false;
}

/* Disk reservations: */

#define SECTORS_CACHE	1024
+1 −20
Original line number Diff line number Diff line
@@ -308,26 +308,7 @@ int bch2_trans_mark_dev_sbs_flags(struct bch_fs *,
				    enum btree_iter_update_trigger_flags);
int bch2_trans_mark_dev_sbs(struct bch_fs *);

static inline bool is_superblock_bucket(struct bch_dev *ca, u64 b)
{
	struct bch_sb_layout *layout = &ca->disk_sb.sb->layout;
	u64 b_offset	= bucket_to_sector(ca, b);
	u64 b_end	= bucket_to_sector(ca, b + 1);
	unsigned i;

	if (!b)
		return true;

	for (i = 0; i < layout->nr_superblocks; i++) {
		u64 offset = le64_to_cpu(layout->sb_offset[i]);
		u64 end = offset + (1 << layout->sb_max_size_bits);

		if (!(offset >= b_end || end <= b_offset))
			return true;
	}

	return false;
}
bool bch2_is_superblock_bucket(struct bch_dev *, u64);

static inline const char *bch2_data_type_str(enum bch_data_type type)
{
Loading