From e25ca3c260442c3908ec4bf3a70ab117142c8545b5c36d98842442d9d8ff1574 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 13 Jun 2013 04:16:10 +0000 Subject: [PATCH] - assemble-EXCL-race.fix: avoid some races during array assembled- particularly at boot (bnc#793954) - boot.md: make sure systemd-udev-trigger runs before boot.md to avoid races: bnc#793954 - mdmon@.service - new file plus patches to allow mdmon to be started by systemd, so it doesn't kill it (bnc#321366) OBS-URL: https://build.opensuse.org/package/show/Base:System/mdadm?expand=0&rev=85 --- ...launching-mdmon-via-systemctl-instea.patch | 99 +++++++++++++++++++ ...g-mdmon-fails-print-an-error-message.patch | 28 ++++++ 0003-mdmon-add-foreground-option.patch | 94 ++++++++++++++++++ ...ppress-error-messages-from-systemctl.patch | 30 ++++++ assemble-EXCL-race.fix | 74 ++++++++++++++ boot.md | 2 +- mdadm.changes | 11 +++ mdadm.spec | 21 +++- 8 files changed, 356 insertions(+), 3 deletions(-) create mode 100644 0001-Add-support-for-launching-mdmon-via-systemctl-instea.patch create mode 100644 0002-In-case-launching-mdmon-fails-print-an-error-message.patch create mode 100644 0003-mdmon-add-foreground-option.patch create mode 100644 0004-Suppress-error-messages-from-systemctl.patch create mode 100644 assemble-EXCL-race.fix diff --git a/0001-Add-support-for-launching-mdmon-via-systemctl-instea.patch b/0001-Add-support-for-launching-mdmon-via-systemctl-instea.patch new file mode 100644 index 0000000..af2b6e7 --- /dev/null +++ b/0001-Add-support-for-launching-mdmon-via-systemctl-instea.patch @@ -0,0 +1,99 @@ +References: bnc#821366 +Git-commit: 0f7bdf8946316548500858303549e396655450c5 +From: Jes Sorensen +Date: Fri, 1 Feb 2013 16:15:18 +0100 +Subject: [PATCH] Add support for launching mdmon via systemctl instead of + fork/exec + +If launching mdmon via systemctl fails, we fall back to the old method +of fork/exec. This allows for having mdmon launched via systemctl +which avoids problems with it getting killed by systemd due to it +ending up in the parent's cgroup (udev). + +Signed-off-by: Jes Sorensen +Signed-off-by: NeilBrown +--- + Makefile | 4 ++++ + systemd/mdmon@.service | 18 ++++++++++++++++++ + util.c | 28 ++++++++++++++++++++++++++++ + 3 files changed, 50 insertions(+) + create mode 100644 systemd/mdmon@.service + +--- mdadm-3.2.6.orig/Makefile ++++ mdadm-3.2.6/Makefile +@@ -73,6 +73,7 @@ MAP_PATH = $(MAP_DIR)/$(MAP_FILE) + MDMON_DIR = $(MAP_DIR) + # place for autoreplace cookies + FAILED_SLOTS_DIR = /run/mdadm/failed-slots ++SYSTEMD_DIR=/lib/systemd/system + DIRFLAGS = -DMAP_DIR=\"$(MAP_DIR)\" -DMAP_FILE=\"$(MAP_FILE)\" + DIRFLAGS += -DMDMON_DIR=\"$(MDMON_DIR)\" + DIRFLAGS += -DFAILED_SLOTS_DIR=\"$(FAILED_SLOTS_DIR)\" +@@ -256,6 +257,9 @@ install-man: mdadm.8 md.4 mdadm.conf.5 m + install-udev: udev-md-raid.rules + $(INSTALL) -D -m 644 udev-md-raid.rules $(DESTDIR)/lib/udev/rules.d/64-md-raid.rules + ++install-systemd: systemd/mdmon@.service ++ $(INSTALL) -D -m 644 systemd/mdmon@.service $(DESTDIR)$(SYSTEMD_DIR)/mdmon@.service ++ + uninstall: + rm -f $(DESTDIR)$(MAN8DIR)/mdadm.8 $(DESTDIR)$(MAN8DIR)/mdmon.8 $(DESTDIR)$(MAN4DIR)/md.4 $(DESTDIR)$(MAN5DIR)/mdadm.conf.5 $(DESTDIR)$(BINDIR)/mdadm + +--- /dev/null ++++ mdadm-3.2.6/systemd/mdmon@.service +@@ -0,0 +1,18 @@ ++# This file is part of mdadm. ++# ++# mdadm is free software; you can redistribute it and/or modify it ++# under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++ ++[Unit] ++Description=MD Metadata Monitor on /dev/%I ++DefaultDependencies=no ++Before=initrd-switch-root.target ++ ++[Service] ++ExecStart=/sbin/mdmon %I ++StandardInput=null ++StandardOutput=null ++StandardError=null ++KillMode=none +--- mdadm-3.2.6.orig/util.c ++++ mdadm-3.2.6/util.c +@@ -1641,6 +1641,34 @@ int start_mdmon(int devnum) + } else + pathbuf[0] = '\0'; + ++ /* First try to run systemctl */ ++ switch(fork()) { ++ case 0: ++ /* FIXME yuk. CLOSE_EXEC?? */ ++ skipped = 0; ++ for (i = 3; skipped < 20; i++) ++ if (close(i) < 0) ++ skipped++; ++ else ++ skipped = 0; ++ ++ snprintf(pathbuf, sizeof(pathbuf), "mdmon@%s.service", ++ devnum2devname(devnum)); ++ status = execl("/usr/bin/systemctl", "systemctl", "start", ++ pathbuf, NULL); ++ status = execl("/bin/systemctl", "systemctl", "start", ++ pathbuf, NULL); ++ exit(1); ++ case -1: fprintf(stderr, Name ":cannot run mdmon. " ++ "Array remains readonly\n"); ++ return -1; ++ default: /* parent - good */ ++ pid = wait(&status); ++ if (pid >= 0 && status == 0) ++ return 0; ++ } ++ ++ /* That failed, try running mdmon directly */ + switch(fork()) { + case 0: + /* FIXME yuk. CLOSE_EXEC?? */ diff --git a/0002-In-case-launching-mdmon-fails-print-an-error-message.patch b/0002-In-case-launching-mdmon-fails-print-an-error-message.patch new file mode 100644 index 0000000..b8d3970 --- /dev/null +++ b/0002-In-case-launching-mdmon-fails-print-an-error-message.patch @@ -0,0 +1,28 @@ +References: bnc#821366 +Git-commit: 15c10423aa9435ed72bd292fecca69224a20fdc8 +From: Jes Sorensen +Date: Fri, 1 Feb 2013 16:15:19 +0100 +Subject: [PATCH] In case launching mdmon fails, print an error message before + exiting + +Signed-off-by: Jes Sorensen +Signed-off-by: NeilBrown +--- + util.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- mdadm-3.2.6.orig/util.c ++++ mdadm-3.2.6/util.c +@@ -1697,8 +1697,11 @@ int start_mdmon(int devnum) + return -1; + default: /* parent - good */ + pid = wait(&status); +- if (pid < 0 || status != 0) ++ if (pid < 0 || status != 0) { ++ fprintf(stderr, Name ":failed to launch mdmon. " ++ "Array remains readonly\n"); + return -1; ++ } + } + return 0; + } diff --git a/0003-mdmon-add-foreground-option.patch b/0003-mdmon-add-foreground-option.patch new file mode 100644 index 0000000..d926ea8 --- /dev/null +++ b/0003-mdmon-add-foreground-option.patch @@ -0,0 +1,94 @@ +References: bnc#821366 +Git-commit: 030419821fb77f9955f2017b4a6d3d8139d6db25 +From: NeilBrown +Date: Tue, 5 Feb 2013 15:57:09 +1100 +Subject: [PATCH] mdmon: add --foreground option + +While not strictly necessary for systemd, it is cleaner to avoid +forking when running from a management daemon. So add a --foreground +option to mdmon. + +Signed-off-by: NeilBrown +--- + mdmon.8 | 10 +++++++++- + mdmon.c | 9 +++++++-- + systemd/mdmon@.service | 2 +- + 3 files changed, 17 insertions(+), 4 deletions(-) + +--- mdadm-3.2.6.orig/mdmon.8 ++++ mdadm-3.2.6/mdmon.8 +@@ -5,7 +5,7 @@ mdmon \- monitor MD external metadata ar + + .SH SYNOPSIS + +-.BI mdmon " [--all] [--takeover] [--offroot] CONTAINER" ++.BI mdmon " [--all] [--takeover] [--offroot] [--foreground] CONTAINER" + + .SH OVERVIEW + The 2.6.27 kernel brings the ability to support external metadata arrays. +@@ -131,6 +131,14 @@ The + device to monitor. It can be a full path like /dev/md/container, or a + simple md device name like md127. + .TP ++.B \-\-foreground ++Normally, ++.I mdmon ++will fork and continue in the background. Adding this option will ++skip that step and run ++.I mdmon ++in the foreground. ++.TP + .B \-\-takeover + This instructs + .I mdmon +--- mdadm-3.2.6.orig/mdmon.c ++++ mdadm-3.2.6/mdmon.c +@@ -295,15 +295,17 @@ int main(int argc, char *argv[]) + int opt; + int all = 0; + int takeover = 0; ++ int dofork = 1; + static struct option options[] = { + {"all", 0, NULL, 'a'}, + {"takeover", 0, NULL, 't'}, + {"help", 0, NULL, 'h'}, + {"offroot", 0, NULL, OffRootOpt}, ++ {"foreground", 0, NULL, 'F'}, + {NULL, 0, NULL, 0} + }; + +- while ((opt = getopt_long(argc, argv, "tha", options, NULL)) != -1) { ++ while ((opt = getopt_long(argc, argv, "thaF", options, NULL)) != -1) { + switch (opt) { + case 'a': + container_name = argv[optind-1]; +@@ -312,6 +314,9 @@ int main(int argc, char *argv[]) + case 't': + takeover = 1; + break; ++ case 'F': ++ dofork = 0; ++ break; + case OffRootOpt: + argv[0][0] = '@'; + break; +@@ -383,7 +388,7 @@ int main(int argc, char *argv[]) + container_name); + exit(1); + } +- return mdmon(devname, devnum, do_fork(), takeover); ++ return mdmon(devname, devnum, dofork && do_fork(), takeover); + } + + static int mdmon(char *devname, int devnum, int must_fork, int takeover) +--- mdadm-3.2.6.orig/systemd/mdmon@.service ++++ mdadm-3.2.6/systemd/mdmon@.service +@@ -11,7 +11,7 @@ DefaultDependencies=no + Before=initrd-switch-root.target + + [Service] +-ExecStart=/sbin/mdmon %I ++ExecStart=/sbin/mdmon --foreground %I + StandardInput=null + StandardOutput=null + StandardError=null diff --git a/0004-Suppress-error-messages-from-systemctl.patch b/0004-Suppress-error-messages-from-systemctl.patch new file mode 100644 index 0000000..4796f21 --- /dev/null +++ b/0004-Suppress-error-messages-from-systemctl.patch @@ -0,0 +1,30 @@ +References: bnc#821366 +Git-commit: 701d5b4ab5ad72f8998d4398d5b209fea877ce37 +From: NeilBrown +Date: Wed, 15 May 2013 11:10:54 +1000 +Subject: [PATCH] Suppress error messages from systemctl. + +We call systemctl to see if systemd will run mdmon for us. +If it cannot, we run mdmon directly, so we aren't interested +in the error message. +So redirect stderr to /dev/null. + +Signed-off-by: NeilBrown +--- + util.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- mdadm-3.2.6.orig/util.c ++++ mdadm-3.2.6/util.c +@@ -1652,6 +1652,11 @@ int start_mdmon(int devnum) + else + skipped = 0; + ++ /* Don't want to see error messages from systemctl. ++ * If the service doesn't exist, we start mdmon ourselves. ++ */ ++ close(2); ++ open("/dev/null", O_WRONLY); + snprintf(pathbuf, sizeof(pathbuf), "mdmon@%s.service", + devnum2devname(devnum)); + status = execl("/usr/bin/systemctl", "systemctl", "start", diff --git a/assemble-EXCL-race.fix b/assemble-EXCL-race.fix new file mode 100644 index 0000000..84bf188 --- /dev/null +++ b/assemble-EXCL-race.fix @@ -0,0 +1,74 @@ +From: NeilBrown +References: bnc#793954 + +If we get EBUSY when openning a device during ASSEMBLE, +try again a limited number of times as we could be racing with +"mdadm -I" from udev or similar. + +This is fixed upstream by more intrusive locking changed. + +Signed-off-by: NeilBrown +--- + Assemble.c | 36 +++++++++++++++++++++++++++++------- + 1 file changed, 29 insertions(+), 7 deletions(-) + +--- mdadm-3.2.6.orig/Assemble.c ++++ mdadm-3.2.6/Assemble.c +@@ -494,7 +494,7 @@ int Assemble(struct supertype *st, char + tmpdev = NULL; + goto loop; + } else { +- ++ int cnt = 5; + content = &info; + tst->ss->getinfo_super(tst, content, NULL); + +@@ -508,6 +508,13 @@ int Assemble(struct supertype *st, char + * be looking at + */ + dfd = dev_open(devname, O_RDONLY | O_EXCL); ++ while (dfd < 0 && errno == EBUSY && cnt > 0) { ++ fprintf(stderr, "EBUSY - retrying dev_open of %s\n", ++ devname); ++ usleep(200000); ++ dfd = dev_open(devname, O_RDONLY | O_EXCL); ++ cnt--; ++ } + if (dfd < 0) { + if (report_missmatch) + fprintf(stderr, Name ": %s is busy - skipping\n", devname); +@@ -1315,13 +1322,28 @@ int Assemble(struct supertype *st, char + j = chosen_drive; + + if (j >= 0 /* && devices[j].uptodate */) { +- int dfd = dev_open(devices[j].devname, +- O_RDWR|O_EXCL); +- if (dfd >= 0) { +- remove_partitions(dfd); +- close(dfd); ++ int cnt = 5; ++ while (cnt > 0) { ++ int dfd = dev_open(devices[j].devname, ++ O_RDWR|O_EXCL); ++ cnt--; ++ if (dfd < 0 && errno == EBUSY) { ++ fprintf(stderr, "EBUSY - retrying open of %s\n", ++ devices[j].devname); ++ usleep(200000); ++ continue; ++ } ++ if (dfd >= 0) { ++ remove_partitions(dfd); ++ close(dfd); ++ } ++ rv = add_disk(mdfd, st, content, &devices[j].i); ++ if (rv == 0 || errno != EBUSY) ++ break; ++ fprintf(stderr, "EBUSY - retrying add of %s\n", ++ devices[j].devname); ++ usleep(200000); + } +- rv = add_disk(mdfd, st, content, &devices[j].i); + + if (rv) { + fprintf(stderr, Name ": failed to add " diff --git a/boot.md b/boot.md index 23a8948..ba033cc 100644 --- a/boot.md +++ b/boot.md @@ -23,7 +23,7 @@ # Provides: boot.md # Required-Start: boot.udev boot.rootfsck # Required-Stop: $null -# Should-Start: boot.scsidev boot.multipath udev-trigger +# Should-Start: boot.scsidev boot.multipath systemd-udev-trigger # Should-Stop: boot.scsidev boot.multipath # Default-Start: B # Default-Stop: diff --git a/mdadm.changes b/mdadm.changes index d00ac2b..1863ee4 100644 --- a/mdadm.changes +++ b/mdadm.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Thu Jun 13 04:12:54 UTC 2013 - nfbrown@suse.com + +- assemble-EXCL-race.fix: avoid some races during + array assembled- particularly at boot (bnc#793954) +- boot.md: make sure systemd-udev-trigger runs before + boot.md to avoid races: bnc#793954 +- mdmon@.service - new file plus patches to allow + mdmon to be started by systemd, so it doesn't + kill it (bnc#321366) + ------------------------------------------------------------------- Tue Apr 16 10:38:19 UTC 2013 - idonmez@suse.com diff --git a/mdadm.spec b/mdadm.spec index 34e353f..9dec453 100644 --- a/mdadm.spec +++ b/mdadm.spec @@ -20,6 +20,7 @@ Name: mdadm Version: 3.2.6 Release: 0 BuildRequires: binutils-devel +BuildRequires: groff BuildRequires: pkgconfig BuildRequires: sgmltool BuildRequires: pkgconfig(libudev) @@ -42,9 +43,19 @@ Source5: mkinitrd-setup.sh Source6: mkinitrd-boot.sh Source7: mdadm.cron Source8: mdadm.shutdown +#PATCH-FIX-UPSTREAM assemble-EXCL-race.fix bnc#793954 +Patch1: assemble-EXCL-race.fix +#PATCH-FIX-UPSTREAM 0001-Add-support-for-launching-mdmon-via-systemctl-instea.patch bnc#821366 +Patch2: 0001-Add-support-for-launching-mdmon-via-systemctl-instea.patch +#PATCH-FIX-UPSTREAM 0002-In-case-launching-mdmon-fails-print-an-error-message.patch bnc#821366 +Patch3: 0002-In-case-launching-mdmon-fails-print-an-error-message.patch +#PATCH-FIX-UPSTREAM 0003-mdmon-add-foreground-option.patch bnc#821366 +Patch4: 0003-mdmon-add-foreground-option.patch +#PATCH-FIX-UPSTREAM 0004-Suppress-error-messages-from-systemctl.patch bnc#821366 +Patch5: 0004-Suppress-error-messages-from-systemctl.patch %define _udevrulesdir %(pkg-config --variable=udevdir udev)/rules.d -%define _systemdshutdowndir %{_unitdir}/../system-shutdown +%define _systemdshutdowndir %{_unitdir}/../system-shutdown %description Mdadm is a program that can be used to control Linux md devices. It is @@ -53,6 +64,11 @@ programs but with a very different interface. %prep %setup -q -a1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 %build make %{?_smp_mflags} CC="%__cc" CXFLAGS="$RPM_OPT_FLAGS -Wno-error" @@ -61,7 +77,7 @@ sgml2html Software-RAID.HOWTO.sgml sgml2txt Software-RAID.HOWTO.sgml %install -make install DESTDIR=%{buildroot} +make install install-systemd DESTDIR=%{buildroot} SYSTEMD_DIR=%{_unitdir} rm -rf %{buildroot}/lib/udev install -d %{buildroot}%{_var}/adm/fillup-templates install -d %{buildroot}{%{_sbindir},%{_sysconfdir}/init.d} @@ -125,5 +141,6 @@ rm -rf %{buildroot} %dir /etc/cron.daily /etc/cron.daily/mdadm %{_systemdshutdowndir}/mdadm.shutdown +%{_unitdir}/mdmon@.service %changelog