Re: [PATCH] loop file resizable

From: hooanon05
Date: Sun Nov 23 2008 - 21:08:40 EST



Karel Zak:
> On Fri, Nov 21, 2008 at 09:23:48PM +0900, hooanon05@xxxxxxxxxxx wrote:
:::
> > If you tell me the URL of the base version of losetup, I will make a
> > patch.
>
> git://git.kernel.org/pub/scm/utils/util-linux-ng/util-linux-ng.git

Thanx.


> Note, that I'll commit the patch when the kernel side will be in
> Linus's tree.

Sure.
Here is the patch.

J. R. Okajima

----------------------------------------------------------------------

Subject: [PATCH 1/1] grow the size of loopback device and its backend file

introduce a new option, "-g | --grow <new_size> <loopdev> [file]" which
requres the kernel patch titled
"Subject: + loop-add-ioctl-to-resize-a-loop-device.patch added to -mm tree"
on 21 Nov 2008.

Signed-off-by: J. R. Okajima <hooanon05@xxxxxxxxxxx>
---
mount/lomount.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
mount/loop.h | 2 +
2 files changed, 152 insertions(+), 4 deletions(-)

diff --git a/mount/lomount.c b/mount/lomount.c
index 5675eac..c705b43 100644
--- a/mount/lomount.c
+++ b/mount/lomount.c
@@ -24,6 +24,7 @@
#include "xmalloc.h"
#include "realpath.h"
#include "pathnames.h"
+#include "blkdev.h"

#define SIZE(a) (sizeof(a)/sizeof(a[0]))

@@ -827,6 +828,136 @@ del_loop (const char *device) {
return 0;
}

+void grow_err(const char *name, unsigned long long old, unsigned long long new)
+{
+ fprintf(stderr, "size (%llu) must be larger than current %s (%llu)\n",
+ new, name, old);
+}
+
+int grow_file(const char *file, unsigned long long new)
+{
+ int err, fd;
+ unsigned long long append;
+ size_t sz;
+ ssize_t ssz;
+ const size_t one_g = 1 << 30;
+ struct stat st;
+ char *p;
+
+ err = -1;
+ fd = open(file, O_WRONLY | O_APPEND);
+ if (fd < 0)
+ goto out_p;
+
+ err = fstat(fd, &st);
+ if (err)
+ goto out_p;
+
+ err = -1;
+ if (new < st.st_size) {
+ grow_err(file, st.st_size, new);
+ goto out;
+ }
+
+ append = new - st.st_size;
+ sz = append;
+ if (sz > one_g)
+ sz = one_g;
+ while (1) {
+ p = calloc(sz, 1);
+ if (p)
+ break;
+ sz >>= 1;
+ if (!sz) {
+ errno = ENOMEM;
+ goto out_p;
+ }
+ }
+
+ /*
+ * instread of ftrundate(2),
+ * allocate disk blocks to support ENOSPC
+ * on the loopback mounted filesystem
+ */
+ err = 0;
+ while (append > 0) {
+ if (append < sz)
+ sz = append;
+ ssz = write(fd, p, sz);
+ if (ssz == -1) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ err = errno;
+ break;
+ }
+ append -= ssz;
+ }
+ free(p);
+ if (err) {
+ errno = err;
+ goto out_p;
+ }
+
+ err = fsync(fd);
+ if (err)
+ goto out_p;
+ err = close(fd);
+ if (!err)
+ goto out; /* success */
+
+ out_p:
+ perror(file);
+ out:
+ return err;
+}
+
+int grow_capacity(unsigned long long new, const char *device,
+ const char *file)
+{
+ int err, fd;
+ unsigned long long old;
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0) {
+ err = errno;
+ perror(device);
+ 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;
+ grow_err(device, old, new);
+ goto out;
+ }
+
+ if (file) {
+ err = grow_file(file, new);
+ if (err)
+ goto out;
+ }
+
+ err = ioctl(fd, LOOP_SET_CAPACITY, new);
+ if (err) {
+ err = errno;
+ perror("ioctl LOOP_SET_CAPACITY");
+ }
+
+ out:
+ return err;
+}
+
#else /* no LOOP_SET_FD defined */
static void
mutter(void) {
@@ -872,6 +1003,7 @@ usage(void) {
" %1$s -d | --detach <loopdev> delete\n"
" %1$s -f | --find find unused\n"
" %1$s -j | --associated <file> [-o <num>] list all associated with <file>\n"
+ " %1$s -g | --grow <new_size> <loopdev> [file] grow capacity\n"
" %1$s [ options ] {-f|--find|loopdev} <file> setup\n"),
progname);

