linux-api.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 260/266] loop: add ioctl to resize a loop device
@ 2009-01-06 22:43 akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b
       [not found] ` <200901062243.n06Mh7HR004493-AB4EexQrvXRQetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b @ 2009-01-06 22:43 UTC (permalink / raw)
  To: torvalds-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b
  Cc: akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b,
	hooanon05-/E1597aS9LR3+QwDJ9on6Q,
	akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w, hch-jcswGhMUV9g,
	jens.axboe-QHcLZuEGTsvQT0dZR+AlfA, kzak-H+wXaHxf7aLQT0dZR+AlfA,
	linux-api-u79uwXL29TY76Z2rM5mHXA, tomas-VOkecuvH9Oc,
	util-linux-ng-u79uwXL29TY76Z2rM5mHXA,
	viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn

From: J. R. Okajima <hooanon05-/E1597aS9LR3+QwDJ9on6Q@public.gmane.org>

Add the ability to 'resize' the loop device on the fly.

One practical application is a loop file with XFS filesystem, already
mounted: You can easily enlarge the file (append some bytes) and then call
ioctl(fd, LOOP_SET_CAPACITY, new); The loop driver will learn about the
new size and you can use xfs_growfs later on, which will allow you to use
full capacity of the loop file without the need to unmount.

Test app:

----------------------------------------------------------------------
/*
 * Copyright (C) 2005-2008 Junjiro Okajima
 *
 * This program, aufs is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

/*
 * $Id: logrow.c,v 1.1 2008/11/17 01:59:40 sfjro Exp $
 */

#include <linux/fs.h>
#include <linux/loop.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define _GNU_SOURCE
#include <getopt.h>

char *me;

void usage(FILE *f)
{
	fprintf(f, "%s [options] loop_dev [backend_file]\n"
		"-s, --set new_size_in_bytes\n"
		"\twhen backend_file is given, "
		"it will be expanded too while keeping the original contents\n",
		me);
}

struct option opts[] = {
	{
		.name		= "set",
		.has_arg	= 1,
		.flag		= NULL,
		.val		= 's'
	},
	{
		.name		= "help",
		.has_arg	= 0,
		.flag		= NULL,
		.val		= 'h'
	}
};

void err_size(char *name, __u64 old)
{
	fprintf(stderr, "size must be larger than current %s (%llu)\n",
		name, old);
}

int main(int argc, char *argv[])
{
	int fd, err, c, i, bfd;
	ssize_t ssz;
	size_t sz;
	__u64 old, new, append;
	char a[BUFSIZ];
	struct stat st;
	FILE *out;
	char *backend, *dev;

	err = EINVAL;
	out = stderr;
	me = argv[0];
	new = 0;
	while ((c = getopt_long(argc, argv, "s:h", opts, &i)) != -1) {
		switch (c) {
		case 's':
			errno = 0;
			new = strtoull(optarg, NULL, 0);
			if (errno) {
				err = errno;
				perror(argv[i]);
				goto out;
			}
			break;

		case 'h':
			err = 0;
			out = stdout;
			goto err;

		default:
			perror(argv[i]);
			goto err;
		}
	}

	if (optind < argc)
		dev = argv[optind++];
	else
		goto err;

	fd = open(dev, O_RDONLY);
	if (fd < 0) {
		err = errno;
		perror(dev);
		goto out;
	}

	err = ioctl(fd, BLKGETSIZE64, &old);
	if (err) {
		err = errno;
		perror("ioctl BLKGETSIZE64");
		goto out;
	}

	if (!new) {
		printf("%llu\n", old);
		goto out;
	}

	if (new < old) {
		err = EINVAL;
		err_size(dev, old);
		goto out;
	}

	if (optind < argc) {
		backend = argv[optind++];
		bfd = open(backend, O_WRONLY|O_APPEND);
		if (bfd < 0) {
			err = errno;
			perror(backend);
			goto out;
		}
		err = fstat(bfd, &st);
		if (err) {
			err = errno;
			perror(backend);
			goto out;
		}
		if (new < st.st_size) {
			err = EINVAL;
			err_size(backend, st.st_size);
			goto out;
		}
		append = new - st.st_size;
		sz = sizeof(a);
		while (append > 0) {
			if (append < sz)
				sz = append;
			ssz = write(bfd, a, sz);
			if (ssz != sz) {
				err = errno;
				perror(backend);
				goto out;
			}
			append -= sz;
		}
		err = fsync(bfd);
		if (err) {
			err = errno;
			perror(backend);
			goto out;
		}
	}

	err = ioctl(fd, LOOP_SET_CAPACITY, new);
	if (err) {
		err = errno;
		perror("ioctl LOOP_SET_CAPACITY");
	}
	goto out;

 err:
	usage(out);
 out:
	return err;
}

Signed-off-by: J. R. Okajima <hooanon05-/E1597aS9LR3+QwDJ9on6Q@public.gmane.org>
Signed-off-by: Tomas Matejicek <tomas-VOkecuvH9Oc@public.gmane.org>
Cc: <util-linux-ng-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Cc: Karel Zak <kzak-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: Jens Axboe <jens.axboe-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
Cc: Al Viro <viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn@public.gmane.org>
Cc: Christoph Hellwig <hch-jcswGhMUV9g@public.gmane.org>
Cc: Akinobu Mita <akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: <linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Signed-off-by: Andrew Morton <akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
---

 drivers/block/loop.c |   26 ++++++++++++++++++++++++++
 include/linux/loop.h |    1 +
 2 files changed, 27 insertions(+)

diff -puN drivers/block/loop.c~loop-add-ioctl-to-resize-a-loop-device drivers/block/loop.c
--- a/drivers/block/loop.c~loop-add-ioctl-to-resize-a-loop-device
+++ a/drivers/block/loop.c
@@ -1158,6 +1158,28 @@ loop_get_status64(struct loop_device *lo
 	return err;
 }
 
+static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
+{
+	int err;
+	sector_t sec;
+	loff_t sz;
+
+	err = -ENXIO;
+	if (unlikely(lo->lo_state != Lo_bound))
+		goto out;
+	err = figure_loop_size(lo);
+	if (unlikely(err))
+		goto out;
+	sec = get_capacity(lo->lo_disk);
+	sz = sec << 9;
+	mutex_lock(&bdev->bd_mutex);
+	bd_set_size(bdev, sz);
+	mutex_unlock(&bdev->bd_mutex);
+
+ out:
+	return err;
+}
+
 static int lo_ioctl(struct block_device *bdev, fmode_t mode,
 	unsigned int cmd, unsigned long arg)
 {
@@ -1187,6 +1209,9 @@ static int lo_ioctl(struct block_device 
 	case LOOP_GET_STATUS64:
 		err = loop_get_status64(lo, (struct loop_info64 __user *) arg);
 		break;
+	case LOOP_SET_CAPACITY:
+		err = loop_set_capacity(lo, bdev);
+		break;
 	default:
 		err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
 	}
@@ -1332,6 +1357,7 @@ static int lo_compat_ioctl(struct block_
 			lo, (struct compat_loop_info __user *) arg);
 		mutex_unlock(&lo->lo_ctl_mutex);
 		break;
+	case LOOP_SET_CAPACITY:
 	case LOOP_CLR_FD:
 	case LOOP_GET_STATUS64:
 	case LOOP_SET_STATUS64:
diff -puN include/linux/loop.h~loop-add-ioctl-to-resize-a-loop-device include/linux/loop.h
--- a/include/linux/loop.h~loop-add-ioctl-to-resize-a-loop-device
+++ a/include/linux/loop.h
@@ -160,5 +160,6 @@ int loop_unregister_transfer(int number)
 #define LOOP_SET_STATUS64	0x4C04
 #define LOOP_GET_STATUS64	0x4C05
 #define LOOP_CHANGE_FD		0x4C06
+#define LOOP_SET_CAPACITY	0x4C07
 
 #endif
_
--
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [patch 260/266] loop: add ioctl to resize a loop device
       [not found] ` <200901062243.n06Mh7HR004493-AB4EexQrvXRQetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org>
