summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRomain Izard2019-05-03 15:42:22 +0200
committerKarel Zak2019-05-07 12:36:00 +0200
commiteab90ef8d4f66394285e0cff1dfc0a27242c05aa (patch)
tree0c9e4d872f20811c9a091d1ab4162efa8337faae /lib
parentlibsmartcols: use scols_walk_* for calculations and printing (diff)
downloadkernel-qcow2-util-linux-eab90ef8d4f66394285e0cff1dfc0a27242c05aa.tar.gz
kernel-qcow2-util-linux-eab90ef8d4f66394285e0cff1dfc0a27242c05aa.tar.xz
kernel-qcow2-util-linux-eab90ef8d4f66394285e0cff1dfc0a27242c05aa.zip
lib/loopdev.c: Retry LOOP_SET_STATUS64 on EAGAIN
A recent bugfix in the Linux kernel made it possible for the LOOP_SET_STATUS64 ioctl to fail when called with a non-zero offset, with an EAGAIN errno: 5db470e229e2 loop: drop caches if offset or block_size are changed This fix changes a silent failure (where mount could sometimes access the backing loop image through the cache without the specified offset) to an explicit failure, and it has also been backported on stable branches. On a 5.0 kernel, other changes to the loop driver make it hard to get generate the EAGAIN error, but this bugfix has also been backported to stables branches, without these changes. At least with the 4.14 stable branch, the EAGAIN error can be quickly generated with the following loop: while mount -o loop,offset=239 disk point && umount point; do :; done Retry the ioctl when it fails with EAGAIN, which means that mount or losetup will eventually succeed when encountering this case. [kzak@redhat.com: - use our local portable xusleep()] Signed-off-by: Romain Izard <romain.izard.pro@gmail.com> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/loopdev.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/lib/loopdev.c b/lib/loopdev.c
index 5d2e95b7e..952adb872 100644
--- a/lib/loopdev.c
+++ b/lib/loopdev.c
@@ -1275,7 +1275,7 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
*/
int loopcxt_setup_device(struct loopdev_cxt *lc)
{
- int file_fd, dev_fd, mode = O_RDWR, rc = -1, cnt = 0;
+ int file_fd, dev_fd, mode = O_RDWR, rc = -1, cnt = 0, err, again;
int errsv = 0;
if (!lc || !*lc->device || !lc->filename)
@@ -1354,7 +1354,13 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
goto err;
}
- if (ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info)) {
+ do {
+ err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info);
+ again = err && errno == EAGAIN;
+ if (again)
+ xusleep(250000);
+ } while (again);
+ if (err) {
rc = -errno;
errsv = errno;
DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m"));
@@ -1399,7 +1405,7 @@ err:
*/
int loopcxt_ioctl_status(struct loopdev_cxt *lc)
{
- int dev_fd, rc = -1;
+ int dev_fd, rc = -1, err, again;
errno = 0;
dev_fd = loopcxt_get_fd(lc);
@@ -1410,7 +1416,13 @@ int loopcxt_ioctl_status(struct loopdev_cxt *lc)
}
DBG(SETUP, ul_debugobj(lc, "device open: OK"));
- if (ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info)) {
+ do {
+ err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->info);
+ again = err && errno == EAGAIN;
+ if (again)
+ xusleep(250000);
+ } while (again);
+ if (err) {
rc = -errno;
DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m"));
return rc;