+static pid_t write_zeroes_fork(int fd, struct shape *s, struct supertype *st,
+ struct mddev_dev *dv)
+
+{
+ const unsigned long long req_size = 1 << 30;
+ unsigned long long offset_bytes, size_bytes, sz;
+ sigset_t sigset;
+ int ret = 0;
+ pid_t pid;
+
+ size_bytes = KIB_TO_BYTES(s->size);
+
+ /*
+ * If size_bytes is zero, this is a zoned raid array where
+ * each disk is of a different size and uses its full
+ * disk. Thus zero the entire disk.
+ */
+ if (!size_bytes && !get_dev_size(fd, dv->devname, &size_bytes))
+ return -1;
+
+ if (dv->data_offset != INVALID_SECTORS)
+ offset_bytes = SEC_TO_BYTES(dv->data_offset);
+ else
+ offset_bytes = SEC_TO_BYTES(st->data_offset);
+
+ pr_info("zeroing data from %lld to %lld on: %s\n",
+ offset_bytes, size_bytes, dv->devname);
+
+ pid = fork();
+ if (pid < 0) {
+ pr_err("Could not fork to zero disks: %s\n", strerror(errno));
+ return pid;
+ } else if (pid != 0) {
+ return pid;
+ }
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGINT);
+ sigprocmask(SIG_UNBLOCK, &sigset, NULL);
+
+ while (size_bytes) {
+ /*
+ * Split requests to the kernel into 1GB chunks seeing the
+ * fallocate() call is not interruptible and blocking a
+ * ctrl-c for several minutes is not desirable.
+ *
+ * 1GB is chosen as a compromise: the user may still have
+ * to wait several seconds if they ctrl-c on devices that
+ * zero slowly, but will reduce the number of requests
+ * required and thus the overhead on devices that perform
+ * better.
+ */
+ sz = size_bytes;
+ if (sz >= req_size)
+ sz = req_size;
+
+ if (fallocate(fd, FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE,
+ offset_bytes, sz)) {
+ pr_err("zeroing %s failed: %s\n", dv->devname,
+ strerror(errno));
+ ret = 1;
+ break;
+ }
+
+ offset_bytes += sz;
+ size_bytes -= sz;
+ }
+
+ exit(ret);
+}
+
+static int wait_for_zero_forks(int *zero_pids, int count)
+{
+ int wstatus, ret = 0, i, sfd, wait_count = 0;
+ struct signalfd_siginfo fdsi;
+ bool interrupted = false;
+ sigset_t sigset;
+ ssize_t s;
+
+ for (i = 0; i < count; i++)
+ if (zero_pids[i])
+ wait_count++;
+ if (!wait_count)
+ return 0;
+
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGINT);
+ sigaddset(&sigset, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigset, NULL);
+
+ sfd = signalfd(-1, &sigset, 0);
+ if (sfd < 0) {
+ pr_err("Unable to create signalfd: %s\n", strerror(errno));
+ return 1;
+ }
+
+ while (1) {
+ s = read(sfd, &fdsi, sizeof(fdsi));
+ if (s != sizeof(fdsi)) {
+ pr_err("Invalid signalfd read: %s\n", strerror(errno));
+ close(sfd);
+ return 1;
+ }
+
+ if (fdsi.ssi_signo == SIGINT) {
+ printf("\n");
+ pr_info("Interrupting zeroing processes, please wait...\n");
+ interrupted = true;
+ } else if (fdsi.ssi_signo == SIGCHLD) {
+ if (!--wait_count)
+ break;
+ }
+ }
+
+ 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;
+ }
+
+ if (ret)
+ pr_err("zeroing failed!\n");
+ else
+ pr_info("zeroing finished\n");
+
+ return ret;
+}
+