From: Xiao Ni <xni@redhat.com>
To: songliubraving@fb.com, linux-raid@vger.kernel.org
Cc: ncroxon@redhat.com, heinzm@redhat.com, djeffery@redhat.com
Subject: [PATCH 1/1] Set prev_flush_start and flush_bio in an atomic way
Date: Thu, 10 Dec 2020 14:33:32 +0800 [thread overview]
Message-ID: <1607582012-9501-1-git-send-email-xni@redhat.com> (raw)
One customer reports a crash problem which causes by flush request. It triggers a warning
before crash.
/* new request after previous flush is completed */
if (ktime_after(req_start, mddev->prev_flush_start)) {
WARN_ON(mddev->flush_bio);
mddev->flush_bio = bio;
bio = NULL;
}
The WARN_ON is triggered. We use spin lock to protect prev_flush_start and flush_bio
in md_flush_request. But there is no lock protection in md_submit_flush_data. It can
set flush_bio to NULL first because of compiler reordering write instructions.
For example, flush bio1 sets flush bio to NULL first in md_submit_flush_data. An
interrupt or vmware causing an extended stall happen between updating flush_bio and
prev_flush_start. Because flush_bio is NULL, flush bio2 can get the lock and submit
to underlayer disks. Then flush bio1 updates prev_flush_start after the interrupt or
exteneded stall.
Then flush bio3 enters in md_flush_request. The start time req_start is behind
prev_flush_start. The flush_bio is not NULL(flush bio2 hasn't finished). So it can
trigger the WARN_ON now. Then it calls INIT_WORK again. INIT_WORK() will re-initialize
the list pointers in the work_struct, which then can result in a corrupted work list
and the work_struct queued a second time. With the work list corrupted, it can lead
in invalid work items being used and cause a crash in process_one_work.
We need to make sure only one flush bio can be handled at one same time. So add
spin lock in md_submit_flush_data to protect prev_flush_start and flush_bio in
an atomic way.
Reviewed-by: David Jeffery <djeffery@redhat.com>
Signed-off-by: Xiao Ni <xni@redhat.com>
---
drivers/md/md.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index c42af46..2746d5c 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -639,8 +639,10 @@ static void md_submit_flush_data(struct work_struct *ws)
* could wait for this and below md_handle_request could wait for those
* bios because of suspend check
*/
+ spin_lock_irq(&mddev->lock);
mddev->prev_flush_start = mddev->start_flush;
mddev->flush_bio = NULL;
+ spin_unlock_irq(&mddev->lock);
wake_up(&mddev->sb_wait);
if (bio->bi_iter.bi_size == 0) {
--
2.7.5
next reply other threads:[~2020-12-10 6:35 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-12-10 6:33 Xiao Ni [this message]
2021-01-12 9:24 ` [PATCH 1/1] Set prev_flush_start and flush_bio in an atomic way Xiao Ni
2021-01-12 21:36 ` Song Liu
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=1607582012-9501-1-git-send-email-xni@redhat.com \
--to=xni@redhat.com \
--cc=djeffery@redhat.com \
--cc=heinzm@redhat.com \
--cc=linux-raid@vger.kernel.org \
--cc=ncroxon@redhat.com \
--cc=songliubraving@fb.com \
/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).