bcachefs: Avoid write lock on mark_lock
authorKent Overstreet <kent.overstreet@gmail.com>
Thu, 3 Dec 2020 19:17:33 +0000 (14:17 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:21 +0000 (17:08 -0400)
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@linux.dev>
fs/bcachefs/bcachefs.h
fs/bcachefs/buckets.c
fs/bcachefs/super.c

index 807291c33f5c04e4d99a6bfb82e0f7727bce4d27..877ce788d4135dce51bc6959ea906361d9cbf0d4 100644 (file)
@@ -640,6 +640,7 @@ struct bch_fs {
        unsigned                bucket_size_max;
 
        atomic64_t              sectors_available;
+       struct mutex            sectors_available_lock;
 
        struct bch_fs_pcpu __percpu     *pcpu;
 
index ff4c61371830ade3850465f50a0b16d75026df39..2488a2227bd9bba3d1945b37bdc14e9ab5371c76 100644 (file)
@@ -1182,13 +1182,6 @@ void bch2_trans_fs_usage_apply(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);
@@ -1222,7 +1215,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,
@@ -1240,9 +1232,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)) {
@@ -1256,7 +1249,8 @@ recalculate:
                ret = -ENOSPC;
        }
 
-       percpu_up_write(&c->mark_lock);
+       mutex_unlock(&c->sectors_available_lock);
+       percpu_up_read(&c->mark_lock);
 
        return ret;
 }
index e0d4898ad0f546627975ff4ed984d506ed30dc08..b954a4e47e157e7b6a9aa7f9c2110305a3134d7d 100644 (file)
@@ -669,6 +669,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;