Blob Blame History Raw
From 53b543476d271cce71c4f5b66d9d6a28f1a75370 Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@redhat.com>
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 <kzak@redhat.com>
---
 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