linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Ming Lei <ming.lei@redhat.com>,
	John Garry <john.garry@huawei.com>,
	David Jeffery <djeffery@redhat.com>,
	Bart Van Assche <bvanassche@acm.org>,
	Jens Axboe <axboe@kernel.dk>, Sasha Levin <sashal@kernel.org>,
	linux-block@vger.kernel.org
Subject: [PATCH AUTOSEL 5.12 13/52] blk-mq: clear stale request in tags->rq[] before freeing one request pool
Date: Mon,  5 Jul 2021 11:28:34 -0400	[thread overview]
Message-ID: <20210705152913.1521036-13-sashal@kernel.org> (raw)
In-Reply-To: <20210705152913.1521036-1-sashal@kernel.org>

From: Ming Lei <ming.lei@redhat.com>

[ Upstream commit bd63141d585bef14f4caf111f6d0e27fe2300ec6 ]

refcount_inc_not_zero() in bt_tags_iter() still may read one freed
request.

Fix the issue by the following approach:

1) hold a per-tags spinlock when reading ->rqs[tag] and calling
refcount_inc_not_zero in bt_tags_iter()

2) clearing stale request referred via ->rqs[tag] before freeing
request pool, the per-tags spinlock is held for clearing stale
->rq[tag]

So after we cleared stale requests, bt_tags_iter() won't observe
freed request any more, also the clearing will wait for pending
request reference.

The idea of clearing ->rqs[] is borrowed from John Garry's previous
patch and one recent David's patch.

Tested-by: John Garry <john.garry@huawei.com>
Reviewed-by: David Jeffery <djeffery@redhat.com>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20210511152236.763464-4-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 block/blk-mq-tag.c |  9 +++++++--
 block/blk-mq-tag.h |  6 ++++++
 block/blk-mq.c     | 46 +++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c
index 6772c3728865..c4f2f6c123ae 100644
--- a/block/blk-mq-tag.c
+++ b/block/blk-mq-tag.c
@@ -202,10 +202,14 @@ struct bt_iter_data {
 static struct request *blk_mq_find_and_get_req(struct blk_mq_tags *tags,
 		unsigned int bitnr)
 {
-	struct request *rq = tags->rqs[bitnr];
+	struct request *rq;
+	unsigned long flags;
 
+	spin_lock_irqsave(&tags->lock, flags);
+	rq = tags->rqs[bitnr];
 	if (!rq || !refcount_inc_not_zero(&rq->ref))
-		return NULL;
+		rq = NULL;
+	spin_unlock_irqrestore(&tags->lock, flags);
 	return rq;
 }
 
@@ -538,6 +542,7 @@ struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags,
 
 	tags->nr_tags = total_tags;
 	tags->nr_reserved_tags = reserved_tags;
+	spin_lock_init(&tags->lock);
 
 	if (flags & BLK_MQ_F_TAG_HCTX_SHARED)
 		return tags;
diff --git a/block/blk-mq-tag.h b/block/blk-mq-tag.h
index 7d3e6b333a4a..f887988e5ef6 100644
--- a/block/blk-mq-tag.h
+++ b/block/blk-mq-tag.h
@@ -20,6 +20,12 @@ struct blk_mq_tags {
 	struct request **rqs;
 	struct request **static_rqs;
 	struct list_head page_list;
+
+	/*
+	 * used to clear request reference in rqs[] before freeing one
+	 * request pool
+	 */
+	spinlock_t lock;
 };
 
 extern struct blk_mq_tags *blk_mq_init_tags(unsigned int nr_tags,
diff --git a/block/blk-mq.c b/block/blk-mq.c
index d5370ab2eb31..d06ff908f3d9 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -2291,6 +2291,45 @@ blk_qc_t blk_mq_submit_bio(struct bio *bio)
 	return BLK_QC_T_NONE;
 }
 
+static size_t order_to_size(unsigned int order)
+{
+	return (size_t)PAGE_SIZE << order;
+}
+
+/* called before freeing request pool in @tags */
+static void blk_mq_clear_rq_mapping(struct blk_mq_tag_set *set,
+		struct blk_mq_tags *tags, unsigned int hctx_idx)
+{
+	struct blk_mq_tags *drv_tags = set->tags[hctx_idx];
+	struct page *page;
+	unsigned long flags;
+
+	list_for_each_entry(page, &tags->page_list, lru) {
+		unsigned long start = (unsigned long)page_address(page);
+		unsigned long end = start + order_to_size(page->private);
+		int i;
+
+		for (i = 0; i < set->queue_depth; i++) {
+			struct request *rq = drv_tags->rqs[i];
+			unsigned long rq_addr = (unsigned long)rq;
+
+			if (rq_addr >= start && rq_addr < end) {
+				WARN_ON_ONCE(refcount_read(&rq->ref) != 0);
+				cmpxchg(&drv_tags->rqs[i], rq, NULL);
+			}
+		}
+	}
+
+	/*
+	 * Wait until all pending iteration is done.
+	 *
+	 * Request reference is cleared and it is guaranteed to be observed
+	 * after the ->lock is released.
+	 */
+	spin_lock_irqsave(&drv_tags->lock, flags);
+	spin_unlock_irqrestore(&drv_tags->lock, flags);
+}
+
 void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
 		     unsigned int hctx_idx)
 {
@@ -2309,6 +2348,8 @@ void blk_mq_free_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
 		}
 	}
 
+	blk_mq_clear_rq_mapping(set, tags, hctx_idx);
+
 	while (!list_empty(&tags->page_list)) {
 		page = list_first_entry(&tags->page_list, struct page, lru);
 		list_del_init(&page->lru);
@@ -2368,11 +2409,6 @@ struct blk_mq_tags *blk_mq_alloc_rq_map(struct blk_mq_tag_set *set,
 	return tags;
 }
 
-static size_t order_to_size(unsigned int order)
-{
-	return (size_t)PAGE_SIZE << order;
-}
-
 static int blk_mq_init_request(struct blk_mq_tag_set *set, struct request *rq,
 			       unsigned int hctx_idx, int node)
 {
-- 
2.30.2


  parent reply	other threads:[~2021-07-05 15:30 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-05 15:28 [PATCH AUTOSEL 5.12 01/52] HID: do not use down_interruptible() when unbinding devices Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 02/52] EDAC/ti: Add missing MODULE_DEVICE_TABLE Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 03/52] ACPI: PM: s2idle: Add missing LPS0 functions for AMD Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 04/52] ACPI: processor idle: Fix up C-state latency if not ordered Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 05/52] hv_utils: Fix passing zero to 'PTR_ERR' warning Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 06/52] lib: vsprintf: Fix handling of number field widths in vsscanf Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 07/52] Input: goodix - platform/x86: touchscreen_dmi - Move upside down quirks to touchscreen_dmi.c Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 08/52] platform/x86: touchscreen_dmi: Add an extra entry for the upside down Goodix touchscreen on Teclast X89 tablets Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 09/52] platform/x86: touchscreen_dmi: Add info for the Goodix GT912 panel of TM800A550L tablets Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 10/52] ACPI: EC: Make more Asus laptops use ECDT _GPE Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 11/52] block_dump: remove block_dump feature in mark_inode_dirty() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 12/52] blk-mq: grab rq->refcount before calling ->fn in blk_mq_tagset_busy_iter Sasha Levin
2021-07-05 15:28 ` Sasha Levin [this message]
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 14/52] fs: dlm: reconnect if socket error report occurs Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 15/52] fs: dlm: cancel work sync othercon Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 16/52] random32: Fix implicit truncation warning in prandom_seed_state() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 17/52] open: don't silently ignore unknown O-flags in openat2() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 18/52] drivers: hv: Fix missing error code in vmbus_connect() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 19/52] fs: dlm: fix lowcomms_start error case Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 20/52] fs: dlm: fix memory leak when fenced Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 21/52] ACPICA: Fix memory leak caused by _CID repair function Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 22/52] ACPI: bus: Call kobject_put() in acpi_init() error path Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 23/52] ACPI: resources: Add checks for ACPI IRQ override Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 24/52] HID: hid-input: add Surface Go battery quirk Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 25/52] HID: sony: fix freeze when inserting ghlive ps3/wii dongles Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 26/52] block: fix race between adding/removing rq qos and normal IO Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 27/52] platform/x86: asus-nb-wmi: Revert "Drop duplicate DMI quirk structures" Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 28/52] platform/x86: asus-nb-wmi: Revert "add support for ASUS ROG Zephyrus G14 and G15" Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 29/52] platform/x86: toshiba_acpi: Fix missing error code in toshiba_acpi_setup_keyboard() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 30/52] nvme-pci: fix var. type for increasing cq_head Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 31/52] nvmet-fc: do not check for invalid target port in nvmet_fc_handle_fcp_rqst() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 32/52] EDAC/Intel: Do not load EDAC driver when running as a guest Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 33/52] tools/power/x86/intel-speed-select: Fix uncore memory frequency display Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 34/52] PCI: hv: Add check for hyperv_initialized in init_hv_pci_drv() Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 35/52] cifs: improve fallocate emulation Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 36/52] cifs: fix check of dfs interlinks Sasha Levin
2021-07-05 15:28 ` [PATCH AUTOSEL 5.12 37/52] smb3: fix uninitialized value for port in witness protocol move Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210705152913.1521036-13-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=axboe@kernel.dk \
    --cc=bvanassche@acm.org \
    --cc=djeffery@redhat.com \
    --cc=john.garry@huawei.com \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ming.lei@redhat.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).