]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
losetup: wait for udev
authorKarel Zak <kzak@redhat.com>
Fri, 24 Jan 2014 12:58:40 +0000 (13:58 +0100)
committerKarel Zak <kzak@redhat.com>
Fri, 24 Jan 2014 12:58:40 +0000 (13:58 +0100)
On system with /dev/lop-control the udevd creates /dev/loopN nodes.
It seems better to wait a moment after unsuccessful open(/dev/loopN)
and try it to open again.

The problem is pretty visible on systems where udevd also modifies
permission for loopN devices, then open() fails with EACCES when
losetup executed by non-root user (but user who is in "disk" group).

Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1045432
Signed-off-by: Karel Zak <kzak@redhat.com>
include/loopdev.h
lib/loopdev.c

index eb328a080dd512825d6edb4bc7bdb45897389303..793539935fb42e64d6c01a5fb609c99f791b1d1e 100644 (file)
@@ -99,6 +99,7 @@ struct loopdev_cxt {
        unsigned int    extra_check:1;  /* unusual stuff for iterator */
        unsigned int    debug:1;        /* debug mode ON/OFF */
        unsigned int    info_failed:1;  /* LOOP_GET_STATUS ioctl failed */
+       unsigned int    control_ok:1;   /* /dev/loop-control success */
 
        struct sysfs_cxt        sysfs;  /* pointer to /sys/dev/block/<maj:min>/ */
        struct loop_info64      info;   /* for GET/SET ioctl */
index a636a89c8d36a4f1a80e46f44f828cb2d2e00be8..5153eaa8021942a226456b67e5a4810505d46ac5 100644 (file)
@@ -291,9 +291,8 @@ int loopcxt_get_fd(struct loopdev_cxt *lc)
        if (lc->fd < 0) {
                lc->mode = lc->flags & LOOPDEV_FL_RDWR ? O_RDWR : O_RDONLY;
                lc->fd = open(lc->device, lc->mode | O_CLOEXEC);
-               DBG(lc, loopdev_debug("open %s [%s]: %s", lc->device,
-                               lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro",
-                               lc->fd < 0 ? "failed" : "ok"));
+               DBG(lc, loopdev_debug("open %s [%s]: %m", lc->device,
+                               lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro"));
        }
        return lc->fd;
 }
@@ -1182,7 +1181,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;
+       int file_fd, dev_fd, mode = O_RDWR, rc = -1, cnt = 0;
 
        if (!lc || !*lc->device || !lc->filename)
                return -EINVAL;
@@ -1222,7 +1221,19 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
                lc->flags &= ~LOOPDEV_FL_RDONLY;
        }
 
-       dev_fd = loopcxt_get_fd(lc);
+       do {
+               errno = 0;
+               dev_fd = loopcxt_get_fd(lc);
+               if (dev_fd >= 0 || lc->control_ok == 0)
+                       break;
+               if (errno != EACCES && errno != ENOENT)
+                       break;
+               /* We have permissions to open /dev/loop-control, but open
+                * /dev/loopN failed with EACCES, it's probably because udevd
+                * does not applied chown yet. Let's wait a moment. */
+               xusleep(25000);
+       } while (cnt++ < 16);
+
        if (dev_fd < 0) {
                rc = -errno;
                goto err;
@@ -1328,6 +1339,7 @@ int loopcxt_add_device(struct loopdev_cxt *lc)
                rc = ioctl(ctl, LOOP_CTL_ADD, nr);
                close(ctl);
        }
+       lc->control_ok = rc >= 0 ? 1 : 0;
 done:
        DBG(lc, loopdev_debug("add_device done [rc=%d]", rc));
        return rc;
@@ -1356,6 +1368,7 @@ int loopcxt_find_unused(struct loopdev_cxt *lc)
 
                        rc = loopiter_set_device(lc, name);
                }
+               lc->control_ok = ctl >= 0 && rc == 0 ? 1 : 0;
                if (ctl >= 0)
                        close(ctl);
                DBG(lc, loopdev_debug("find_unused by loop-control [rc=%d]", rc));