mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-04 01:20:01 -04:00
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
This commit is contained in:
@@ -1021,8 +1021,8 @@ 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,
|
||||
bool new_fs, struct closure *cl)
|
||||
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;
|
||||
struct journal_device *ja = &ca->journal;
|
||||
@@ -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_disk_reservation_get(c, &disk_res,
|
||||
bucket_to_sector(ca, nr - ja->nr), 1, 0);
|
||||
if (ret)
|
||||
break;
|
||||
ret = bch2_set_nr_journal_buckets_iter(ca, nr, new_fs, &cl);
|
||||
|
||||
ret = __bch2_set_nr_journal_buckets(ca, nr, false, &cl);
|
||||
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;
|
||||
}
|
||||
|
||||
bch_err_fn(c, ret);
|
||||
unlock:
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -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,
|
||||
b->k.bucket, BTREE_ITER_cached);
|
||||
ret = bkey_err(k);
|
||||
struct btree_iter iter;
|
||||
struct bkey_s_c k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_alloc,
|
||||
b->k.bucket, BTREE_ITER_cached);
|
||||
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);
|
||||
|
||||
@@ -69,14 +69,20 @@ 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)
|
||||
{
|
||||
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);
|
||||
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));
|
||||
bch2_write_super(c);
|
||||
mutex_unlock(&c->sb_lock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char * const bch2_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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user