summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2024-04-30 10:24:58 +0200
committerKent Overstreet <kent.overstreet@linux.dev>2024-05-08 23:29:22 +0200
commit3a718c0647680965171a19c2524c137be8f287b9 (patch)
tree94350cd8a53eb8eed0575cb9dc9184200f99b0ec
parentbcachefs: Kill opts.buckets_nouse (diff)
downloadlinux-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.c25
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");