All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] kpartx: Improve finding loopback device by file
@ 2018-02-05  8:58 Julian Andres Klode
  2018-02-05 10:32 ` Martin Wilck
  0 siblings, 1 reply; 10+ messages in thread
From: Julian Andres Klode @ 2018-02-05  8:58 UTC (permalink / raw)
  To: Christophe Varoqui, Device-mapper development mailing list
  Cc: Julian Andres Klode

Commit 9bdfa3eb8e24b668e6c2bb882cddb0ccfe23ed5b changed kpartx
to lookup files by absolute path, using realpath(). This introduced
a regression when part of the filename where symbolic links. While
the kernel stores the absolute path to the backing file, it does not
resolve symbolic links, and hence kpartx would fail to find the loopback
device because it resolves symbolic links when deleting.

This introduces two workarounds in find_loop_by_file()

(1) We match against the specified file name as is as well
(2) We canonicalize the loopinfo.lo_name and match the canonicalized filename
    against that.

Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/multipath-tools/+bug/1747044
Signed-off-by: Julian Andres Klode <julian.klode@canonical.com>
---
 kpartx/kpartx.c |  8 +-------
 kpartx/lopart.c | 12 +++++++++++-
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
index 442b6bd9..c1af1c5e 100644
--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -327,13 +327,7 @@ main(int argc, char **argv){
 
 	if (S_ISREG (buf.st_mode)) {
 		/* already looped file ? */
-		char rpath[PATH_MAX];
-		if (realpath(device, rpath) == NULL) {
-			fprintf(stderr, "Error: %s: %s\n", device,
-				strerror(errno));
-			exit (1);
-		}
-		loopdev = find_loop_by_file(rpath);
+		loopdev = find_loop_by_file(device);
 
 		if (!loopdev && what == DELETE)
 			exit (0);
diff --git a/kpartx/lopart.c b/kpartx/lopart.c
index 02b29e8c..26b2678c 100644
--- a/kpartx/lopart.c
+++ b/kpartx/lopart.c
@@ -69,6 +69,13 @@ char *find_loop_by_file(const char *filename)
 	struct loop_info loopinfo;
 	const char VIRT_BLOCK[] = "/sys/devices/virtual/block";
 	char path[PATH_MAX];
+	char rfilename[PATH_MAX];
+	char rloopfilename[PATH_MAX];
+	if (realpath(filename, rfilename) == NULL) {
+		fprintf(stderr, "Error: %s: %s\n", filename,
+				strerror(errno));
+		exit (1);
+	}
 
 	dir = opendir(VIRT_BLOCK);
 	if (!dir)
@@ -117,7 +124,10 @@ char *find_loop_by_file(const char *filename)
 
 		close (fd);
 
-		if (0 == strcmp(filename, loopinfo.lo_name)) {
+		if (0 == strcmp(filename, loopinfo.lo_name) ||
+		    0 == strcmp(rfilename, loopinfo.lo_name) ||
+		    (realpath(loopinfo.lo_name, rloopfilename) &&
+		     0 == strcmp(rfilename, rloopfilename))) {
 			found = realpath(path, NULL);
 			break;
 		}
-- 
2.15.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] kpartx: Improve finding loopback device by file
  2018-02-05  8:58 [PATCH] kpartx: Improve finding loopback device by file Julian Andres Klode
@ 2018-02-05 10:32 ` Martin Wilck
  2018-02-05 10:45   ` Julian Andres Klode
  0 siblings, 1 reply; 10+ messages in thread
From: Martin Wilck @ 2018-02-05 10:32 UTC (permalink / raw)
  To: Julian Andres Klode, Christophe Varoqui,
	Device-mapper development mailing list

On Mon, 2018-02-05 at 09:58 +0100, Julian Andres Klode wrote:
> Commit 9bdfa3eb8e24b668e6c2bb882cddb0ccfe23ed5b changed kpartx
> to lookup files by absolute path, using realpath(). This introduced
> a regression when part of the filename where symbolic links. While
> the kernel stores the absolute path to the backing file, it does not
> resolve symbolic links, and hence kpartx would fail to find the
> loopback
> device because it resolves symbolic links when deleting.
> 
> This introduces two workarounds in find_loop_by_file()
> 
> (1) We match against the specified file name as is as well
> (2) We canonicalize the loopinfo.lo_name and match the canonicalized
> filename
>     against that.
> 
> Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/multipath-tools
> /+bug/1747044
> Signed-off-by: Julian Andres Klode <julian.klode@canonical.com>
> ---
>  kpartx/kpartx.c |  8 +-------
>  kpartx/lopart.c | 12 +++++++++++-
>  2 files changed, 12 insertions(+), 8 deletions(-)
> 
> diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
> index 442b6bd9..c1af1c5e 100644
> --- a/kpartx/kpartx.c
> +++ b/kpartx/kpartx.c
> @@ -327,13 +327,7 @@ main(int argc, char **argv){
>  
>  	if (S_ISREG (buf.st_mode)) {
>  		/* already looped file ? */
> -		char rpath[PATH_MAX];
> -		if (realpath(device, rpath) == NULL) {
> -			fprintf(stderr, "Error: %s: %s\n", device,
> -				strerror(errno));
> -			exit (1);
> -		}
> -		loopdev = find_loop_by_file(rpath);
> +		loopdev = find_loop_by_file(device);
>  
>  		if (!loopdev && what == DELETE)
>  			exit (0);
> diff --git a/kpartx/lopart.c b/kpartx/lopart.c
> index 02b29e8c..26b2678c 100644
> --- a/kpartx/lopart.c
> +++ b/kpartx/lopart.c
> @@ -69,6 +69,13 @@ char *find_loop_by_file(const char *filename)
>  	struct loop_info loopinfo;
>  	const char VIRT_BLOCK[] = "/sys/devices/virtual/block";
>  	char path[PATH_MAX];
> +	char rfilename[PATH_MAX];
> +	char rloopfilename[PATH_MAX];
> +	if (realpath(filename, rfilename) == NULL) {
> +		fprintf(stderr, "Error: %s: %s\n", filename,
> +				strerror(errno));
> +		exit (1);
> +	}
>  
>  	dir = opendir(VIRT_BLOCK);
>  	if (!dir)
> @@ -117,7 +124,10 @@ char *find_loop_by_file(const char *filename)
>  
>  		close (fd);
>  
> -		if (0 == strcmp(filename, loopinfo.lo_name)) {
> +		if (0 == strcmp(filename, loopinfo.lo_name) ||
> +		    0 == strcmp(rfilename, loopinfo.lo_name) ||
> +		    (realpath(loopinfo.lo_name, rloopfilename) &&
> +		     0 == strcmp(rfilename, rloopfilename))) {
>  			found = realpath(path, NULL);
>  			break;
>  		}

That "if x matches y or x matches y' or x' matches y" feels like
guesswork. Can't we simply call realpath() on both loopinfo.lo_name and
filename, and compare the two? 

Martin

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] kpartx: Improve finding loopback device by file
  2018-02-05 10:32 ` Martin Wilck
