From 53b543476d271cce71c4f5b66d9d6a28f1a75370 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Wed, 9 Mar 2022 11:28:07 +0100 Subject: lib/loopdev: consolidate ioctls calls on EAGAIN Keep all logic to repeat ioctl calls in one macro rather than duplicate code. Addresses: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=2117203 Signed-off-by: Karel Zak --- lib/loopdev.c | 97 ++++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/lib/loopdev.c b/lib/loopdev.c index fda0e1210..cceab2db1 100644 --- a/lib/loopdev.c +++ b/lib/loopdev.c @@ -43,7 +43,6 @@ #include "debug.h" #include "fileutils.h" - #define LOOPDEV_MAX_TRIES 10 /* @@ -77,6 +76,24 @@ static void loopdev_init_debug(void) #define loopcxt_sysfs_available(_lc) (!((_lc)->flags & LOOPDEV_FL_NOSYSFS)) \ && !loopcxt_ioctl_enabled(_lc) +/* + * Calls @x and repeat on EAGAIN + */ +#define repeat_on_eagain(x) __extension__ ({ \ + int _c = 0, _e; \ + do { \ + errno = 0; \ + _e = x; \ + if (_e == 0 || errno != EAGAIN) \ + break; \ + if (_c >= LOOPDEV_MAX_TRIES) \ + break; \ + xusleep(250000); \ + _c++; \ + } while (1); \ + _e == 0 ? 0 : errno ? -errno : -1; \ + }) + /* * @lc: context * @device: device name, absolute device path or NULL to reset the current setting @@ -1276,6 +1293,7 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd) return 0; } + /* * @lc: context * @@ -1364,8 +1382,9 @@ int loopcxt_setup_device(struct loopdev_cxt *lc) * -- since Linux v5.8-rc1, commit 3448914e8cc550ba792d4ccc74471d1ca4293aae */ lc->config.fd = file_fd; - if (ioctl(dev_fd, LOOP_CONFIGURE, &lc->config) < 0) { - rc = -errno; + + rc = repeat_on_eagain( ioctl(dev_fd, LOOP_CONFIGURE, &lc->config) ); + if (rc != 0) { errsv = errno; if (errno != EINVAL && errno != ENOTTY) { DBG(SETUP, ul_debugobj(lc, "LOOP_CONFIGURE failed: %m")); @@ -1430,6 +1449,7 @@ err: return rc; } + /* * @lc: context * @@ -1443,28 +1463,18 @@ err: */ int loopcxt_ioctl_status(struct loopdev_cxt *lc) { - int dev_fd, rc = -1, err, again, tries = 0; + int dev_fd, rc; errno = 0; dev_fd = loopcxt_get_fd(lc); - if (dev_fd < 0) { - rc = -errno; - return rc; - } - DBG(SETUP, ul_debugobj(lc, "device open: OK")); + if (dev_fd < 0) + return -errno; - do { - err = ioctl(dev_fd, LOOP_SET_STATUS64, &lc->config.info); - again = err && errno == EAGAIN; - if (again) { - xusleep(250000); - tries++; - } - } while (again && tries <= LOOPDEV_MAX_TRIES); + DBG(SETUP, ul_debugobj(lc, "calling LOOP_SET_STATUS64")); - if (err) { - rc = -errno; + rc = repeat_on_eagain( ioctl(dev_fd, LOOP_SET_STATUS64, &lc->config.info) ); + if (rc != 0) { DBG(SETUP, ul_debugobj(lc, "LOOP_SET_STATUS64 failed: %m")); return rc; } @@ -1475,14 +1485,16 @@ int loopcxt_ioctl_status(struct loopdev_cxt *lc) int loopcxt_ioctl_capacity(struct loopdev_cxt *lc) { - int fd = loopcxt_get_fd(lc); + int rc, fd = loopcxt_get_fd(lc); if (fd < 0) return -EINVAL; + DBG(SETUP, ul_debugobj(lc, "calling LOOP_SET_CAPACITY")); + /* Kernels prior to v2.6.30 don't support this ioctl */ - if (ioctl(fd, LOOP_SET_CAPACITY, 0) < 0) { - int rc = -errno; + rc = repeat_on_eagain( ioctl(fd, LOOP_SET_CAPACITY, 0) ); + if (rc != 0) { DBG(CXT, ul_debugobj(lc, "LOOP_SET_CAPACITY failed: %m")); return rc; } @@ -1493,14 +1505,16 @@ int loopcxt_ioctl_capacity(struct loopdev_cxt *lc) int loopcxt_ioctl_dio(struct loopdev_cxt *lc, unsigned long use_dio) { - int fd = loopcxt_get_fd(lc); + int rc, fd = loopcxt_get_fd(lc); if (fd < 0) return -EINVAL; + DBG(SETUP, ul_debugobj(lc, "calling LOOP_SET_DIRECT_IO")); + /* Kernels prior to v4.4 don't support this ioctl */ - if (ioctl(fd, LOOP_SET_DIRECT_IO, use_dio) < 0) { - int rc = -errno; + rc = repeat_on_eagain( ioctl(fd, LOOP_SET_DIRECT_IO, use_dio) ); + if (rc != 0) { DBG(CXT, ul_debugobj(lc, "LOOP_SET_DIRECT_IO failed: %m")); return rc; } @@ -1515,25 +1529,19 @@ int loopcxt_ioctl_dio(struct loopdev_cxt *lc, unsigned long use_dio) */ int loopcxt_ioctl_blocksize(struct loopdev_cxt *lc, uint64_t blocksize) { - int fd = loopcxt_get_fd(lc); - int err, again, tries = 0; + int rc, fd = loopcxt_get_fd(lc); if (fd < 0) return -EINVAL; - do { - /* Kernels prior to v4.14 don't support this ioctl */ - err = ioctl(fd, LOOP_SET_BLOCK_SIZE, (unsigned long) blocksize); - again = err && errno == EAGAIN; - if (again) { - xusleep(250000); - tries++; - } else if (err) { - int rc = -errno; - DBG(CXT, ul_debugobj(lc, "LOOP_SET_BLOCK_SIZE failed: %m")); - return rc; - } - } while (again && tries <= LOOPDEV_MAX_TRIES); + DBG(SETUP, ul_debugobj(lc, "calling LOOP_SET_BLOCK_SIZE")); + + rc = repeat_on_eagain( + ioctl(fd, LOOP_SET_BLOCK_SIZE, (unsigned long) blocksize) ); + if (rc != 0) { + DBG(CXT, ul_debugobj(lc, "LOOP_SET_BLOCK_SIZE failed: %m")); + return rc; + } DBG(CXT, ul_debugobj(lc, "logical block size set")); return 0; @@ -1541,14 +1549,17 @@ int loopcxt_ioctl_blocksize(struct loopdev_cxt *lc, uint64_t blocksize) int loopcxt_delete_device(struct loopdev_cxt *lc) { - int fd = loopcxt_get_fd(lc); + int rc, fd = loopcxt_get_fd(lc); if (fd < 0) return -EINVAL; - if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { + DBG(SETUP, ul_debugobj(lc, "calling LOOP_SET_CLR_FD")); + + rc = repeat_on_eagain( ioctl(fd, LOOP_CLR_FD, 0) ); + if (rc != 0) { DBG(CXT, ul_debugobj(lc, "LOOP_CLR_FD failed: %m")); - return -errno; + return rc; } DBG(CXT, ul_debugobj(lc, "device removed")); -- 2.37.1