From d50c5917f07a0674e4e48a19d6902d17fb43e5bc Mon Sep 17 00:00:00 2001 From: Matthias Koenig Date: Mon, 9 Jun 2008 16:38:25 +0200 Subject: [PATCH] mount: retry on ENOMEDIUM Due to a change in kernel behaviour when opening CDROM devices, we need to retry the open/mount call when ENOMEDIUM is returned. Explanation from Tejun Heo: Okay, the difference is from the addition of cdrom_get_media_event() call to both sr_drive_status() and ide_cdrom_drive_status(). Previously, the cdrom driver can't differentiate between tray closed w/ no media and tray open and always returned tray open, which triggers close and retry in the open logic which probably have delayed things enough to get the media recognized. Now the cdrom driver can discern between tray closed w/o media and device not ready for other reasons and returns -ENOMEDIUM on the former. This is all good and dandy but the problem seems that some drives report no media right after the tray is closed but it hasn't properly detected the media yet. It seems the only way to work around the problem is via sensible retries (e.g. try three times 5 secs apart) and I don't think we can add that type of retry logic into cdrom open path. Please note that the previous logic wasn't water proof. Some drives can take longer to recognize the media is there and could have failed the in-kernel retry too. Also, reading the media can take quite some time and during that period the drive reports media present but device not ready. The driver will retry the command (e.g. READ TOC for open) five times but all of them can fail w/ EMEDIUMTYPE. [kzak@redhat.com: - add CRDOM_NOMEDIUM_RETRIES to blkdev.h - add verbose message to mount.c] Signed-off-by: Matthias Koenig Signed-off-by: Karel Zak --- include/blkdev.h | 3 +++ mount/fsprobe_volumeid.c | 11 ++++++++++- mount/mount.c | 13 +++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/blkdev.h b/include/blkdev.h index 1b10569b..409b5e43 100644 --- a/include/blkdev.h +++ b/include/blkdev.h @@ -6,6 +6,9 @@ #define DEFAULT_SECTOR_SIZE 512 +/* open() retries when errno is ENOMEDIUM */ +#define CRDOM_NOMEDIUM_RETRIES 5 + #if !defined(BLKROSET) && defined(__linux__) #define BLKROSET _IO(0x12,93) /* set device read-only (0 = read-write) */ diff --git a/mount/fsprobe_volumeid.c b/mount/fsprobe_volumeid.c index 7c98dc6e..949db829 100644 --- a/mount/fsprobe_volumeid.c +++ b/mount/fsprobe_volumeid.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -30,10 +31,18 @@ static char struct volume_id *id; const char *val; char *value = NULL; + int retries = 0; +retry: fd = open(device, O_RDONLY); - if (fd < 0) + if (fd < 0) { + if (errno == ENOMEDIUM && retries < CRDOM_NOMEDIUM_RETRIES) { + ++retries; + sleep(3); + goto retry; + } return NULL; + } id = volume_id_open_fd(fd); if (!id) { diff --git a/mount/mount.c b/mount/mount.c index 39a9bd85..be051355 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -1071,6 +1071,7 @@ try_mount_one (const char *spec0, const char *node0, const char *types0, int loop = 0; const char *loopdev = 0, *loopfile = 0; struct stat statbuf; + int retries = 0; /* Nr of retries for mount in case of ENOMEDIUM */ /* copies for freeing on exit */ const char *opts1, *spec1, *node1, *types1, *extra_opts1; @@ -1133,6 +1134,7 @@ try_mount_one (const char *spec0, const char *node0, const char *types0, goto out; } +mount_retry: block_signals (SIG_BLOCK); if (!fake) { @@ -1362,6 +1364,17 @@ try_mount_one (const char *spec0, const char *node0, const char *types0, } break; } + case ENOMEDIUM: + if (retries < CRDOM_NOMEDIUM_RETRIES) { + if (verbose) + printf(_("mount: no medium found on %s ...trying again\n"), + spec); + sleep(3); + ++retries; + goto mount_retry; + } + error(_("mount: no medium found on %s"), spec); + break; default: error ("mount: %s", strerror (mnt_err)); break; } -- 2.39.5