All of lore.kernel.org
 help / color / mirror / Atom feed
From: mwilck@suse.com
To: Christophe Varoqui <christophe.varoqui@opensvc.com>,
	Benjamin Marzinski <bmarzins@redhat.com>
Cc: dm-devel@redhat.com, Martin Wilck <mwilck@suse.com>
Subject: [dm-devel] [PATCH v2 15/21] kpartx: use opened loop device immediately
Date: Wed,  1 Dec 2021 13:36:44 +0100	[thread overview]
Message-ID: <20211201123650.16240-16-mwilck@suse.com> (raw)
In-Reply-To: <20211201123650.16240-1-mwilck@suse.com>

From: Martin Wilck <mwilck@suse.com>

The code in find_unused_loop_device() goes through circles to
get an unused device, but it takes no care not to race with a different
process opening the same loop device. Use the once-opened
loop device for setup immediately instead of closing and re-opening it.

While at it, simplify the code somewhat.

Reviewed-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 kpartx/kpartx.c |  4 +--
 kpartx/lopart.c | 83 ++++++++++++++++++++-----------------------------
 kpartx/lopart.h |  3 +-
 3 files changed, 35 insertions(+), 55 deletions(-)

diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index 7bc6454..3c49999 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -359,9 +359,7 @@ main(int argc, char **argv){
 			exit (0);
 
 		if (!loopdev) {
-			loopdev = find_unused_loop_device();
-
-			if (set_loop(loopdev, rpath, 0, &ro)) {
+			if (set_loop(&loopdev, rpath, 0, &ro)) {
 				fprintf(stderr, "can't set up loop\n");
 				exit (1);
 			}
diff --git a/kpartx/lopart.c b/kpartx/lopart.c
index 2661940..7041ddf 100644
--- a/kpartx/lopart.c
+++ b/kpartx/lopart.c
@@ -39,24 +39,6 @@
 #define LOOP_CTL_GET_FREE       0x4C82
 #endif
 
-static char *
-xstrdup (const char *s)
-{
-	char *t;
-
-	if (s == NULL)
-		return NULL;
-
-	t = strdup (s);
-
-	if (t == NULL) {
-		fprintf(stderr, "not enough memory");
-		exit(1);
-	}
-
-	return t;
-}
-
 #define SIZE(a) (sizeof(a)/sizeof(a[0]))
 
 char *find_loop_by_file(const char *filename)
@@ -157,9 +139,9 @@ char *find_loop_by_file(const char *filename)
 	return found;
 }
 
-char *find_unused_loop_device(void)
+static char *find_unused_loop_device(int mode, int *loop_fd)
 {
-	char dev[21], *next_loop_dev = NULL;
+	char dev[21];
 	int fd, next_loop = 0, somedev = 0, someloop = 0, loop_known = 0;
 	int next_loop_fd;
 	struct stat statbuf;
@@ -168,45 +150,48 @@ char *find_unused_loop_device(void)
 
 	next_loop_fd = open("/dev/loop-control", O_RDWR);
 	if (next_loop_fd < 0)
-		return NULL;
+		goto no_loop_fd;
 
-	if (!(fstat(next_loop_fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode))) {
-		close(next_loop_fd);
-		return NULL;
-	}
+	if (!(fstat(next_loop_fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)))
+		goto nothing_found;
 
-	while (next_loop_dev == NULL) {
+	for (;;) {
 		next_loop = ioctl(next_loop_fd, LOOP_CTL_GET_FREE);
-		if (next_loop < 0) {
-			close(next_loop_fd);
-			return NULL;
-		}
+		if (next_loop < 0)
+			goto nothing_found;
+
 		sprintf(dev, "/dev/loop%d", next_loop);
 
-		fd = open (dev, O_RDONLY);
+		fd = open (dev, mode);
 		if (fd >= 0) {
 			if (fstat (fd, &statbuf) == 0 &&
 			    S_ISBLK(statbuf.st_mode)) {
 				somedev++;
 				if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0)
 					someloop++;		/* in use */
-				else if (errno == ENXIO)
-					next_loop_dev = xstrdup(dev);
+				else if (errno == ENXIO) {
+					char *name = strdup(dev);
+
+					if (name == NULL)
+						close(fd);
+					else
+						*loop_fd = fd;
+					close(next_loop_fd);
+					return name;
+				}
 
 			}
 			close (fd);
 
 			/* continue trying as long as devices exist */
-			continue;
-		}
-		break;
+		} else
+			break;
 	}
 
+nothing_found:
 	close(next_loop_fd);
 
-	if (next_loop_dev)
-		return next_loop_dev;
-
+no_loop_fd:
 	/* Nothing found. Why not? */
 	if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
 		char line[100];
@@ -248,10 +233,10 @@ char *find_unused_loop_device(void)
 	return NULL;
 }
 
-int set_loop(const char *device, const char *file, int offset, int *loopro)
+int set_loop(char **device, const char *file, int offset, int *loopro)
 {
 	struct loop_info loopinfo;
-	int fd, ffd, mode;
+	int fd = -1, ret = 1, ffd, mode;
 
 	mode = (*loopro ? O_RDONLY : O_RDWR);
 
@@ -266,9 +251,9 @@ int set_loop(const char *device, const char *file, int offset, int *loopro)
 		}
 	}
 
