From f073c56142eebe7e2d71a3d1386810eda7e9107a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 10 Nov 2016 00:20:17 -0500 Subject: sys-fs/mtools: fix locking errors w/syslinux & udev --- sys-fs/mtools/files/mtools-4.0.18-locking.patch | 163 ++++++++++++++++++++++++ sys-fs/mtools/mtools-4.0.18-r1.ebuild | 51 ++++++++ 2 files changed, 214 insertions(+) create mode 100644 sys-fs/mtools/files/mtools-4.0.18-locking.patch create mode 100644 sys-fs/mtools/mtools-4.0.18-r1.ebuild (limited to 'sys-fs/mtools') diff --git a/sys-fs/mtools/files/mtools-4.0.18-locking.patch b/sys-fs/mtools/files/mtools-4.0.18-locking.patch new file mode 100644 index 000000000000..3b53c73c645c --- /dev/null +++ b/sys-fs/mtools/files/mtools-4.0.18-locking.patch @@ -0,0 +1,163 @@ +https://crbug.com/508713 +https://lists.gnu.org/archive/html/info-mtools/2016-11/msg00000.html + +From 04df65ed797e47da5b423c7f9aec99d82dfde400 Mon Sep 17 00:00:00 2001 +From: Mike Frysinger +Date: Wed, 7 Sep 2016 12:33:42 -0400 +Subject: [PATCH] add support for retrying device locking + +When running syslinux's install phase, it will run a bunch of mtools +commands in quick succession. If you're on a fast enough machine, it +can often fail with errors like: +plain floppy: device "/proc/2908/fd/3" busy (Resource temporarily unavailable): +Cannot initialize 'S:' +Bad target s:/ldlinux.sys +syslinux: failed to create ldlinux.sys + +The issue is that after some of the mtools calls, the kernel notices +that the fs image has changed, so it notifies userspace. This wakes +up udev which grabs a lock on the device to rescan it for changes +(e.g. updated fs metadata like UUID). The udev phase does not finish +before syslinux fires off another mtools call which means mtools now +fails with a locking error. + +You can recreate this with a simple test: +- loop mount a fat fs image +- open the loop device for writing +- generate a mtools.conf pointing the file to /proc/$pid/fd/$fd +- run mattrib && mcopy +- see udev open/lock the loop device after mattrib runs to probe it +- see mcopy fail because udev is still holding the lock + +To fix things, we teach mtools to retry its locking calls temporarily. +If it still fails after a timeout, we abort like normal. We also make +this behavior configurable by adding a new global timeout option. +--- + config.c | 2 ++ + mtools.h | 1 + + mtools.texi | 7 +++++++ + mtools.tmpl.5 | 4 ++++ + plain_io.c | 10 ++++++++++ + xdf_io.c | 11 +++++++++++ + 6 files changed, 35 insertions(+) + +diff --git a/config.c b/config.c +index f08688399d1d..ea4178452f6a 100644 +--- a/config.c ++++ b/config.c +@@ -63,6 +63,7 @@ unsigned int mtools_no_vfat=0; + unsigned int mtools_numeric_tail=1; + unsigned int mtools_dotted_dir=0; + unsigned int mtools_twenty_four_hour_clock=1; ++unsigned int mtools_lock_timeout=30; + unsigned int mtools_default_codepage=850; + const char *mtools_date_string="yyyy-mm-dd"; + char *country_string=0; +@@ -90,6 +91,7 @@ static switches_t global_switches[] = { + (caddr_t) &mtools_twenty_four_hour_clock, T_UINT }, + { "MTOOLS_DATE_STRING", + (caddr_t) &mtools_date_string, T_STRING }, ++ { "MTOOLS_LOCK_TIMEOUT", (caddr_t) &mtools_lock_timeout, T_UINT }, + { "DEFAULT_CODEPAGE", (caddr_t) &mtools_default_codepage, T_UINT } + }; + +diff --git a/mtools.h b/mtools.h +index ef98e942ee2c..fa8c1bdc8a1b 100644 +--- a/mtools.h ++++ b/mtools.h +@@ -188,6 +188,7 @@ extern unsigned int mtools_ignore_short_case; + extern unsigned int mtools_no_vfat; + extern unsigned int mtools_numeric_tail; + extern unsigned int mtools_dotted_dir; ++extern unsigned int mtools_lock_timeout; + extern unsigned int mtools_twenty_four_hour_clock; + extern const char *mtools_date_string; + extern unsigned int mtools_rate_0, mtools_rate_any; +diff --git a/mtools.texi b/mtools.texi +index 1085789c1cb6..1c7ad94d40f9 100644 +--- a/mtools.texi ++++ b/mtools.texi +@@ -658,6 +658,10 @@ DOSEMU image files. + @vindex MTOOLS_FAT_COMPATIBILITY + @vindex MTOOLS_LOWER_CASE + @vindex MTOOLS_NO_VFAT ++@vindex MTOOLS_DOTTED_DIR ++@vindex MTOOLS_NAME_NUMERIC_TAIL ++@vindex MTOOLS_TWENTY_FOUR_HOUR_CLOCK ++@vindex MTOOLS_LOCK_TIMEOUT + @cindex FreeDOS + + Global flags may be set to 1 or to 0. +@@ -692,6 +696,9 @@ clash would have happened. + @item MTOOLS_TWENTY_FOUR_HOUR_CLOCK + If 1, uses the European notation for times (twenty four hour clock), + else uses the UK/US notation (am/pm) ++@item MTOOLS_LOCK_TIMEOUT ++How long, in seconds, to wait for a locked device to become free. ++Defaults to 30. + @end table + + Example: +diff --git a/mtools.tmpl.5 b/mtools.tmpl.5 +index 565fdd7513aa..8cdaaf2ba929 100644 +--- a/mtools.tmpl.5 ++++ b/mtools.tmpl.5 +@@ -106,6 +106,10 @@ clash would have happened. + \&\fR\&\f(CWMTOOLS_TWENTY_FOUR_HOUR_CLOCK\fR\ + If 1, uses the European notation for times (twenty four hour clock), + else uses the UK/US notation (am/pm) ++.TP ++\&\fR\&\f(CWMTOOLS_LOCK_TIMEOUT\fR\ ++How long, in seconds, to wait for a locked device to become free. ++Defaults to 30. + .PP + Example: + Inserting the following line into your configuration file instructs +diff --git a/plain_io.c b/plain_io.c +index c9d8418b8b4d..3dc035c9ce92 100644 +--- a/plain_io.c ++++ b/plain_io.c +@@ -632,7 +632,17 @@ APIRET rc; + #ifndef __CYGWIN__ + #ifndef OS_mingw32msvc + /* lock the device on writes */ ++ retry: + if (locked && lock_dev(This->fd, mode == O_RDWR, dev)) { ++ /* retry the lock in case another system process (e.g. udev) ++ * has temporarily locked the device. this happens when you ++ * run multiple mtools commands at once which triggers the ++ * system to lock/rescan/unlock. */ ++ static int retries = 0; ++ if (errno == EAGAIN && retries++ < mtools_lock_timeout * 10) { ++ usleep(100); ++ goto retry; ++ } + if(errmsg) + #ifdef HAVE_SNPRINTF + snprintf(errmsg,199, +diff --git a/xdf_io.c b/xdf_io.c +index f0db3b3d9f38..8f64f6348f0c 100644 +--- a/xdf_io.c ++++ b/xdf_io.c +@@ -638,7 +638,18 @@ Stream_t *XdfOpen(struct device *dev, char *name, + goto exit_2; + + /* lock the device on writes */ ++ retry: + if (lock_dev(This->fd, mode == O_RDWR, dev)) { ++ /* retry the lock in case another system process (e.g. udev) ++ * has temporarily locked the device. this happens when you ++ * run multiple mtools commands at once which triggers the ++ * system to lock/rescan/unlock. */ ++ static int retries = 0; ++ if (errno == EAGAIN && retries++ < mtools_lock_timeout * 10) { ++ usleep(100); ++ goto retry; ++ } ++ + #ifdef HAVE_SNPRINTF + snprintf(errmsg,199,"xdf floppy: device \"%s\" busy:", + dev->name); +-- +2.9.0 + diff --git a/sys-fs/mtools/mtools-4.0.18-r1.ebuild b/sys-fs/mtools/mtools-4.0.18-r1.ebuild new file mode 100644 index 000000000000..cb981c349079 --- /dev/null +++ b/sys-fs/mtools/mtools-4.0.18-r1.ebuild @@ -0,0 +1,51 @@ +# Copyright 1999-2016 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +EAPI="5" + +inherit flag-o-matic + +DESCRIPTION="utilities to access MS-DOS disks from Unix without mounting them" +HOMEPAGE="http://mtools.linux.lu/" +SRC_URI="mirror://gnu/${PN}/${P}.tar.bz2" + +LICENSE="GPL-3" +SLOT="0" +KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ppc ~ppc64 ~sparc ~x86 ~x64-macos ~x64-solaris" +IUSE="X elibc_glibc" + +DEPEND=" + !elibc_glibc? ( virtual/libiconv ) + X? ( + x11-libs/libICE + x11-libs/libXau + x11-libs/libSM + x11-libs/libX11 + x11-libs/libXt + )" +RDEPEND="${DEPEND}" + +src_prepare() { + # Don't throw errors on existing directories + sed -i -e "s:mkdir:mkdir -p:" mkinstalldirs || die + + epatch "${FILESDIR}"/${P}-locking.patch # https://crbug.com/508713 +} + +src_configure() { + # 447688 + use elibc_glibc || append-libs iconv + econf \ + --sysconfdir="${EPREFIX}"/etc/mtools \ + $(use_with X x) +} + +src_install() { + emake DESTDIR="${D}" install + dodoc README* Release.notes + + insinto /etc/mtools + doins mtools.conf + # default is fine + sed -i -e '/^SAMPLE FILE$/s:^:#:' "${ED}"/etc/mtools/mtools.conf || die +} -- cgit v1.2.3-65-gdbad