@ 2018-02-05 10:45   ` Julian Andres Klode
  2018-02-05 13:53     ` Martin Wilck
  0 siblings, 1 reply; 10+ messages in thread
From: Julian Andres Klode @ 2018-02-05 10:45 UTC (permalink / raw)
  To: Martin Wilck; +Cc: Device-mapper development mailing list

On Mon, Feb 05, 2018 at 11:32:13AM +0100, Martin Wilck wrote:
> On Mon, 2018-02-05 at 09:58 +0100, Julian Andres Klode wrote:
> > Commit 9bdfa3eb8e24b668e6c2bb882cddb0ccfe23ed5b changed kpartx
> > to lookup files by absolute path, using realpath(). This introduced
> > a regression when part of the filename where symbolic links. While
> > the kernel stores the absolute path to the backing file, it does not
> > resolve symbolic links, and hence kpartx would fail to find the
> > loopback
> > device because it resolves symbolic links when deleting.
> > 
> > This introduces two workarounds in find_loop_by_file()
> > 
> > (1) We match against the specified file name as is as well
> > (2) We canonicalize the loopinfo.lo_name and match the canonicalized
> > filename
> >     against that.
> > 
> > Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/multipath-tools
> > /+bug/1747044
> > Signed-off-by: Julian Andres Klode <julian.klode@canonical.com>
> > ---
> >  kpartx/kpartx.c |  8 +-------
> >  kpartx/lopart.c | 12 +++++++++++-
> >  2 files changed, 12 insertions(+), 8 deletions(-)
> > 
> > diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
> > index 442b6bd9..c1af1c5e 100644
> > --- a/kpartx/kpartx.c
> > +++ b/kpartx/kpartx.c
> > @@ -327,13 +327,7 @@ main(int argc, char **argv){
> >  
> >  	if (S_ISREG (buf.st_mode)) {
> >  		/* already looped file ? */
> > -		char rpath[PATH_MAX];
> > -		if (realpath(device, rpath) == NULL) {
> > -			fprintf(stderr, "Error: %s: %s\n", device,
> > -				strerror(errno));
> > -			exit (1);
> > -		}
> > -		loopdev = find_loop_by_file(rpath);
> > +		loopdev = find_loop_by_file(device);
> >  
> >  		if (!loopdev && what == DELETE)
> >  			exit (0);
> > diff --git a/kpartx/lopart.c b/kpartx/lopart.c
> > index 02b29e8c..26b2678c 100644
> > --- a/kpartx/lopart.c
> > +++ b/kpartx/lopart.c
> > @@ -69,6 +69,13 @@ char *find_loop_by_file(const char *filename)
> >  	struct loop_info loopinfo;
> >  	const char VIRT_BLOCK[] = "/sys/devices/virtual/block";
> >  	char path[PATH_MAX];
> > +	char rfilename[PATH_MAX];
> > +	char rloopfilename[PATH_MAX];
> > +	if (realpath(filename, rfilename) == NULL) {
> > +		fprintf(stderr, "Error: %s: %s\n", filename,
> > +				strerror(errno));
> > +		exit (1);
> > +	}
> >  
> >  	dir = opendir(VIRT_BLOCK);
> >  	if (!dir)
> > @@ -117,7 +124,10 @@ char *find_loop_by_file(const char *filename)
> >  
> >  		close (fd);
> >  
> > -		if (0 == strcmp(filename, loopinfo.lo_name)) {
> > +		if (0 == strcmp(filename, loopinfo.lo_name) ||
> > +		    0 == strcmp(rfilename, loopinfo.lo_name) ||
> > +		    (realpath(loopinfo.lo_name, rloopfilename) &&
> > +		     0 == strcmp(rfilename, rloopfilename))) {
> >  			found = realpath(path, NULL);
> >  			break;
> >  		}
> 
> That "if x matches y or x matches y' or x' matches y" feels like
> guesswork. Can't we simply call realpath() on both loopinfo.lo_name and
> filename, and compare the two? 

Probably yes. That said there might be some corner cases:

(1) What happens if the backing file of a loopback is deleted - realpath
    can fail with ENOENT.
(2) A path could be longer than PATH_MAX and it would fail with ENAMETOOLONG
    - this is a "problem" with the initial realpath as well, but less so, because
    the user can control that.

I guess the 0 == strcmp(rfilename, loopinfo.lo_name) is not likely to happen, but
in the end, I did not want to think that much about it and go with something that
definitely works as best as possible.

-- 
debian developer - deb.li/jak | jak-linux.org - free software dev
ubuntu core developer                              i speak de, en

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] kpartx: Improve finding loopback device by file
  2018-02-05 10:45   ` Julian Andres Klode
@ 2018-02-05 13:53     ` Martin Wilck
  2018-02-05 14:41       ` Julian Andres Klode
  0 siblings, 1 reply; 10+ messages in thread
From: Martin Wilck @ 2018-02-05 13:53 UTC (permalink / raw)
  To: dm-devel, Julian Andres Klode

On Mon, 2018-02-05 at 11:45 +0100, Julian Andres Klode wrote:
> On Mon, Feb 05, 2018 at 11:32:13AM +0100, Martin Wilck wrote:
> > On Mon, 2018-02-05 at 09:58 +0100, Julian Andres Klode wrote:
> > > C
> > >  		close (fd);
> > >  
> > > -		if (0 == strcmp(filename, loopinfo.lo_name)) {
> > > +		if (0 == strcmp(filename, loopinfo.lo_name) ||
> > > +		    0 == strcmp(rfilename, loopinfo.lo_name) ||
> > > +		    (realpath(loopinfo.lo_name, rloopfilename)
> > > &&
> > > +		     0 == strcmp(rfilename, rloopfilename))) {
> > >  			found = realpath(path, NULL);
> > >  			break;
> > >  		}
> > 
> > That "if x matches y or x matches y' or x' matches y" feels like
> > guesswork. Can't we simply call realpath() on both loopinfo.lo_name
> > and
> > filename, and compare the two? 
> 
> Probably yes. That said there might be some corner cases:
> 
> (1) What happens if the backing file of a loopback is deleted -
> realpath
>     can fail with ENOENT.
> (2) A path could be longer than PATH_MAX and it would fail with
> ENAMETOOLONG
>     - this is a "problem" with the initial realpath as well, but less
> so, because
>     the user can control that.

Both are scenarios in which kpartx would have good reason to fail (with
a meaningful error message). That's better than guessing, IMO.

kpartx' functionality to work with loop file names (as opposed to just
block devices) is a convenience feature anyway. I'd rather be certain
to avoid deleting stuff we aren't supposed to.

Regards
Martin

> 
> I guess the 0 == strcmp(rfilename, loopinfo.lo_name) is not likely to
> happen, but
> in the end, I did not want to think that much about it and go with
> something that
> definitely works as best as possible.
> 

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] kpartx: Improve finding loopback device by file
  2018-02-05 13:53     ` Martin Wilck
@ 2018-02-05 14:41       ` Julian Andres Klode
  2018-02-05 15:12         ` Martin Wilck
  0 siblings, 1 reply; 10+ messages in thread
From: Julian Andres Klode @ 2018-02-05 14:41 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Mon, Feb 05, 2018 at 02:53:07PM +0100, Martin Wilck wrote:
> On Mon, 2018-02-05 at 11:45 +0100, Julian Andres Klode wrote:
> > On Mon, Feb 05, 2018 at 11:32:13AM +0100, Martin Wilck wrote:
> > > On Mon, 2018-02-05 at 09:58 +0100, Julian Andres Klode wrote:
> > > > C
> > > >  		close (fd);
> > > >  
> > > > -		if (0 == strcmp(filename, loopinfo.lo_name)) {
> > > > +		if (0 == strcmp(filename, loopinfo.lo_name) ||
> > > > +		    0 == strcmp(rfilename, loopinfo.lo_name) ||
> > > > +		    (realpath(loopinfo.lo_name, rloopfilename)
> > > > &&
> > > > +		     0 == strcmp(rfilename, rloopfilename))) {
> > > >  			found = realpath(path, NULL);
> > > >  			break;
> > > >  		}
> > > 
> > > That "if x matches y or x matches y' or x' matches y" feels like
> > > guesswork. Can't we simply call realpath() on both loopinfo.lo_name
> > > and
> > > filename, and compare the two? 
> > 
> > Probably yes. That said there might be some corner cases:
> > 
> > (1) What happens if the backing file of a loopback is deleted -
> > realpath
> >     can fail with ENOENT.
> > (2) A path could be longer than PATH_MAX and it would fail with
> > ENAMETOOLONG
> >     - this is a "problem" with the initial realpath as well, but less
> > so, because
> >     the user can control that.
> 
> Both are scenarios in which kpartx would have good reason to fail (with
> a meaningful error message). That's better than guessing, IMO.

(1) Definitely not. Just because one of your (potentially other) loopback devices
has a deleted file you should not fail. (2) I don't really know.

But the problem here is that you are looking at loopback devices created by
stuff other than kpartx, and they might not be in a "good" state. But you
don't want to abort just because some _other_ loopback device is broken.

-- 
debian developer - deb.li/jak | jak-linux.org - free software dev
ubuntu core developer                              i speak de, en

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] kpartx: Improve finding loopback device by file
  2018-02-05 14:41       ` Julian Andres Klode
@ 2018-02-05 15:12         ` Martin Wilck
  2018-02-05 15:46           ` Julian Andres Klode
  0 siblings, 1 reply; 10+ messages in thread
From: Martin Wilck @ 2018-02-05 15:12 UTC (permalink / raw)
  To: Julian Andres Klode; +Cc: dm-devel

On Mon, 2018-02-05 at 15:41 +0100, Julian Andres Klode wrote:
> On Mon, Feb 05, 2018 at 02:53:07PM +0100, Martin Wilck wrote:
> > On Mon, 2018-02-05 at 11:45 +0100, Julian Andres Klode wrote:
> > > On Mon, Feb 05, 2018 at 11:32:13AM +0100, Martin Wilck wrote:
> > > > On Mon, 2018-02-05 at 09:58 +0100, Julian Andres Klode wrote:
> > > > > C
> > > > >  		close (fd);
> > > > >  
> > > > > -		if (0 == strcmp(filename, loopinfo.lo_name))
> > > > > {
> > > > > +		if (0 == strcmp(filename, loopinfo.lo_name)
> > > > > ||
> > > > > +		    0 == strcmp(rfilename, loopinfo.lo_name)
> > > > > ||
> > > > > +		    (realpath(loopinfo.lo_name,
> > > > > rloopfilename)
> > > > > &&
> > > > > +		     0 == strcmp(rfilename, rloopfilename)))
> > > > > {
> > > > >  			found = realpath(path, NULL);
> > > > >  			break;
> > > > >  		}
> > > > 
> > > > That "if x matches y or x matches y' or x' matches y" feels
> > > > like
> > > > guesswork. Can't we simply call realpath() on both
> > > > loopinfo.lo_name
> > > > and
> > > > filename, and compare the two? 
> > > 
> > > Probably yes. That said there might be some corner cases:
> > > 
> > > (1) What happens if the backing file of a loopback is deleted -
> > > realpath
> > >     can fail with ENOENT.
> > > (2) A path could be longer than PATH_MAX and it would fail with
> > > ENAMETOOLONG
> > >     - this is a "problem" with the initial realpath as well, but
> > > less
> > > so, because
> > >     the user can control that.
> > 
> > Both are scenarios in which kpartx would have good reason to fail
> > (with
> > a meaningful error message). That's better than guessing, IMO.
> 
> (1) Definitely not. Just because one of your (potentially other)
> loopback devices
> has a deleted file you should not fail.

Sorry for being imprecise. You're right, aborting here while scanning
for a matching device would of course be wrong. And deleting such a
broken loop device can't be a big mistake.

>  (2) I don't really know.
> 
> But the problem here is that you are looking at loopback devices
> created by
> stuff other than kpartx, and they might not be in a "good" state. But
> you
> don't want to abort just because some _other_ loopback device is
> broken.

Can we agree on the following:

 1 if realpath (filename) results in error, abort
 2 if realpath(lo_name) results in ENODEV and filename matches lo_name,
remove loop device
 3 if realpath(lo_name) results in another error code, skip it
 4 remove if realpath(filename) matches realpath(lo_name)

???

Martin

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] kpartx: Improve finding loopback device by file
  2018-02-05 15:12         ` Martin Wilck
@ 2018-02-05 15:46           ` Julian Andres Klode
  2018-02-05 17:07             ` Martin Wilck
  0 siblings, 1 reply; 10+ messages in thread
From: Julian Andres Klode @ 2018-02-05 15:46 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Mon, Feb 05, 2018 at 04:12:00PM +0100, Martin Wilck wrote:
> On Mon, 2018-02-05 at 15:41 +0100, Julian Andres Klode wrote:
> > On Mon, Feb 05, 2018 at 02:53:07PM +0100, Martin Wilck wrote:
> > > On Mon, 2018-02-05 at 11:45 +0100, Julian Andres Klode wrote:
> > > > On Mon, Feb 05, 2018 at 11:32:13AM +0100, Martin Wilck wrote:
> > > > > On Mon, 2018-02-05 at 09:58 +0100, Julian Andres Klode wrote:
> > > > > > C
> > > > > >  		close (fd);
> > > > > >  
> > > > > > -		if (0 == strcmp(filename, loopinfo.lo_name))
> > > > > > {
> > > > > > +		if (0 == strcmp(filename, loopinfo.lo_name)
> > > > > > ||
> > > > > > +		    0 == strcmp(rfilename, loopinfo.lo_name)
> > > > > > ||
> > > > > > +		    (realpath(loopinfo.lo_name,
> > > > > > rloopfilename)
> > > > > > &&
> > > > > > +		     0 == strcmp(rfilename, rloopfilename)))
> > > > > > {
> > > > > >  			found = realpath(path, NULL);
> > > > > >  			break;
> > > > > >  		}
> > > > > 
> > > > > That "if x matches y or x matches y' or x' matches y" feels
> > > > > like
> > > > > guesswork. Can't we simply call realpath() on both
> > > > > loopinfo.lo_name
> > > > > and
> > > > > filename, and compare the two? 
> > > > 
> > > > Probably yes. That said there might be some corner cases:
> > > > 
> > > > (1) What happens if the backing file of a loopback is deleted -
> > > > realpath
> > > >     can fail with ENOENT.
> > > > (2) A path could be longer than PATH_MAX and it would fail with
> > > > ENAMETOOLONG
> > > >     - this is a "problem" with the initial realpath as well, but
> > > > less
> > > > so, because
> > > >     the user can control that.
> > > 
> > > Both are scenarios in which kpartx would have good reason to fail
> > > (with
> > > a meaningful error message). That's better than guessing, IMO.
> > 
> > (1) Definitely not. Just because one of your (potentially other)
> > loopback devices
> > has a deleted file you should not fail.
> 
> Sorry for being imprecise. You're right, aborting here while scanning
> for a matching device would of course be wrong. And deleting such a
> broken loop device can't be a big mistake.
> 
> >  (2) I don't really know.
> > 
> > But the problem here is that you are looking at loopback devices
> > created by
> > stuff other than kpartx, and they might not be in a "good" state. But
> > you
> > don't want to abort just because some _other_ loopback device is
> > broken.
> 
> Can we agree on the following:
> 
>  1 if realpath (filename) results in error, abort

OK


>  2 if realpath(lo_name) results in ENODEV and filename matches lo_name,
> remove loop device
>  3 if realpath(lo_name) results in another error code, skip it
>  4 remove if realpath(filename) matches realpath(lo_name)


This seems like a lot of ifs. It might be easier to just path if
realpath(path) fails (as realpath(1) does), something like:

		
		char *loopname = loopinfo.lo_name;
		if (realpath(loopinfo.lo_name, rloopfilename) != NULL)
			loopname = rloopfilename;

		if (0 == strcmp(filename, loopinfo.lo_name) ||
		    0 == strcmp(rfilename, loopname))) {
			found = realpath(path, NULL);
			break;
		}


That should solve all problems and produce useful results with not
a lot of logic.


We could also abstract that away into:

  const char *safe_realpath(const char *path, char *resolved_path)
  {
    char *real = realpath(path, resolved_path);

    return real != NULL ? real : path;
  }


(this has strange behavior compared to realpath, because it does not
 always return resolved_path; I guess, you could strncpy it there, but
 ugh, seems complicated).


-- 
debian developer - deb.li/jak | jak-linux.org - free software dev
ubuntu core developer                              i speak de, en

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] kpartx: Improve finding loopback device by file
  2018-02-05 15:46           ` Julian Andres Klode
@ 2018-02-05 17:07             ` Martin Wilck
  2018-02-06 11:19               ` Julian Andres Klode
  0 siblings, 1 reply; 10+ messages in thread
From: Martin Wilck @ 2018-02-05 17:07 UTC (permalink / raw)
  To: Julian Andres Klode; +Cc: dm-devel

On Mon, 2018-02-05 at 16:46 +0100, Julian Andres Klode wrote:
> On Mon, Feb 05, 2018 at 04:12:00PM +0100, Martin Wilck wrote:
> > 
> > Can we agree on the following:
> > 
> >  1 if realpath (filename) results in error, abort
> 
> OK
> 
> 
> >  2 if realpath(lo_name) results in ENODEV and filename matches
> > lo_name,
> > remove loop device
> >  3 if realpath(lo_name) results in another error code, skip it
> >  4 remove if realpath(filename) matches realpath(lo_name)
> 
> 
> This seems like a lot of ifs. It might be easier to just path if
> realpath(path) fails (as realpath(1) does), something like:
> 
> 		
> 		char *loopname = loopinfo.lo_name;
> 		if (realpath(loopinfo.lo_name, rloopfilename) != NULL)
> 			loopname = rloopfilename;
> 
> 		if (0 == strcmp(filename, loopinfo.lo_name) ||my
		    0 == strcmp(rfilename, loopname))) {
> 			found = realpath(path, NULL);
> 			break;
> 		}
> 
> 
> That should solve all problems and produce useful results with not
> a lot of logic.

I've reproduced your issue. I can see that the current behavior is
wrong. 

This may be paranoid, but I really want to avoid false positives -
kpartx removing mappings it isn't supposed to remove. Therefore I'd
like to avoid compare by "filename" and "loopname". I think it's
possible.

IMO it would be better to have kpartx use the realpath while *creating*
the partition mapping already:

--- a/kpartx/kpartx.c
+++ b/kpartx/kpartx.c
@@ -341,7 +341,7 @@ main(int argc, char **argv){
                if (!loopdev) {
                        loopdev = find_unused_loop_device();
 
-                       if (set_loop(loopdev, device, 0, &ro)) {
+                       if (set_loop(loopdev, rpath, 0, &ro)) {
                                fprintf(stderr, "can't set up loop\n");
                                exit (1);
                        }


That would make sure that kpartx can delete loop devices created by
itself, which is what we want. IMO it's sufficient to solve your issue.

The -ENODEV case is more tricky, your patch doesn't solve it. If you do

kpartx -a /some/image
rm -f /some/image
kpartx -d /some/image

kpartx -d fails, and that's unrelated to the realpath code (it fails in
stat(device) already). Honestly, I don't think we need to support this
scenario. Setting up a loop device and then deleting the backing file
is shooting oneself in the foot.

Martin

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] kpartx: Improve finding loopback device by file
  2018-02-05 17:07             ` Martin Wilck
@ 2018-02-06 11:19               ` Julian Andres Klode
  2018-02-06 12:53                 ` Martin Wilck
  0 siblings, 1 reply; 10+ messages in thread
From: Julian Andres Klode @ 2018-02-06 11:19 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel

On Mon, Feb 05, 2018 at 06:07:13PM +0100, Martin Wilck wrote:
> On Mon, 2018-02-05 at 16:46 +0100, Julian Andres Klode wrote:
> > On Mon, Feb 05, 2018 at 04:12:00PM +0100, Martin Wilck wrote:
> > > 
> > > Can we agree on the following:
> > > 
> > >  1 if realpath (filename) results in error, abort
> > 
> > OK
> > 
> > 
> > >  2 if realpath(lo_name) results in ENODEV and filename matches
> > > lo_name,
> > > remove loop device
> > >  3 if realpath(lo_name) results in another error code, skip it
> > >  4 remove if realpath(filename) matches realpath(lo_name)
> > 
> > 
> > This seems like a lot of ifs. It might be easier to just path if
> > realpath(path) fails (as realpath(1) does), something like:
> > 
> > 		
> > 		char *loopname = loopinfo.lo_name;
> > 		if (realpath(loopinfo.lo_name, rloopfilename) != NULL)
> > 			loopname = rloopfilename;
> > 
> > 		if (0 == strcmp(filename, loopinfo.lo_name) ||my
> 		    0 == strcmp(rfilename, loopname))) {
> > 			found = realpath(path, NULL);
> > 			break;
> > 		}
> > 
> > 
> > That should solve all problems and produce useful results with not
> > a lot of logic.
> 
> I've reproduced your issue. I can see that the current behavior is
> wrong. 
> 
> This may be paranoid, but I really want to avoid false positives -
> kpartx removing mappings it isn't supposed to remove. Therefore I'd
> like to avoid compare by "filename" and "loopname". I think it's
> possible.
> 
> IMO it would be better to have kpartx use the realpath while *creating*
> the partition mapping already:
> 
> --- a/kpartx/kpartx.c
> +++ b/kpartx/kpartx.c
> @@ -341,7 +341,7 @@ main(int argc, char **argv){
>                 if (!loopdev) {
>                         loopdev = find_unused_loop_device();
>  
> -                       if (set_loop(loopdev, device, 0, &ro)) {
> +                       if (set_loop(loopdev, rpath, 0, &ro)) {
>                                 fprintf(stderr, "can't set up loop\n");
>                                 exit (1);
>                         }
> 
> 
> That would make sure that kpartx can delete loop devices created by
> itself, which is what we want. IMO it's sufficient to solve your issue.

I was about to suggest that, but did not do it, as it's kind of weird. You
add /a/b/c.img (pointing to /x/y/z.img) and losetup then shows you /x/y/z.img
- I fear this might break some stuff that checks whether the binding was
actually created (or checks which loop device it was created at).
-- 
debian developer - deb.li/jak | jak-linux.org - free software dev
ubuntu core developer                              i speak de, en

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] kpartx: Improve finding loopback device by file
  2018-02-06 11:19               ` Julian Andres Klode
@ 2018-02-06 12:53                 ` Martin Wilck
  0 siblings, 0 replies; 10+ messages in thread
From: Martin Wilck @ 2018-02-06 12:53 UTC (permalink / raw)
  To: Julian Andres Klode; +Cc: dm-devel

On Tue, 2018-02-06 at 12:19 +0100, Julian Andres Klode wrote:
> On Mon, Feb 05, 2018 at 06:07:13PM +0100, Martin Wilck wrote:
> > On Mon, 2018-02-05 at 16:46 +0100, Julian Andres Klode wrote:
> > > On Mon, Feb 05, 2018 at 04:12:00PM +0100, Martin Wilck wrote:
> > > > 
> > > > Can we agree on the following:
> > > > 
> > > >  1 if realpath (filename) results in error, abort
> > > 
> > > OK
> > > 
> > > 
> > > >  2 if realpath(lo_name) results in ENODEV and filename matches
> > > > lo_name,
> > > > remove loop device
> > > >  3 if realpath(lo_name) results in another error code, skip it
> > > >  4 remove if realpath(filename) matches realpath(lo_name)
> > > 
> > > 
> > > This seems like a lot of ifs. It might be easier to just path if
> > > realpath(path) fails (as realpath(1) does), something like:
> > > 
> > > 		
> > > 		char *loopname = loopinfo.lo_name;
> > > 		if (realpath(loopinfo.lo_name, rloopfilename) != NULL)
> > > 			loopname = rloopfilename;
> > > 
> > > 		if (0 == strcmp(filename, loopinfo.lo_name) ||my
> > 
> > 		    0 == strcmp(rfilename, loopname))) {
> > > 			found = realpath(path, NULL);
> > > 			break;
> > > 		}
> > > 
> > > 
> > > That should solve all problems and produce useful results with
> > > not
> > > a lot of logic.
> > 
> > I've reproduced your issue. I can see that the current behavior is
> > wrong. 
> > 
> > This may be paranoid, but I really want to avoid false positives -
> > kpartx removing mappings it isn't supposed to remove. Therefore I'd
> > like to avoid compare by "filename" and "loopname". I think it's
> > possible.
> > 
> > IMO it would be better to have kpartx use the realpath while
> > *creating*
> > the partition mapping already:
> > 
> > --- a/kpartx/kpartx.c
> > +++ b/kpartx/kpartx.c
> > @@ -341,7 +341,7 @@ main(int argc, char **argv){
> >                 if (!loopdev) {
> >                         loopdev = find_unused_loop_device();
> >  
> > -                       if (set_loop(loopdev, device, 0, &ro)) {
> > +                       if (set_loop(loopdev, rpath, 0, &ro)) {
> >                                 fprintf(stderr, "can't set up
> > loop\n");
> >                                 exit (1);
> >                         }
> > 
> > 
> > That would make sure that kpartx can delete loop devices created by
> > itself, which is what we want. IMO it's sufficient to solve your
> > issue.
> 
> I was about to suggest that, but did not do it, as it's kind of
> weird. You
> add /a/b/c.img (pointing to /x/y/z.img) and losetup then shows you
> /x/y/z.img
> - I fear this might break some stuff that checks whether the binding
> was
> actually created (or checks which loop device it was created at).

IMO this is exactly the right thing to do. In order to identify loop
mappings, you shouldn't rely on something as volatile as arbitrary
symlinks. I'm aware that the "real path" isn't carved in stone either, 
but at least it uniquely identifies a file at a given point in time.
Internally, the loop driver refers to the inode anyway.

The scripts you mention, if they actually exist, would benefit if they
were fixed to work with real paths, too.

Regards
Martin

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2018-02-06 12:53 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-02-05  8:58 [PATCH] kpartx: Improve finding loopback device by file Julian Andres Klode
2018-02-05 10:32 ` Martin Wilck
2018-02-05 10:45   ` Julian Andres Klode
2018-02-05 13:53     ` Martin Wilck
2018-02-05 14:41       ` Julian Andres Klode
2018-02-05 15:12         ` Martin Wilck
2018-02-05 15:46           ` Julian Andres Klode
2018-02-05 17:07             ` Martin Wilck
2018-02-06 11:19               ` Julian Andres Klode
2018-02-06 12:53                 ` Martin Wilck

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.