@ 2009-01-06 23:58   ` Linus Torvalds
       [not found]     ` <alpine.LFD.2.00.0901061554140.8799-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Linus Torvalds @ 2009-01-06 23:58 UTC (permalink / raw)
  To: Andrew Morton
  Cc: hooanon05-/E1597aS9LR3+QwDJ9on6Q,
	akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w, hch-jcswGhMUV9g, Jens Axboe,
	kzak-H+wXaHxf7aLQT0dZR+AlfA, linux-api-u79uwXL29TY76Z2rM5mHXA,
	tomas-VOkecuvH9Oc, util-linux-ng-u79uwXL29TY76Z2rM5mHXA, Al Viro



On Tue, 6 Jan 2009, akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org wrote:
> 
> Add the ability to 'resize' the loop device on the fly.

Hell no.

There is apparently no security checking here. No way can we allow this 
for any random user that can open the loopback device read-only and then 
just change its size.

It needs to use all the same security checks as "loop_set_status()" and 
friends, afaik.

Maybe I'm missing something, but I'm not going to apply it without 
somebody explaining why this isn't a total piece of shit.

I also don't want to have copyright licenses in changelogs. If it's a test 
app, anybody should be able to use it, no restrictions.

		Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [patch 260/266] loop: add ioctl to resize a loop device
       [not found]     ` <alpine.LFD.2.00.0901061554140.8799-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
@ 2009-01-07  0:04       ` Andrew Morton
       [not found]         ` <20090106160414.b165d452.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Andrew Morton @ 2009-01-07  0:04 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: hooanon05-/E1597aS9LR3+QwDJ9on6Q,
	akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w, hch-jcswGhMUV9g,
	jens.axboe-QHcLZuEGTsvQT0dZR+AlfA, kzak-H+wXaHxf7aLQT0dZR+AlfA,
	linux-api-u79uwXL29TY76Z2rM5mHXA, tomas-VOkecuvH9Oc,
	util-linux-ng-u79uwXL29TY76Z2rM5mHXA,
	viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn

On Tue, 6 Jan 2009 15:58:19 -0800 (PST)
Linus Torvalds <torvalds-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org> wrote:

> 
> 
> On Tue, 6 Jan 2009, akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org wrote:
> > 
> > Add the ability to 'resize' the loop device on the fly.
> 
> Hell no.
> 
> There is apparently no security checking here. No way can we allow this 
> for any random user that can open the loopback device read-only and then 
> just change its size.
> 
> It needs to use all the same security checks as "loop_set_status()" and 
> friends, afaik.
> 

oops, didn't think of that.

There's a bug, too:

> +static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
> +{
> +	int err;
> +	sector_t sec;
> +	loff_t sz;
> +
> +	err = -ENXIO;
> +	if (unlikely(lo->lo_state != Lo_bound))
> +		goto out;
> +	err = figure_loop_size(lo);
> +	if (unlikely(err))
> +		goto out;
> +	sec = get_capacity(lo->lo_disk);
> +	sz = sec << 9;

This can overflow if sector_t is 32-bit.  Fix with:

	sz = (loff_t)sec << 9;

> +	mutex_lock(&bdev->bd_mutex);
> +	bd_set_size(bdev, sz);
> +	mutex_unlock(&bdev->bd_mutex);
> +
> + out:
> +	return err;
> +}

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [patch 260/266] loop: add ioctl to resize a loop device
       [not found]         ` <20090106160414.b165d452.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
