losetup: wait for udev

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>
This commit is contained in:
Karel Zak 2014-01-24 13:58:40 +01:00
parent a5bd793996
commit 663bf04061
2 changed files with 19 additions and 5 deletions

View 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 */

View 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));