From 3719876809e745b9db5293d418600c194bbf5c23 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Mon, 14 Jan 2019 12:25:40 -0500 Subject: sbitmap: Protect swap_lock from softirqs The swap_lock used by sbitmap has a chain with locks taken from softirq, but the swap_lock is not protected from being preempted by softirqs. A chain exists of: sbq->ws[i].wait -> dispatch_wait_lock -> swap_lock Where the sbq->ws[i].wait lock can be taken from softirq context, which means all locks below it in the chain must also be protected from softirqs. Reported-by: Clark Williams Fixes: 58ab5e32e6fd ("sbitmap: silence bogus lockdep IRQ warning") Fixes: ea86ea2cdced ("sbitmap: amortize cost of clearing bits") Cc: Jens Axboe Cc: Ming Lei Cc: Guenter Roeck Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Linus Torvalds --- lib/sbitmap.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'lib/sbitmap.c') diff --git a/lib/sbitmap.c b/lib/sbitmap.c index 65c2d06250a6..864354000e04 100644 --- a/lib/sbitmap.c +++ b/lib/sbitmap.c @@ -26,14 +26,9 @@ static inline bool sbitmap_deferred_clear(struct sbitmap *sb, int index) { unsigned long mask, val; - unsigned long __maybe_unused flags; bool ret = false; - /* Silence bogus lockdep warning */ -#if defined(CONFIG_LOCKDEP) - local_irq_save(flags); -#endif - spin_lock(&sb->map[index].swap_lock); + spin_lock_bh(&sb->map[index].swap_lock); if (!sb->map[index].cleared) goto out_unlock; @@ -54,10 +49,7 @@ static inline bool sbitmap_deferred_clear(struct sbitmap *sb, int index) ret = true; out_unlock: - spin_unlock(&sb->map[index].swap_lock); -#if defined(CONFIG_LOCKDEP) - local_irq_restore(flags); -#endif + spin_unlock_bh(&sb->map[index].swap_lock); return ret; } -- cgit v1.2.3 From fe76fc6aaf538df27708ffa3e5d549a6c8e16142 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 15 Jan 2019 11:59:52 +0800 Subject: sbitmap: Protect swap_lock from hardirq Because we may call blk_mq_get_driver_tag() directly from blk_mq_dispatch_rq_list() without holding any lock, then HARDIRQ may come and the above DEADLOCK is triggered. Commit ab53dcfb3e7b ("sbitmap: Protect swap_lock from hardirq") tries to fix this issue by using 'spin_lock_bh', which isn't enough because we complete request from hardirq context direclty in case of multiqueue. Cc: Clark Williams Fixes: ab53dcfb3e7b ("sbitmap: Protect swap_lock from hardirq") Cc: Jens Axboe Cc: Ming Lei Cc: Guenter Roeck Cc: Steven Rostedt (VMware) Signed-off-by: Ming Lei Signed-off-by: Linus Torvalds --- lib/sbitmap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib/sbitmap.c') diff --git a/lib/sbitmap.c b/lib/sbitmap.c index 864354000e04..5b382c1244ed 100644 --- a/lib/sbitmap.c +++ b/lib/sbitmap.c @@ -27,8 +27,9 @@ static inline bool sbitmap_deferred_clear(struct sbitmap *sb, int index) { unsigned long mask, val; bool ret = false; + unsigned long flags; - spin_lock_bh(&sb->map[index].swap_lock); + spin_lock_irqsave(&sb->map[index].swap_lock, flags); if (!sb->map[index].cleared) goto out_unlock; @@ -49,7 +50,7 @@ static inline bool sbitmap_deferred_clear(struct sbitmap *sb, int index) ret = true; out_unlock: - spin_unlock_bh(&sb->map[index].swap_lock); + spin_unlock_irqrestore(&sb->map[index].swap_lock, flags); return ret; } -- cgit v1.2.3