@ 2009-01-07  6:13           ` hooanon05-/E1597aS9LR3+QwDJ9on6Q
  2009-01-07  6:14           ` [PATCH 1/2] security check for LOOP_SET_CAPACITY J. R. Okajima
  2009-01-07  6:14           ` [PATCH 2/2] LOOP_SET_CAPACITY sector_t may be narrow for bit-shfit J. R. Okajima
  2 siblings, 0 replies; 6+ messages in thread
From: hooanon05-/E1597aS9LR3+QwDJ9on6Q @ 2009-01-07  6:13 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Linus Torvalds, akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w,
	hch-jcswGhMUV9g, jens.axboe-QHcLZuEGTsvQT0dZR+AlfA,
	kzak-H+wXaHxf7aLQT0dZR+AlfA, linux-api-u79uwXL29TY76Z2rM5mHXA,
	tomas-VOkecuvH9Oc, util-linux-ng-u79uwXL29TY76Z2rM5mHXA,
	viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn


Andrew Morton:
> > There is apparently no security checking here. No way can we allow this 
> > for any random user that can open the loopback device read-only and then 
> > just change its size.
> > 
> > It needs to use all the same security checks as "loop_set_status()" and 
> > friends, afaik.
> > 
> 
> oops, didn't think of that.

I will add some security checks and send a new patch. But it may not be
purely same to loop_set_status() since the checks for encrypt_key or
something is unnecessary.


> This can overflow if sector_t is 32-bit.  Fix with:
> 
> 	sz = (loff_t)sec << 9;

I will fix and send it too.


J. R. Okajima
--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 1/2] security check for LOOP_SET_CAPACITY
       [not found]         ` <20090106160414.b165d452.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
  2009-01-07  6:13           ` hooanon05-/E1597aS9LR3+QwDJ9on6Q
@ 2009-01-07  6:14           ` J. R. Okajima
  2009-01-07  6:14           ` [PATCH 2/2] LOOP_SET_CAPACITY sector_t may be narrow for bit-shfit J. R. Okajima
  2 siblings, 0 replies; 6+ messages in thread
From: J. R. Okajima @ 2009-01-07  6:14 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Linus Torvalds, akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w,
	hch-jcswGhMUV9g, jens.axboe-QHcLZuEGTsvQT0dZR+AlfA,
	kzak-H+wXaHxf7aLQT0dZR+AlfA, linux-api-u79uwXL29TY76Z2rM5mHXA,
	tomas-VOkecuvH9Oc, util-linux-ng-u79uwXL29TY76Z2rM5mHXA,
	viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn

Respoding the comment from Linus Torvalds, LOOP_SET_CAPACITY now
requires the device file to be opened for write or CAP_SYS_ADMIN.

Signed-off-by: J. R. Okajima <hooanon05-/E1597aS9LR3+QwDJ9on6Q@public.gmane.org>
---
 drivers/block/loop.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 80e523e..fcd28a7 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1210,7 +1210,9 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
 		err = loop_get_status64(lo, (struct loop_info64 __user *) arg);
 		break;
 	case LOOP_SET_CAPACITY:
-		err = loop_set_capacity(lo, bdev);
+		err = -EPERM;
+		if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
+			err = loop_set_capacity(lo, bdev);
 		break;
 	default:
 		err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
-- 
1.5.5.4.dirty

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 2/2] LOOP_SET_CAPACITY sector_t may be narrow for bit-shfit
       [not found]         ` <20090106160414.b165d452.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
  2009-01-07  6:13           ` hooanon05-/E1597aS9LR3+QwDJ9on6Q
  2009-01-07  6:14           ` [PATCH 1/2] security check for LOOP_SET_CAPACITY J. R. Okajima
