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.
164 lines
5.6 KiB
164 lines
5.6 KiB
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 <vapier@chromium.org>
|
|
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
|
|
|