diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2024-04-30 10:24:58 +0200 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-05-08 23:29:22 +0200 |
commit | 3a718c0647680965171a19c2524c137be8f287b9 (patch) | |
tree | 94350cd8a53eb8eed0575cb9dc9184200f99b0ec | |
parent | bcachefs: Kill opts.buckets_nouse (diff) | |
download | linux-3a718c0647680965171a19c2524c137be8f287b9.tar.xz linux-3a718c0647680965171a19c2524c137be8f287b9.zip |
bcachefs: On device add, prefer unused slots
We can't strictly guarantee that no pointers refer to nonexistent
devices - we attempt to, but we need to be safe when the filesystem is
corrupt.
Therefore, change device_add to try to pick a slot that's never been
used, or the slot that's been unused the longest.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/super.c | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c index 1cbb2b3f4740..6c6087039781 100644 --- a/fs/bcachefs/super.c +++ b/fs/bcachefs/super.c @@ -1764,9 +1764,28 @@ int bch2_dev_add(struct bch_fs *c, const char *path) if (dynamic_fault("bcachefs:add:no_slot")) goto no_slot; - for (dev_idx = 0; dev_idx < BCH_SB_MEMBERS_MAX; dev_idx++) - if (!bch2_member_exists(c->disk_sb.sb, dev_idx)) - goto have_slot; + if (c->sb.nr_devices < BCH_SB_MEMBERS_MAX) { + dev_idx = c->sb.nr_devices; + goto have_slot; + } + + int best = -1; + u64 best_last_mount = 0; + for (dev_idx = 0; dev_idx < BCH_SB_MEMBERS_MAX; dev_idx++) { + struct bch_member m = bch2_sb_member_get(c->disk_sb.sb, dev_idx); + if (bch2_member_alive(&m)) + continue; + + u64 last_mount = le64_to_cpu(m.last_mount); + if (best < 0 || last_mount < best_last_mount) { + best = dev_idx; + best_last_mount = last_mount; + } + } + if (best >= 0) { + dev_idx = best; + goto have_slot; + } no_slot: ret = -BCH_ERR_ENOSPC_sb_members; bch_err_msg(c, ret, "setting up new superblock"); |