@@ -889,13 +1021,14 @@ usage(void) {

int
main(int argc, char **argv) {
- char *p, *offset, *sizelimit, *encryption, *passfd, *device, *file, *assoc;
+ char *p, *offset, *sizelimit, *encryption, *passfd, *device, *file,
+ *assoc, *grow;
int delete, find, c, all;
int res = 0;
int showdev = 0;
int ro = 0;
int pfd = -1;
- unsigned long long off, slimit;
+ unsigned long long off, slimit, new_size;
struct option longopts[] = {
{ "all", 0, 0, 'a' },
{ "detach", 0, 0, 'd' },
@@ -903,6 +1036,7 @@ main(int argc, char **argv) {
{ "find", 0, 0, 'f' },
{ "help", 0, 0, 'h' },
{ "associated", 1, 0, 'j' },
+ { "grow", 1, 0, 'g' },
{ "offset", 1, 0, 'o' },
{ "sizelimit", 1, 0, 128 },
{ "pass-fd", 1, 0, 'p' },
@@ -919,13 +1053,13 @@ main(int argc, char **argv) {
delete = find = all = 0;
off = 0;
slimit = 0;
- assoc = offset = sizelimit = encryption = passfd = NULL;
+ assoc = offset = sizelimit = encryption = passfd = grow = NULL;

progname = argv[0];
if ((p = strrchr(progname, '/')) != NULL)
progname = p+1;

- while ((c = getopt_long(argc, argv, "ade:E:fhj:o:p:rsv",
+ while ((c = getopt_long(argc, argv, "ade:E:fg:hj:o:p:rsv",
longopts, NULL)) != -1) {
switch (c) {
case 'a':
@@ -944,6 +1078,9 @@ main(int argc, char **argv) {
case 'f':
find = 1;
break;
+ case 'g':
+ grow = optarg;
+ break;
case 'j':
assoc = optarg;
break;
@@ -984,6 +1121,10 @@ main(int argc, char **argv) {
} else if (assoc) {
if (encryption || showdev || passfd || ro)
usage();
+ } else if (grow) {
+ if (all || assoc || find
+ || (argc != 4 && argc != 5))
+ usage();
} else {
if (argc < optind+1 || argc > optind+2)
usage();
@@ -995,6 +1136,9 @@ main(int argc, char **argv) {
if (sizelimit && sscanf(sizelimit, "%llu", &slimit) != 1)
usage();

+ if (grow && sscanf(grow, "%llu", &new_size) != 1)
+ usage();
+
if (all)
return show_used_loop_devices();
else if (assoc)
@@ -1020,6 +1164,8 @@ main(int argc, char **argv) {

if (delete)
res = del_loop(device);
+ else if (grow)
+ res = grow_capacity(new_size, device, file);
else if (file == NULL)
res = show_loop(device);
else {
diff --git a/mount/loop.h b/mount/loop.h
index 6068852..c6d244e 100644
--- a/mount/loop.h
+++ b/mount/loop.h
@@ -22,6 +22,8 @@
#define LOOP_GET_STATUS 0x4C03
#define LOOP_SET_STATUS64 0x4C04
#define LOOP_GET_STATUS64 0x4C05
+/* #define LOOP_CHANGE_FD 0x4C06 */
+#define LOOP_SET_CAPACITY 0x4C07

/* Flags for loop_into{64,}->lo_flags */
enum {
--
1.5.5.4.dirty

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/