You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
87 lines
2.4 KiB
87 lines
2.4 KiB
2 months ago
|
From 1a5c0e60308651a20d25ff52511230a20d830330 Mon Sep 17 00:00:00 2001
|
||
|
From: Logan Gunthorpe <logang@deltatee.com>
|
||
|
Date: Tue, 4 Jun 2024 10:38:36 -0600
|
||
|
Subject: [PATCH 102/157] mdadm: Fix hang race condition in
|
||
|
wait_for_zero_forks()
|
||
|
|
||
|
Running a create operation with --write-zeros can randomly hang
|
||
|
forever waiting for child processes. This happens roughly on in
|
||
|
ten runs with when running with small (20MB) loop devices.
|
||
|
|
||
|
The bug is caused by the fact that signals can be coallesced into
|
||
|
one if they are not read by signalfd quick enough. So if two children
|
||
|
finish at exactly the same time, only one SIGCHLD will be received
|
||
|
by the parent.
|
||
|
|
||
|
To fix this, wait on all processes with WNOHANG every time a SIGCHLD
|
||
|
is received and exit when all processes have been waited on.
|
||
|
|
||
|
Reported-by: Xiao Ni <xni@redhat.com>
|
||
|
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
|
||
|
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
|
||
|
---
|
||
|
Create.c | 28 +++++++++++++++-------------
|
||
|
1 file changed, 15 insertions(+), 13 deletions(-)
|
||
|
|
||
|
diff --git a/Create.c b/Create.c
|
||
|
index d033eb68..4f992a22 100644
|
||
|
--- a/Create.c
|
||
|
+++ b/Create.c
|
||
|
@@ -178,6 +178,7 @@ static int wait_for_zero_forks(int *zero_pids, int count)
|
||
|
bool interrupted = false;
|
||
|
sigset_t sigset;
|
||
|
ssize_t s;
|
||
|
+ pid_t pid;
|
||
|
|
||
|
for (i = 0; i < count; i++)
|
||
|
if (zero_pids[i])
|
||
|
@@ -196,7 +197,7 @@ static int wait_for_zero_forks(int *zero_pids, int count)
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
- while (1) {
|
||
|
+ while (wait_count) {
|
||
|
s = read(sfd, &fdsi, sizeof(fdsi));
|
||
|
if (s != sizeof(fdsi)) {
|
||
|
pr_err("Invalid signalfd read: %s\n", strerror(errno));
|
||
|
@@ -209,23 +210,24 @@ static int wait_for_zero_forks(int *zero_pids, int count)
|
||
|
pr_info("Interrupting zeroing processes, please wait...\n");
|
||
|
interrupted = true;
|
||
|
} else if (fdsi.ssi_signo == SIGCHLD) {
|
||
|
- if (!--wait_count)
|
||
|
- break;
|
||
|
+ for (i = 0; i < count; i++) {
|
||
|
+ if (!zero_pids[i])
|
||
|
+ continue;
|
||
|
+
|
||
|
+ pid = waitpid(zero_pids[i], &wstatus, WNOHANG);
|
||
|
+ if (pid <= 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ zero_pids[i] = 0;
|
||
|
+ if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus))
|
||
|
+ ret = 1;
|
||
|
+ wait_count--;
|
||
|
+ }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
close(sfd);
|
||
|
|
||
|
- for (i = 0; i < count; i++) {
|
||
|
- if (!zero_pids[i])
|
||
|
- continue;
|
||
|
-
|
||
|
- waitpid(zero_pids[i], &wstatus, 0);
|
||
|
- zero_pids[i] = 0;
|
||
|
- if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus))
|
||
|
- ret = 1;
|
||
|
- }
|
||
|
-
|
||
|
if (interrupted) {
|
||
|
pr_err("zeroing interrupted!\n");
|
||
|
return 1;
|
||
|
--
|
||
|
2.41.0
|
||
|
|