Commit 0f52fd4f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'bcachefs-2025-03-06' of git://evilpiepirate.org/bcachefs

Pull bcachefs fixes from Kent Overstreet:

 - Fix a compatibility issue: we shouldn't be setting incompat feature
   bits unless explicitly requested

 - Fix another bug where the journal alloc/resize path could spuriously
   fail with -BCH_ERR_open_buckets_empty

 - Copygc shouldn't run on read-only devices: fragmentation isn't an
   issue if we're not currently writing to a given device, and it may
   not have anywhere to move the data to

* tag 'bcachefs-2025-03-06' of git://evilpiepirate.org/bcachefs:
  bcachefs: copygc now skips non-rw devices
  bcachefs: Fix bch2_dev_journal_alloc() spuriously failing
  bcachefs: Don't set BCH_FEATURE_incompat_version_field unless requested
parents f315296c 8ba73f53
Loading
Loading
Loading
Loading
+32 −27
Original line number Diff line number Diff line
@@ -1021,7 +1021,7 @@ struct journal_buf *bch2_next_write_buffer_flush_journal_buf(struct journal *j,

/* allocate journal on a device: */

static int __bch2_set_nr_journal_buckets(struct bch_dev *ca, unsigned nr,
static int bch2_set_nr_journal_buckets_iter(struct bch_dev *ca, unsigned nr,
					    bool new_fs, struct closure *cl)
{
	struct bch_fs *c = ca->fs;
@@ -1150,26 +1150,20 @@ static int __bch2_set_nr_journal_buckets(struct bch_dev *ca, unsigned nr,
	return ret;
}

/*
 * Allocate more journal space at runtime - not currently making use if it, but
 * the code works:
 */
int bch2_set_nr_journal_buckets(struct bch_fs *c, struct bch_dev *ca,
				unsigned nr)
static int bch2_set_nr_journal_buckets_loop(struct bch_fs *c, struct bch_dev *ca,
					    unsigned nr, bool new_fs)
{
	struct journal_device *ja = &ca->journal;
	struct closure cl;
	int ret = 0;

	struct closure cl;
	closure_init_stack(&cl);

	down_write(&c->state_lock);

	/* don't handle reducing nr of buckets yet: */
	if (nr < ja->nr)
		goto unlock;
		return 0;

	while (ja->nr < nr) {
	while (!ret && ja->nr < nr) {
		struct disk_reservation disk_res = { 0, 0, 0 };

		/*
@@ -1182,27 +1176,38 @@ int bch2_set_nr_journal_buckets(struct bch_fs *c, struct bch_dev *ca,
		 * filesystem-wide allocation will succeed, this is a device
		 * specific allocation - we can hang here:
		 */

		if (!new_fs) {
			ret = bch2_disk_reservation_get(c, &disk_res,
							bucket_to_sector(ca, nr - ja->nr), 1, 0);
			if (ret)
				break;
		}

		ret = __bch2_set_nr_journal_buckets(ca, nr, false, &cl);
		ret = bch2_set_nr_journal_buckets_iter(ca, nr, new_fs, &cl);

		bch2_disk_reservation_put(c, &disk_res);
		if (ret == -BCH_ERR_bucket_alloc_blocked ||
		    ret == -BCH_ERR_open_buckets_empty)
			ret = 0; /* wait and retry */

		bch2_disk_reservation_put(c, &disk_res);
		closure_sync(&cl);
	}

		if (ret &&
		    ret != -BCH_ERR_bucket_alloc_blocked &&
		    ret != -BCH_ERR_open_buckets_empty)
			break;
	return ret;
}

	bch_err_fn(c, ret);
unlock:
/*
 * Allocate more journal space at runtime - not currently making use if it, but
 * the code works:
 */
int bch2_set_nr_journal_buckets(struct bch_fs *c, struct bch_dev *ca,
				unsigned nr)
{
	down_write(&c->state_lock);
	int ret = bch2_set_nr_journal_buckets_loop(c, ca, nr, false);
	up_write(&c->state_lock);

	bch_err_fn(c, ret);
	return ret;
}

@@ -1228,7 +1233,7 @@ int bch2_dev_journal_alloc(struct bch_dev *ca, bool new_fs)
		     min(1 << 13,
			 (1 << 24) / ca->mi.bucket_size));

	ret = __bch2_set_nr_journal_buckets(ca, nr, new_fs, NULL);
	ret = bch2_set_nr_journal_buckets_loop(ca->fs, ca, nr, new_fs);
err:
	bch_err_fn(ca, ret);
	return ret;
+12 −13
Original line number Diff line number Diff line
@@ -74,20 +74,14 @@ static int bch2_bucket_is_movable(struct btree_trans *trans,
				  struct move_bucket *b, u64 time)
{
	struct bch_fs *c = trans->c;
	struct btree_iter iter;
	struct bkey_s_c k;
	struct bch_alloc_v4 _a;
	const struct bch_alloc_v4 *a;
	int ret;

	if (bch2_bucket_is_open(trans->c,
				b->k.bucket.inode,
				b->k.bucket.offset))
	if (bch2_bucket_is_open(c, b->k.bucket.inode, b->k.bucket.offset))
		return 0;

	k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_alloc,
	struct btree_iter iter;
	struct bkey_s_c k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_alloc,
				       b->k.bucket, BTREE_ITER_cached);
	ret = bkey_err(k);
	int ret = bkey_err(k);
	if (ret)
		return ret;

@@ -95,13 +89,18 @@ static int bch2_bucket_is_movable(struct btree_trans *trans,
	if (!ca)
		goto out;

	a = bch2_alloc_to_v4(k, &_a);
	if (ca->mi.state != BCH_MEMBER_STATE_rw ||
	    !bch2_dev_is_online(ca))
		goto out_put;

	struct bch_alloc_v4 _a;
	const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k, &_a);
	b->k.gen	= a->gen;
	b->sectors	= bch2_bucket_sectors_dirty(*a);
	u64 lru_idx	= alloc_lru_idx_fragmentation(*a, ca);

	ret = lru_idx && lru_idx <= time;

out_put:
	bch2_dev_put(ca);
out:
	bch2_trans_iter_exit(trans, &iter);
+16 −8
Original line number Diff line number Diff line
@@ -69,16 +69,22 @@ enum bcachefs_metadata_version bch2_latest_compatible_version(enum bcachefs_meta
	return v;
}

void bch2_set_version_incompat(struct bch_fs *c, enum bcachefs_metadata_version version)
bool bch2_set_version_incompat(struct bch_fs *c, enum bcachefs_metadata_version version)
{
	bool ret = (c->sb.features & BIT_ULL(BCH_FEATURE_incompat_version_field)) &&
		   version <= c->sb.version_incompat_allowed;

	if (ret) {
		mutex_lock(&c->sb_lock);
		SET_BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb,
			max(BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb), version));
	c->disk_sb.sb->features[0] |= cpu_to_le64(BCH_FEATURE_incompat_version_field);
		bch2_write_super(c);
		mutex_unlock(&c->sb_lock);
	}

	return ret;
}

const char * const bch2_sb_fields[] = {
#define x(name, nr)	#name,
	BCH_SB_FIELDS()
@@ -1219,9 +1225,11 @@ void bch2_sb_upgrade(struct bch_fs *c, unsigned new_version, bool incompat)
	c->disk_sb.sb->version = cpu_to_le16(new_version);
	c->disk_sb.sb->features[0] |= cpu_to_le64(BCH_SB_FEATURES_ALL);

	if (incompat)
	if (incompat) {
		SET_BCH_SB_VERSION_INCOMPAT_ALLOWED(c->disk_sb.sb,
			max(BCH_SB_VERSION_INCOMPAT_ALLOWED(c->disk_sb.sb), new_version));
		c->disk_sb.sb->features[0] |= cpu_to_le64(BCH_FEATURE_incompat_version_field);
	}
}

static int bch2_sb_ext_validate(struct bch_sb *sb, struct bch_sb_field *f,
+4 −7
Original line number Diff line number Diff line
@@ -21,17 +21,14 @@ static inline bool bch2_version_compatible(u16 version)
void bch2_version_to_text(struct printbuf *, enum bcachefs_metadata_version);
enum bcachefs_metadata_version bch2_latest_compatible_version(enum bcachefs_metadata_version);

void bch2_set_version_incompat(struct bch_fs *, enum bcachefs_metadata_version);
bool bch2_set_version_incompat(struct bch_fs *, enum bcachefs_metadata_version);

static inline bool bch2_request_incompat_feature(struct bch_fs *c,
						 enum bcachefs_metadata_version version)
{
	if (unlikely(version > c->sb.version_incompat)) {
		if (version > c->sb.version_incompat_allowed)
			return false;
		bch2_set_version_incompat(c, version);
	}
	return true;
	return likely(version <= c->sb.version_incompat)
		? true
		: bch2_set_version_incompat(c, version);
}

static inline size_t bch2_sb_field_bytes(struct bch_sb_field *f)