-	if ((fd = open (device, mode)) < 0) {
+	*device = find_unused_loop_device(mode, &fd);
+	if (!*device) {
 		close(ffd);
-		perror (device);
 		return 1;
 	}
 
@@ -282,22 +267,20 @@ int set_loop(const char *device, const char *file, int offset, int *loopro)
 
 	if (ioctl(fd, LOOP_SET_FD, (void*)(uintptr_t)(ffd)) < 0) {
 		perror ("ioctl: LOOP_SET_FD");
-		close (fd);
-		close (ffd);
-		return 1;
+		goto out;
 	}
 
 	if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) {
 		(void) ioctl (fd, LOOP_CLR_FD, 0);
 		perror ("ioctl: LOOP_SET_STATUS");
-		close (fd);
-		close (ffd);
-		return 1;
+		goto out;
 	}
+	ret = 0;
 
+out:
 	close (fd);
 	close (ffd);
-	return 0;
+	return ret;
 }
 
 int del_loop(const char *device)
diff --git a/kpartx/lopart.h b/kpartx/lopart.h
index d3bad10..c73ab23 100644
--- a/kpartx/lopart.h
+++ b/kpartx/lopart.h
@@ -1,5 +1,4 @@
 extern int verbose;
-extern int set_loop (const char *, const char *, int, int *);
+extern int set_loop (char **, const char *, int, int *);
 extern int del_loop (const char *);
-extern char * find_unused_loop_device (void);
 extern char * find_loop_by_file (const char *);
-- 
2.33.1


--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel


  parent reply	other threads:[~2021-12-01 12:37 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-01 12:36 [dm-devel] [PATCH v2 00/21] multipath-tools: coverity fixes mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 01/21] multipath tools: github workflows: add coverity workflow mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 02/21] multipathd (coverity): check atexit() return value mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 03/21] multipathd (coverity): terminate uxlsnr when polls allocation fails mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 04/21] libmultipath: strbuf: add __get_strbuf_buf() mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 05/21] libmultipath (coverity): improve input checking in parse_vpd_pg83 mwilck
2021-12-01 18:35   ` Benjamin Marzinski
2021-12-01 12:36 ` [dm-devel] [PATCH v2 06/21] multipath-tools: add tests for broken VPD page 83 mwilck
2021-12-01 18:37   ` Benjamin Marzinski
2021-12-01 12:36 ` [dm-devel] [PATCH v2 07/21] libmultipath: use strbuf in parse_vpd_pg83() mwilck
2021-12-01 18:36   ` Benjamin Marzinski
2021-12-01 12:36 ` [dm-devel] [PATCH v2 08/21] libmultipath (coverity): fix tainted values in alua_rtpg.c mwilck
2021-12-01 19:08   ` Benjamin Marzinski
2021-12-01 12:36 ` [dm-devel] [PATCH v2 09/21] multipath, multipathd: exit if bindings file is broken mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 10/21] libmultipath (coverity): silence unchecked return value warning mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 11/21] multipath: remove pointless code from getopt processing mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 12/21] libmultipath (coverity): set umask before mkstemp mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 13/21] multipathd (coverity): simplify set_oom_adj() mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 14/21] kpartx: open /dev/loop-control only once mwilck
2021-12-01 12:36 ` mwilck [this message]
2021-12-01 12:36 ` [dm-devel] [PATCH v2 16/21] kpartx: find_unused_loop_device(): add newlines mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 17/21] multipathd (coverity): daemonize(): use dup2 mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 18/21] libmultipath (coverity): avoid sleeping in dm_mapname() mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 19/21] libmultipath (coverity): Revert "setup_map: wait for pending path checkers to finish" mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 20/21] libmultipath (coverity): check return values in dm_get_multipath() mwilck
2021-12-01 12:36 ` [dm-devel] [PATCH v2 21/21] libmultipath: update_pathvec_from_dm: don't force DI_WWID mwilck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211201123650.16240-16-mwilck@suse.com \
    --to=mwilck@suse.com \
    --cc=bmarzins@redhat.com \
    --cc=christophe.varoqui@opensvc.com \
    --cc=dm-devel@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.