blk-ioc: protect ioc_destroy_icq() by 'queue_lock'
authorYu Kuai <yukuai3@huawei.com>
Wed, 31 May 2023 07:34:35 +0000 (15:34 +0800)
committerJens Axboe <axboe@kernel.dk>
Thu, 1 Jun 2023 15:13:31 +0000 (09:13 -0600)
commit5a0ac57c48aa9380126bd9bf3ec82140aab84548
tree7d440f4a22f244eea9dfbcd27edc62457f923c9a
parent6c500000af037f74b66dd01b565c8ee1b501cc1b
blk-ioc: protect ioc_destroy_icq() by 'queue_lock'

Currently, icq is tracked by both request_queue(icq->q_node) and
task(icq->ioc_node), and ioc_clear_queue() from elevator exit is not
safe because it can access the list without protection:

ioc_clear_queue ioc_release_fn
 lock queue_lock
 list_splice
 /* move queue list to a local list */
 unlock queue_lock
 /*
  * lock is released, the local list
  * can be accessed through task exit.
  */

lock ioc->lock
while (!hlist_empty)
 icq = hlist_entry
 lock queue_lock
  ioc_destroy_icq
   delete icq->ioc_node
 while (!list_empty)
  icq = list_entry()    list_del icq->q_node
  /*
   * This is not protected by any lock,
   * list_entry concurrent with list_del
   * is not safe.
   */

 unlock queue_lock
unlock ioc->lock

Fix this problem by protecting list 'icq->q_node' by queue_lock from
ioc_clear_queue().

Reported-and-tested-by: Pradeep Pragallapati <quic_pragalla@quicinc.com>
Link: https://lore.kernel.org/lkml/20230517084434.18932-1-quic_pragalla@quicinc.com/
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20230531073435.2923422-1-yukuai1@huaweicloud.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-ioc.c