summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2020-12-03 14:17:33 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2020-12-07 11:50:44 -0500
commitdedfb1438185c7de976981234c355efccf95c93a (patch)
tree5f7ddbfaaa30448e886c8b90d16afe5e6b8170db
parent68c53eaea82f36db3344d04cff14c5d988615c1a (diff)
bcachefs: Avoid write lock on mark_lock
mark_lock is a frequently taken lock, and there's also potential for deadlocks since currently bch2_clear_page_bits which is called from memory reclaim has to take it to drop disk reservations. The disk reservation get path takes it when it recalculates the number of sectors known to be available, but it's not really needed for consistency. We just want to make sure we only have one thread updating the sectors_available count, which we can do with a dedicated mutex. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/bcachefs.h1
-rw-r--r--fs/bcachefs/buckets.c16
-rw-r--r--fs/bcachefs/super.c2
3 files changed, 8 insertions, 11 deletions
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index 23561c652d18..eb5b40804773 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -673,6 +673,7 @@ struct bch_fs {
unsigned bucket_size_max;
atomic64_t sectors_available;
+ struct mutex sectors_available_lock;
struct bch_fs_pcpu __percpu *pcpu;
diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c
index e297101af3a1..0000fc76d2d9 100644
--- a/fs/bcachefs/buckets.c
+++ b/fs/bcachefs/buckets.c
@@ -2032,13 +2032,6 @@ int bch2_trans_mark_update(struct btree_trans *trans,
/* Disk reservations: */
-static u64 bch2_recalc_sectors_available(struct bch_fs *c)
-{
- percpu_u64_set(&c->pcpu->sectors_available, 0);
-
- return avail_factor(__bch2_fs_usage_read_short(c).free);
-}
-
void __bch2_disk_reservation_put(struct bch_fs *c, struct disk_reservation *res)
{
percpu_down_read(&c->mark_lock);
@@ -2073,7 +2066,6 @@ int bch2_disk_reservation_add(struct bch_fs *c, struct disk_reservation *res,
if (get < sectors) {
preempt_enable();
- percpu_up_read(&c->mark_lock);
goto recalculate;
}
} while ((v = atomic64_cmpxchg(&c->sectors_available,
@@ -2091,9 +2083,10 @@ out:
return 0;
recalculate:
- percpu_down_write(&c->mark_lock);
+ mutex_lock(&c->sectors_available_lock);
- sectors_available = bch2_recalc_sectors_available(c);
+ percpu_u64_set(&c->pcpu->sectors_available, 0);
+ sectors_available = avail_factor(__bch2_fs_usage_read_short(c).free);
if (sectors <= sectors_available ||
(flags & BCH_DISK_RESERVATION_NOFAIL)) {
@@ -2107,7 +2100,8 @@ recalculate:
ret = -ENOSPC;
}
- percpu_up_write(&c->mark_lock);
+ mutex_unlock(&c->sectors_available_lock);
+ percpu_up_read(&c->mark_lock);
return ret;
}
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index 748350589eb8..651fbc5d52b1 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -716,6 +716,8 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
bch2_fs_btree_cache_init_early(&c->btree_cache);
+ mutex_init(&c->sectors_available_lock);
+
if (percpu_init_rwsem(&c->mark_lock))
goto err;