@ 2009-01-07  6:14           ` J. R. Okajima
  2 siblings, 0 replies; 6+ messages in thread
From: J. R. Okajima @ 2009-01-07  6:14 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Linus Torvalds, akinobu.mita-Re5JQEeQqe8AvxtiuMwx3w,
	hch-jcswGhMUV9g, jens.axboe-QHcLZuEGTsvQT0dZR+AlfA,
	kzak-H+wXaHxf7aLQT0dZR+AlfA, linux-api-u79uwXL29TY76Z2rM5mHXA,
	tomas-VOkecuvH9Oc, util-linux-ng-u79uwXL29TY76Z2rM5mHXA,
	viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn

Fixing the bug pointed out by Andrew Morton, shift loff_t instead of
sector_t since sector_t may be 32-bit.

Signed-off-by: J. R. Okajima <hooanon05-/E1597aS9LR3+QwDJ9on6Q@public.gmane.org>
---
 drivers/block/loop.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index fcd28a7..eaed1fa 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1171,7 +1171,9 @@ static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
 	if (unlikely(err))
 		goto out;
 	sec = get_capacity(lo->lo_disk);
-	sz = sec << 9;
+	/* the width of sector_t may be narrow for bit-shift */
+	sz = sec;
+	sz <<= 9;
 	mutex_lock(&bdev->bd_mutex);
 	bd_set_size(bdev, sz);
 	mutex_unlock(&bdev->bd_mutex);
-- 
1.5.5.4.dirty

--
To unsubscribe from this list: send the line "unsubscribe linux-api" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

end of thread, other threads:[~2009-01-07  6:14 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-01-06 22:43 [patch 260/266] loop: add ioctl to resize a loop device akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b
     [not found] ` <200901062243.n06Mh7HR004493-AB4EexQrvXRQetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org>
2009-01-06 23:58   ` Linus Torvalds
     [not found]     ` <alpine.LFD.2.00.0901061554140.8799-bi+AKbBUZKY6gyzm1THtWbp2dZbC/Bob@public.gmane.org>
2009-01-07  0:04       ` Andrew Morton
     [not found]         ` <20090106160414.b165d452.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
2009-01-07  6:13           ` hooanon05-/E1597aS9LR3+QwDJ9on6Q
2009-01-07  6:14           ` [PATCH 1/2] security check for LOOP_SET_CAPACITY J. R. Okajima
2009-01-07  6:14           ` [PATCH 2/2] LOOP_SET_CAPACITY sector_t may be narrow for bit-shfit J. R. Okajima

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).