summaryrefslogtreecommitdiffstats
path: root/sys/dev/nvme
diff options
context:
space:
mode:
authorjimharris <jimharris@FreeBSD.org>2015-11-23 17:26:20 +0000
committerjimharris <jimharris@FreeBSD.org>2015-11-23 17:26:20 +0000
commite7b87655f99a1ecf09ab62b98b6c0fe5c00ada72 (patch)
treeb63b1016a1ab94ed058f0146bd4a0de25adb661c /sys/dev/nvme
parentd2f61b2025b492fdac9e1367f9953e02f2808c54 (diff)
downloadFreeBSD-src-e7b87655f99a1ecf09ab62b98b6c0fe5c00ada72.zip
FreeBSD-src-e7b87655f99a1ecf09ab62b98b6c0fe5c00ada72.tar.gz
MFC r290198:
nvme: fix race condition in split bio completion path Sponsored by: Intel
Diffstat (limited to 'sys/dev/nvme')
-rw-r--r--sys/dev/nvme/nvme_ns.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/sys/dev/nvme/nvme_ns.c b/sys/dev/nvme/nvme_ns.c
index 84a1980..c6a00df 100644
--- a/sys/dev/nvme/nvme_ns.c
+++ b/sys/dev/nvme/nvme_ns.c
@@ -239,7 +239,7 @@ static void
nvme_bio_child_inbed(struct bio *parent, int bio_error)
{
struct nvme_completion parent_cpl;
- int inbed;
+ int children, inbed;
if (bio_error != 0) {
parent->bio_flags |= BIO_ERROR;
@@ -248,10 +248,13 @@ nvme_bio_child_inbed(struct bio *parent, int bio_error)
/*
* atomic_fetchadd will return value before adding 1, so we still
- * must add 1 to get the updated inbed number.
+ * must add 1 to get the updated inbed number. Save bio_children
+ * before incrementing to guard against race conditions when
+ * two children bios complete on different queues.
*/
+ children = atomic_load_acq_int(&parent->bio_children);
inbed = atomic_fetchadd_int(&parent->bio_inbed, 1) + 1;
- if (inbed == parent->bio_children) {
+ if (inbed == children) {
bzero(&parent_cpl, sizeof(parent_cpl));
if (parent->bio_flags & BIO_ERROR)
parent_cpl.status.sc = NVME_SC_DATA_TRANSFER_ERROR;
OpenPOWER on IntegriCloud