* Re: [PATCH 6.0 479/862] sbitmap: fix possible io hung due to lost wakeup [not found] ` <20221019083311.114449669@linuxfoundation.org> @ 2022-10-19 15:06 ` Hugh Dickins 2022-10-19 17:25 ` Greg Kroah-Hartman 0 siblings, 1 reply; 4+ messages in thread From: Hugh Dickins @ 2022-10-19 15:06 UTC (permalink / raw) To: Greg Kroah-Hartman Cc: linux-kernel, stable, Yu Kuai, Jan Kara, Jens Axboe, Sasha Levin, linux-block On Wed, 19 Oct 2022, Greg Kroah-Hartman wrote: > From: Yu Kuai <yukuai3@huawei.com> > > [ Upstream commit 040b83fcecfb86f3225d3a5de7fd9b3fbccf83b4 ] > > There are two problems can lead to lost wakeup: > > 1) invalid wakeup on the wrong waitqueue: > > For example, 2 * wake_batch tags are put, while only wake_batch threads > are woken: > > __sbq_wake_up > atomic_cmpxchg -> reset wait_cnt > __sbq_wake_up -> decrease wait_cnt > ... > __sbq_wake_up -> wait_cnt is decreased to 0 again > atomic_cmpxchg > sbq_index_atomic_inc -> increase wake_index > wake_up_nr -> wake up and waitqueue might be empty > sbq_index_atomic_inc -> increase again, one waitqueue is skipped > wake_up_nr -> invalid wake up because old wakequeue might be empty > > To fix the problem, increasing 'wake_index' before resetting 'wait_cnt'. > > 2) 'wait_cnt' can be decreased while waitqueue is empty > > As pointed out by Jan Kara, following race is possible: > > CPU1 CPU2 > __sbq_wake_up __sbq_wake_up > sbq_wake_ptr() sbq_wake_ptr() -> the same > wait_cnt = atomic_dec_return() > /* decreased to 0 */ > sbq_index_atomic_inc() > /* move to next waitqueue */ > atomic_set() > /* reset wait_cnt */ > wake_up_nr() > /* wake up on the old waitqueue */ > wait_cnt = atomic_dec_return() > /* > * decrease wait_cnt in the old > * waitqueue, while it can be > * empty. > */ > > Fix the problem by waking up before updating 'wake_index' and > 'wait_cnt'. > > With this patch, noted that 'wait_cnt' is still decreased in the old > empty waitqueue, however, the wakeup is redirected to a active waitqueue, > and the extra decrement on the old empty waitqueue is not handled. > > Fixes: 88459642cba4 ("blk-mq: abstract tag allocation out into sbitmap library") > Signed-off-by: Yu Kuai <yukuai3@huawei.com> > Reviewed-by: Jan Kara <jack@suse.cz> > Link: https://lore.kernel.org/r/20220803121504.212071-1-yukuai1@huaweicloud.com > Signed-off-by: Jens Axboe <axboe@kernel.dk> > Signed-off-by: Sasha Levin <sashal@kernel.org> I have no authority on linux-block, but I'll say NAK to this one (and 517/862), and let Jens and Jan overrule me if they disagree. This was the first of several 6.1-rc1 commits which had given me lost wakeups never suffered before; was not tagged Cc stable; and (unless I've missed it on lore) never had AUTOSEL posted to linux-block or linux-kernel. Hugh > --- > lib/sbitmap.c | 55 ++++++++++++++++++++++++++++++--------------------- > 1 file changed, 33 insertions(+), 22 deletions(-) > > diff --git a/lib/sbitmap.c b/lib/sbitmap.c > index 29eb0484215a..1f31147872e6 100644 > --- a/lib/sbitmap.c > +++ b/lib/sbitmap.c > @@ -611,32 +611,43 @@ static bool __sbq_wake_up(struct sbitmap_queue *sbq) > return false; > > wait_cnt = atomic_dec_return(&ws->wait_cnt); > - if (wait_cnt <= 0) { > - int ret; > + /* > + * For concurrent callers of this, callers should call this function > + * again to wakeup a new batch on a different 'ws'. > + */ > + if (wait_cnt < 0 || !waitqueue_active(&ws->wait)) > + return true; > > - wake_batch = READ_ONCE(sbq->wake_batch); > + if (wait_cnt > 0) > + return false; > > - /* > - * Pairs with the memory barrier in sbitmap_queue_resize() to > - * ensure that we see the batch size update before the wait > - * count is reset. > - */ > - smp_mb__before_atomic(); > + wake_batch = READ_ONCE(sbq->wake_batch); > > - /* > - * For concurrent callers of this, the one that failed the > - * atomic_cmpxhcg() race should call this function again > - * to wakeup a new batch on a different 'ws'. > - */ > - ret = atomic_cmpxchg(&ws->wait_cnt, wait_cnt, wake_batch); > - if (ret == wait_cnt) { > - sbq_index_atomic_inc(&sbq->wake_index); > - wake_up_nr(&ws->wait, wake_batch); > - return false; > - } > + /* > + * Wake up first in case that concurrent callers decrease wait_cnt > + * while waitqueue is empty. > + */ > + wake_up_nr(&ws->wait, wake_batch); > > - return true; > - } > + /* > + * Pairs with the memory barrier in sbitmap_queue_resize() to > + * ensure that we see the batch size update before the wait > + * count is reset. > + * > + * Also pairs with the implicit barrier between decrementing wait_cnt > + * and checking for waitqueue_active() to make sure waitqueue_active() > + * sees result of the wakeup if atomic_dec_return() has seen the result > + * of atomic_set(). > + */ > + smp_mb__before_atomic(); > + > + /* > + * Increase wake_index before updating wait_cnt, otherwise concurrent > + * callers can see valid wait_cnt in old waitqueue, which can cause > + * invalid wakeup on the old waitqueue. > + */ > + sbq_index_atomic_inc(&sbq->wake_index); > + atomic_set(&ws->wait_cnt, wake_batch); > > return false; > } > -- > 2.35.1 > > > > ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 6.0 479/862] sbitmap: fix possible io hung due to lost wakeup 2022-10-19 15:06 ` [PATCH 6.0 479/862] sbitmap: fix possible io hung due to lost wakeup Hugh Dickins @ 2022-10-19 17:25 ` Greg Kroah-Hartman 2022-10-19 17:37 ` Jens Axboe 0 siblings, 1 reply; 4+ messages in thread From: Greg Kroah-Hartman @ 2022-10-19 17:25 UTC (permalink / raw) To: Hugh Dickins Cc: linux-kernel, stable, Yu Kuai, Jan Kara, Jens Axboe, Sasha Levin, linux-block On Wed, Oct 19, 2022 at 08:06:26AM -0700, Hugh Dickins wrote: > On Wed, 19 Oct 2022, Greg Kroah-Hartman wrote: > > > From: Yu Kuai <yukuai3@huawei.com> > > > > [ Upstream commit 040b83fcecfb86f3225d3a5de7fd9b3fbccf83b4 ] > > > > There are two problems can lead to lost wakeup: > > > > 1) invalid wakeup on the wrong waitqueue: > > > > For example, 2 * wake_batch tags are put, while only wake_batch threads > > are woken: > > > > __sbq_wake_up > > atomic_cmpxchg -> reset wait_cnt > > __sbq_wake_up -> decrease wait_cnt > > ... > > __sbq_wake_up -> wait_cnt is decreased to 0 again > > atomic_cmpxchg > > sbq_index_atomic_inc -> increase wake_index > > wake_up_nr -> wake up and waitqueue might be empty > > sbq_index_atomic_inc -> increase again, one waitqueue is skipped > > wake_up_nr -> invalid wake up because old wakequeue might be empty > > > > To fix the problem, increasing 'wake_index' before resetting 'wait_cnt'. > > > > 2) 'wait_cnt' can be decreased while waitqueue is empty > > > > As pointed out by Jan Kara, following race is possible: > > > > CPU1 CPU2 > > __sbq_wake_up __sbq_wake_up > > sbq_wake_ptr() sbq_wake_ptr() -> the same > > wait_cnt = atomic_dec_return() > > /* decreased to 0 */ > > sbq_index_atomic_inc() > > /* move to next waitqueue */ > > atomic_set() > > /* reset wait_cnt */ > > wake_up_nr() > > /* wake up on the old waitqueue */ > > wait_cnt = atomic_dec_return() > > /* > > * decrease wait_cnt in the old > > * waitqueue, while it can be > > * empty. > > */ > > > > Fix the problem by waking up before updating 'wake_index' and > > 'wait_cnt'. > > > > With this patch, noted that 'wait_cnt' is still decreased in the old > > empty waitqueue, however, the wakeup is redirected to a active waitqueue, > > and the extra decrement on the old empty waitqueue is not handled. > > > > Fixes: 88459642cba4 ("blk-mq: abstract tag allocation out into sbitmap library") > > Signed-off-by: Yu Kuai <yukuai3@huawei.com> > > Reviewed-by: Jan Kara <jack@suse.cz> > > Link: https://lore.kernel.org/r/20220803121504.212071-1-yukuai1@huaweicloud.com > > Signed-off-by: Jens Axboe <axboe@kernel.dk> > > Signed-off-by: Sasha Levin <sashal@kernel.org> > > I have no authority on linux-block, but I'll say NAK to this one > (and 517/862), and let Jens and Jan overrule me if they disagree. > > This was the first of several 6.1-rc1 commits which had given me lost > wakeups never suffered before; was not tagged Cc stable; and (unless I've > missed it on lore) never had AUTOSEL posted to linux-block or linux-kernel. Ok, thanks for the review. I'll drop both of the sbitmap.c changes and if people report issues and want them back, I'll be glad to revisit them then. greg k-h ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 6.0 479/862] sbitmap: fix possible io hung due to lost wakeup 2022-10-19 17:25 ` Greg Kroah-Hartman @ 2022-10-19 17:37 ` Jens Axboe 0 siblings, 0 replies; 4+ messages in thread From: Jens Axboe @ 2022-10-19 17:37 UTC (permalink / raw) To: Greg Kroah-Hartman, Hugh Dickins Cc: linux-kernel, stable, Yu Kuai, Jan Kara, Sasha Levin, linux-block On 10/19/22 10:25 AM, Greg Kroah-Hartman wrote: > On Wed, Oct 19, 2022 at 08:06:26AM -0700, Hugh Dickins wrote: >> On Wed, 19 Oct 2022, Greg Kroah-Hartman wrote: >> >>> From: Yu Kuai <yukuai3@huawei.com> >>> >>> [ Upstream commit 040b83fcecfb86f3225d3a5de7fd9b3fbccf83b4 ] >>> >>> There are two problems can lead to lost wakeup: >>> >>> 1) invalid wakeup on the wrong waitqueue: >>> >>> For example, 2 * wake_batch tags are put, while only wake_batch threads >>> are woken: >>> >>> __sbq_wake_up >>> atomic_cmpxchg -> reset wait_cnt >>> __sbq_wake_up -> decrease wait_cnt >>> ... >>> __sbq_wake_up -> wait_cnt is decreased to 0 again >>> atomic_cmpxchg >>> sbq_index_atomic_inc -> increase wake_index >>> wake_up_nr -> wake up and waitqueue might be empty >>> sbq_index_atomic_inc -> increase again, one waitqueue is skipped >>> wake_up_nr -> invalid wake up because old wakequeue might be empty >>> >>> To fix the problem, increasing 'wake_index' before resetting 'wait_cnt'. >>> >>> 2) 'wait_cnt' can be decreased while waitqueue is empty >>> >>> As pointed out by Jan Kara, following race is possible: >>> >>> CPU1 CPU2 >>> __sbq_wake_up __sbq_wake_up >>> sbq_wake_ptr() sbq_wake_ptr() -> the same >>> wait_cnt = atomic_dec_return() >>> /* decreased to 0 */ >>> sbq_index_atomic_inc() >>> /* move to next waitqueue */ >>> atomic_set() >>> /* reset wait_cnt */ >>> wake_up_nr() >>> /* wake up on the old waitqueue */ >>> wait_cnt = atomic_dec_return() >>> /* >>> * decrease wait_cnt in the old >>> * waitqueue, while it can be >>> * empty. >>> */ >>> >>> Fix the problem by waking up before updating 'wake_index' and >>> 'wait_cnt'. >>> >>> With this patch, noted that 'wait_cnt' is still decreased in the old >>> empty waitqueue, however, the wakeup is redirected to a active waitqueue, >>> and the extra decrement on the old empty waitqueue is not handled. >>> >>> Fixes: 88459642cba4 ("blk-mq: abstract tag allocation out into sbitmap library") >>> Signed-off-by: Yu Kuai <yukuai3@huawei.com> >>> Reviewed-by: Jan Kara <jack@suse.cz> >>> Link: https://lore.kernel.org/r/20220803121504.212071-1-yukuai1@huaweicloud.com >>> Signed-off-by: Jens Axboe <axboe@kernel.dk> >>> Signed-off-by: Sasha Levin <sashal@kernel.org> >> >> I have no authority on linux-block, but I'll say NAK to this one >> (and 517/862), and let Jens and Jan overrule me if they disagree. >> >> This was the first of several 6.1-rc1 commits which had given me lost >> wakeups never suffered before; was not tagged Cc stable; and (unless I've >> missed it on lore) never had AUTOSEL posted to linux-block or linux-kernel. > > Ok, thanks for the review. I'll drop both of the sbitmap.c changes and > if people report issues and want them back, I'll be glad to revisit them > then. Sorry for being late, did see Hugh respond to the original auto-select as well, and was surprised to see it moving forward after that. Let's please drop them for now. -- Jens Axboe ^ permalink raw reply [flat|nested] 4+ messages in thread
[parent not found: <20221019083312.840347737@linuxfoundation.org>]
* Re: [PATCH 6.0 517/862] sbitmap: Avoid leaving waitqueue in invalid state in __sbq_wake_up() [not found] ` <20221019083312.840347737@linuxfoundation.org> @ 2022-10-19 15:08 ` Hugh Dickins 0 siblings, 0 replies; 4+ messages in thread From: Hugh Dickins @ 2022-10-19 15:08 UTC (permalink / raw) To: Greg Kroah-Hartman Cc: linux-kernel, stable, Keith Busch, Jan Kara, Jens Axboe, Sasha Levin, linux-block On Wed, 19 Oct 2022, Greg Kroah-Hartman wrote: > From: Jan Kara <jack@suse.cz> > > [ Upstream commit 48c033314f372478548203c583529f53080fd078 ] > > When __sbq_wake_up() decrements wait_cnt to 0 but races with someone > else waking the waiter on the waitqueue (so the waitqueue becomes > empty), it exits without reseting wait_cnt to wake_batch number. Once > wait_cnt is 0, nobody will ever reset the wait_cnt or wake the new > waiters resulting in possible deadlocks or busyloops. Fix the problem by > making sure we reset wait_cnt even if we didn't wake up anybody in the > end. > > Fixes: 040b83fcecfb ("sbitmap: fix possible io hung due to lost wakeup") > Reported-by: Keith Busch <kbusch@kernel.org> > Signed-off-by: Jan Kara <jack@suse.cz> > Link: https://lore.kernel.org/r/20220908130937.2795-1-jack@suse.cz > Signed-off-by: Jens Axboe <axboe@kernel.dk> > Signed-off-by: Sasha Levin <sashal@kernel.org> I have no authority on linux-block, but I'll say NAK to this one (and 479/862), and let Jens and Jan overrule me if they disagree. This was another of several 6.1-rc1 commits which had given me lost wakeups never suffered before; was not tagged Cc stable; and (unless I've missed it on lore) never had AUTOSEL posted to linux-block or linux-kernel. Hugh > --- > lib/sbitmap.c | 18 +++++++++++++++--- > 1 file changed, 15 insertions(+), 3 deletions(-) > > diff --git a/lib/sbitmap.c b/lib/sbitmap.c > index 1f31147872e6..bb1970ad4875 100644 > --- a/lib/sbitmap.c > +++ b/lib/sbitmap.c > @@ -605,6 +605,7 @@ static bool __sbq_wake_up(struct sbitmap_queue *sbq) > struct sbq_wait_state *ws; > unsigned int wake_batch; > int wait_cnt; > + bool ret; > > ws = sbq_wake_ptr(sbq); > if (!ws) > @@ -615,12 +616,23 @@ static bool __sbq_wake_up(struct sbitmap_queue *sbq) > * For concurrent callers of this, callers should call this function > * again to wakeup a new batch on a different 'ws'. > */ > - if (wait_cnt < 0 || !waitqueue_active(&ws->wait)) > + if (wait_cnt < 0) > return true; > > + /* > + * If we decremented queue without waiters, retry to avoid lost > + * wakeups. > + */ > if (wait_cnt > 0) > - return false; > + return !waitqueue_active(&ws->wait); > > + /* > + * When wait_cnt == 0, we have to be particularly careful as we are > + * responsible to reset wait_cnt regardless whether we've actually > + * woken up anybody. But in case we didn't wakeup anybody, we still > + * need to retry. > + */ > + ret = !waitqueue_active(&ws->wait); > wake_batch = READ_ONCE(sbq->wake_batch); > > /* > @@ -649,7 +661,7 @@ static bool __sbq_wake_up(struct sbitmap_queue *sbq) > sbq_index_atomic_inc(&sbq->wake_index); > atomic_set(&ws->wait_cnt, wake_batch); > > - return false; > + return ret; > } > > void sbitmap_queue_wake_up(struct sbitmap_queue *sbq) > -- > 2.35.1 > > > > ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2022-10-19 17:38 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20221019083249.951566199@linuxfoundation.org>
[not found] ` <20221019083311.114449669@linuxfoundation.org>
2022-10-19 15:06 ` [PATCH 6.0 479/862] sbitmap: fix possible io hung due to lost wakeup Hugh Dickins
2022-10-19 17:25 ` Greg Kroah-Hartman
2022-10-19 17:37 ` Jens Axboe
[not found] ` <20221019083312.840347737@linuxfoundation.org>
2022-10-19 15:08 ` [PATCH 6.0 517/862] sbitmap: Avoid leaving waitqueue in invalid state in __sbq_wake_up() Hugh Dickins
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox