2008-03-18 12:16:41

by Laurent Vivier

[permalink] [raw]
Subject: [PATCH][RESEND][v3] Modify loop device to be able to manage partitions of the disk image

v3 is an updated version of v2, replacing a "%d" by a "%lu".

This patch allows to use loop device with partitionned disk image.

Original behavior of loop is not modified.

A new parameter is introduced to define how many partition we want to be
able to manage per loop device. This parameter is "loop_max_part".

For instance, to manage 63 partitions / loop device, we will do:
# modprobe loop loop_max_part=63
# ls -l /dev/loop?
brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7

And to attach a raw partitionned disk image, the original losetup is used:

# losetup -f etch.img
EXT3 FS on loop0p1, internal journal
EXT3-fs: mounted filesystem with ordered data mode.
loop: module loaded
loop0: p1 p2 < p5 >
# ls -l /dev/loop?*
brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
brw-rw---- 1 root disk 7, 1 2008-03-05 14:57 /dev/loop0p1
brw-rw---- 1 root disk 7, 2 2008-03-05 14:57 /dev/loop0p2
brw-rw---- 1 root disk 7, 5 2008-03-05 14:57 /dev/loop0p5
brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
# mount /dev/loop0p1 /mnt
kjournald starting. Commit interval 5 seconds
EXT3 FS on loop0p1, internal journal
EXT3-fs: mounted filesystem with ordered data mode.
# ls /mnt
bench cdrom home lib mnt root srv usr
bin dev initrd lost+found opt sbin sys var
boot etc initrd.img media proc selinux tmp vmlinuz
# umount /mnt
# losetup -d /dev/loop0

Of course, the same behavior can be done using kpartx on a loop device,
but modifying loop avoids to stack several layers of block device (loop +
device mapper), this is a very light modification (40% of modifications
are to manage the new parameter).

Signed-off-by: Laurent Vivier <[email protected]>
---
Documentation/kernel-parameters.txt | 4 +++
drivers/block/loop.c | 39 ++++++++++++++++++++++++++++++----
2 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 9a5b665..7f2fd52 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1075,6 +1075,10 @@ and is between 256 and 4096 characters. It is defined in the file
be mounted
Format: <1-256>

+ loop_max_part= [LOOP] Maximum number of partitions per loopback device.
+ Should be greater than 0, the maximum value depends
+ on max_loop.
+
maxcpus= [SMP] Maximum number of processors that an SMP kernel
should make use of. maxcpus=n : n >= 0 limits the
kernel to using 'n' processors. n=0 is a special case,
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 91ebb00..16b2aa6 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -82,6 +82,9 @@
static LIST_HEAD(loop_devices);
static DEFINE_MUTEX(loop_devices_mutex);

+static int loop_max_part;
+static int part_shift;
+
/*
* Transfer functions
*/
@@ -692,6 +695,8 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
goto out_putf;

fput(old_file);
+ if (loop_max_part > 0)
+ ioctl_by_bdev(bdev, BLKRRPART, 0);
return 0;

out_putf:
@@ -819,6 +824,8 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
}
lo->lo_state = Lo_bound;
wake_up_process(lo->lo_thread);
+ if (loop_max_part > 0)
+ ioctl_by_bdev(bdev, BLKRRPART, 0);
return 0;

out_clr:
@@ -1360,6 +1367,8 @@ static struct block_device_operations lo_fops = {
static int max_loop;
module_param(max_loop, int, 0);
MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
+module_param(loop_max_part, int, 0);
+MODULE_PARM_DESC(loop_max_part, "Maximum number of partitions per loop device");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);

@@ -1412,7 +1421,7 @@ static struct loop_device *loop_alloc(int i)
if (!lo->lo_queue)
goto out_free_dev;

- disk = lo->lo_disk = alloc_disk(1);
+ disk = lo->lo_disk = alloc_disk(1 << part_shift);
if (!disk)
goto out_free_queue;

@@ -1422,7 +1431,7 @@ static struct loop_device *loop_alloc(int i)
init_waitqueue_head(&lo->lo_event);
spin_lock_init(&lo->lo_lock);
disk->major = LOOP_MAJOR;
- disk->first_minor = i;
+ disk->first_minor = i << part_shift;
disk->fops = &lo_fops;
disk->private_data = lo;
disk->queue = lo->lo_queue;
@@ -1502,7 +1511,12 @@ static int __init loop_init(void)
* themselves and have kernel automatically instantiate actual
* device on-demand.
*/
- if (max_loop > 1UL << MINORBITS)
+
+ part_shift = 0;
+ if (loop_max_part > 0)
+ part_shift = fls(loop_max_part);
+
+ if (max_loop > 1UL << (MINORBITS - part_shift))
return -EINVAL;

if (max_loop) {
@@ -1510,7 +1524,7 @@ static int __init loop_init(void)
range = max_loop;
} else {
nr = 8;
- range = 1UL << MINORBITS;
+ range = 1UL << (MINORBITS - part_shift);
}

if (register_blkdev(LOOP_MAJOR, "loop"))
@@ -1549,7 +1563,7 @@ static void __exit loop_exit(void)
unsigned long range;
struct loop_device *lo, *next;

- range = max_loop ? max_loop : 1UL << MINORBITS;
+ range = max_loop ? max_loop : 1UL << (MINORBITS - part_shift);

list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
loop_del_one(lo);
@@ -1569,4 +1583,19 @@ static int __init max_loop_setup(char *str)
}

__setup("max_loop=", max_loop_setup);
+
+static int __init max_part_setup(char *str)
+{
+ loop_max_part = simple_strtol(str, NULL, 0);
+ if (loop_max_part > (1UL << (MINORBITS - 1))) {
+ /* we must keep at least one bit for loop device number */
+ printk(KERN_ERR
+ "loop: loop_max_part cannot be greater than %lu\n",
+ 1UL << (MINORBITS - 1));
+ return 0;
+ }
+ return 1;
+}
+
+__setup("loop_max_part=", max_part_setup);
#endif
--
1.5.2.4


2008-03-19 19:33:28

by Laurent Vivier

[permalink] [raw]
Subject: [PATCH][v4] Modify loop device to be able to manage partitions of the disk image

This patch allows to use loop device with partitionned disk image.

Original behavior of loop is not modified.

A new parameter is introduced to define how many partition we want to be
able to manage per loop device. This parameter is "max_part".

For instance, to manage 63 partitions / loop device, we will do:
# modprobe loop max_part=63
# ls -l /dev/loop?*
brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7

And to attach a raw partitionned disk image, the original losetup is used:

# losetup -f etch.img
# ls -l /dev/loop?*
brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
brw-rw---- 1 root disk 7, 1 2008-03-05 14:57 /dev/loop0p1
brw-rw---- 1 root disk 7, 2 2008-03-05 14:57 /dev/loop0p2
brw-rw---- 1 root disk 7, 5 2008-03-05 14:57 /dev/loop0p5
brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
# mount /dev/loop0p1 /mnt
# ls /mnt
bench cdrom home lib mnt root srv usr
bin dev initrd lost+found opt sbin sys var
boot etc initrd.img media proc selinux tmp vmlinuz
# umount /mnt
# losetup -d /dev/loop0

Of course, the same behavior can be done using kpartx on a loop device,
but modifying loop avoids to stack several layers of block device (loop +
device mapper), this is a very light modification (40% of modifications
are to manage the new parameter).

Signed-off-by: Laurent Vivier <[email protected]>
---
drivers/block/loop.c | 26 +++++++++++++++++++++-----
1 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 91ebb00..f7f1635 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -82,6 +82,9 @@
static LIST_HEAD(loop_devices);
static DEFINE_MUTEX(loop_devices_mutex);

+static int max_part;
+static int part_shift;
+
/*
* Transfer functions
*/
@@ -692,6 +695,8 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
goto out_putf;

fput(old_file);
+ if (max_part > 0)
+ ioctl_by_bdev(bdev, BLKRRPART, 0);
return 0;

out_putf:
@@ -819,6 +824,8 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
}
lo->lo_state = Lo_bound;
wake_up_process(lo->lo_thread);
+ if (max_part > 0)
+ ioctl_by_bdev(bdev, BLKRRPART, 0);
return 0;

out_clr:
@@ -919,6 +926,8 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
fput(filp);
/* This is safe: open() is still holding a reference. */
module_put(THIS_MODULE);
+ if (max_part > 0)
+ ioctl_by_bdev(bdev, BLKRRPART, 0);
return 0;
}

@@ -1360,6 +1369,8 @@ static struct block_device_operations lo_fops = {
static int max_loop;
module_param(max_loop, int, 0);
MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
+module_param(max_part, int, 0);
+MODULE_PARM_DESC(max_part, "Maximum number of partitions per loop device");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);

@@ -1412,7 +1423,7 @@ static struct loop_device *loop_alloc(int i)
if (!lo->lo_queue)
goto out_free_dev;

- disk = lo->lo_disk = alloc_disk(1);
+ disk = lo->lo_disk = alloc_disk(1 << part_shift);
if (!disk)
goto out_free_queue;

@@ -1422,7 +1433,7 @@ static struct loop_device *loop_alloc(int i)
init_waitqueue_head(&lo->lo_event);
spin_lock_init(&lo->lo_lock);
disk->major = LOOP_MAJOR;
- disk->first_minor = i;
+ disk->first_minor = i << part_shift;
disk->fops = &lo_fops;
disk->private_data = lo;
disk->queue = lo->lo_queue;
@@ -1502,7 +1513,12 @@ static int __init loop_init(void)
* themselves and have kernel automatically instantiate actual
* device on-demand.
*/
- if (max_loop > 1UL << MINORBITS)
+
+ part_shift = 0;
+ if (max_part > 0)
+ part_shift = fls(max_part);
+
+ if (max_loop > 1UL << (MINORBITS - part_shift))
return -EINVAL;

if (max_loop) {
@@ -1510,7 +1526,7 @@ static int __init loop_init(void)
range = max_loop;
} else {
nr = 8;
- range = 1UL << MINORBITS;
+ range = 1UL << (MINORBITS - part_shift);
}

if (register_blkdev(LOOP_MAJOR, "loop"))
@@ -1549,7 +1565,7 @@ static void __exit loop_exit(void)
unsigned long range;
struct loop_device *lo, *next;

- range = max_loop ? max_loop : 1UL << MINORBITS;
+ range = max_loop ? max_loop : 1UL << (MINORBITS - part_shift);

list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
loop_del_one(lo);
--
1.5.2.4

2008-03-19 20:42:55

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH][RESEND][v3] Modify loop device to be able to manage partitions of the disk image

On Tue, 18 Mar 2008 13:19:20 +0100
Laurent Vivier <[email protected]> wrote:

> v3 is an updated version of v2, replacing a "%d" by a "%lu".
>
> This patch allows to use loop device with partitionned disk image.
>
> Original behavior of loop is not modified.
>
> A new parameter is introduced to define how many partition we want to be
> able to manage per loop device. This parameter is "loop_max_part".
>
> For instance, to manage 63 partitions / loop device, we will do:
> # modprobe loop loop_max_part=63
> # ls -l /dev/loop?
> brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
> brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
> brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
> brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
> brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
> brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
> brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
> brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
>
> And to attach a raw partitionned disk image, the original losetup is used:
>
> # losetup -f etch.img
> EXT3 FS on loop0p1, internal journal
> EXT3-fs: mounted filesystem with ordered data mode.
> loop: module loaded
> loop0: p1 p2 < p5 >
> # ls -l /dev/loop?*
> brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
> brw-rw---- 1 root disk 7, 1 2008-03-05 14:57 /dev/loop0p1
> brw-rw---- 1 root disk 7, 2 2008-03-05 14:57 /dev/loop0p2
> brw-rw---- 1 root disk 7, 5 2008-03-05 14:57 /dev/loop0p5
> brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
> brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
> brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
> brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
> brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
> brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
> brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
> # mount /dev/loop0p1 /mnt
> kjournald starting. Commit interval 5 seconds
> EXT3 FS on loop0p1, internal journal
> EXT3-fs: mounted filesystem with ordered data mode.
> # ls /mnt
> bench cdrom home lib mnt root srv usr
> bin dev initrd lost+found opt sbin sys var
> boot etc initrd.img media proc selinux tmp vmlinuz
> # umount /mnt
> # losetup -d /dev/loop0
>
> Of course, the same behavior can be done using kpartx on a loop device,
> but modifying loop avoids to stack several layers of block device (loop +
> device mapper), this is a very light modification (40% of modifications
> are to manage the new parameter).
>
> ...
>
> index 9a5b665..7f2fd52 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -1075,6 +1075,10 @@ and is between 256 and 4096 characters. It is defined in the file
> be mounted
> Format: <1-256>
>
> + loop_max_part= [LOOP] Maximum number of partitions per loopback device.
> + Should be greater than 0, the maximum value depends
> + on max_loop.
> +

This shouldn't be needed.

> @@ -1360,6 +1367,8 @@ static struct block_device_operations lo_fops = {
> static int max_loop;
> module_param(max_loop, int, 0);
> MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
> +module_param(loop_max_part, int, 0);
> +MODULE_PARM_DESC(loop_max_part, "Maximum number of partitions per loop device");

Because this module_param() gives us the loop.loop_max_part=N kernel boot
parameter.

Given which, I think we could rename it to just "max_part":

modprobe loop max_part=4

kernel vmlinuz-... loop.max_part=4

?

> __setup("max_loop=", max_loop_setup);

That could go away in the same way, but we have a back-compat problem.

> +
> +static int __init max_part_setup(char *str)
> +{
> + loop_max_part = simple_strtol(str, NULL, 0);
> + if (loop_max_part > (1UL << (MINORBITS - 1))) {
> + /* we must keep at least one bit for loop device number */
> + printk(KERN_ERR
> + "loop: loop_max_part cannot be greater than %lu\n",
> + 1UL << (MINORBITS - 1));
> + return 0;
> + }
> + return 1;
> +}
> +
> +__setup("loop_max_part=", max_part_setup);

2008-03-19 21:47:41

by Bill Davidsen

[permalink] [raw]
Subject: Re: [PATCH][RESEND][v3] Modify loop device to be able to manage partitions of the disk image

Laurent Vivier wrote:
> v3 is an updated version of v2, replacing a "%d" by a "%lu".
>
> This patch allows to use loop device with partitionned disk image.
>
How does this compare in overhead to using nbd?

> Original behavior of loop is not modified.
>
> A new parameter is introduced to define how many partition we want to be
> able to manage per loop device. This parameter is "loop_max_part".
>
> For instance, to manage 63 partitions / loop device, we will do:
> # modprobe loop loop_max_part=63
> # ls -l /dev/loop?
> brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
> brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
> brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
> brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
> brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
> brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
> brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
> brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
>
> And to attach a raw partitionned disk image, the original losetup is used:
>
> # losetup -f etch.img
> EXT3 FS on loop0p1, internal journal
> EXT3-fs: mounted filesystem with ordered data mode.
> loop: module loaded
> loop0: p1 p2 < p5 >
> # ls -l /dev/loop?*
> brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
> brw-rw---- 1 root disk 7, 1 2008-03-05 14:57 /dev/loop0p1
> brw-rw---- 1 root disk 7, 2 2008-03-05 14:57 /dev/loop0p2
> brw-rw---- 1 root disk 7, 5 2008-03-05 14:57 /dev/loop0p5
> brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
> brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
> brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
> brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
> brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
> brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
> brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
> # mount /dev/loop0p1 /mnt
> kjournald starting. Commit interval 5 seconds
> EXT3 FS on loop0p1, internal journal
> EXT3-fs: mounted filesystem with ordered data mode.
> # ls /mnt
> bench cdrom home lib mnt root srv usr
> bin dev initrd lost+found opt sbin sys var
> boot etc initrd.img media proc selinux tmp vmlinuz
> # umount /mnt
> # losetup -d /dev/loop0
>
> Of course, the same behavior can be done using kpartx on a loop device,
> but modifying loop avoids to stack several layers of block device (loop +
> device mapper), this is a very light modification (40% of modifications
> are to manage the new parameter).
>
> Signed-off-by: Laurent Vivier <[email protected]>
> ---
> Documentation/kernel-parameters.txt | 4 +++
> drivers/block/loop.c | 39 ++++++++++++++++++++++++++++++----
> 2 files changed, 38 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> index 9a5b665..7f2fd52 100644
> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -1075,6 +1075,10 @@ and is between 256 and 4096 characters. It is defined in the file
> be mounted
> Format: <1-256>
>
> + loop_max_part= [LOOP] Maximum number of partitions per loopback device.
> + Should be greater than 0, the maximum value depends
> + on max_loop.
> +
> maxcpus= [SMP] Maximum number of processors that an SMP kernel
> should make use of. maxcpus=n : n >= 0 limits the
> kernel to using 'n' processors. n=0 is a special case,
> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> index 91ebb00..16b2aa6 100644
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -82,6 +82,9 @@
> static LIST_HEAD(loop_devices);
> static DEFINE_MUTEX(loop_devices_mutex);
>
> +static int loop_max_part;
> +static int part_shift;
> +
> /*
> * Transfer functions
> */
> @@ -692,6 +695,8 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
> goto out_putf;
>
> fput(old_file);
> + if (loop_max_part > 0)
> + ioctl_by_bdev(bdev, BLKRRPART, 0);
> return 0;
>
> out_putf:
> @@ -819,6 +824,8 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
> }
> lo->lo_state = Lo_bound;
> wake_up_process(lo->lo_thread);
> + if (loop_max_part > 0)
> + ioctl_by_bdev(bdev, BLKRRPART, 0);
> return 0;
>
> out_clr:
> @@ -1360,6 +1367,8 @@ static struct block_device_operations lo_fops = {
> static int max_loop;
> module_param(max_loop, int, 0);
> MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
> +module_param(loop_max_part, int, 0);
> +MODULE_PARM_DESC(loop_max_part, "Maximum number of partitions per loop device");
> MODULE_LICENSE("GPL");
> MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
>
> @@ -1412,7 +1421,7 @@ static struct loop_device *loop_alloc(int i)
> if (!lo->lo_queue)
> goto out_free_dev;
>
> - disk = lo->lo_disk = alloc_disk(1);
> + disk = lo->lo_disk = alloc_disk(1 << part_shift);
> if (!disk)
> goto out_free_queue;
>
> @@ -1422,7 +1431,7 @@ static struct loop_device *loop_alloc(int i)
> init_waitqueue_head(&lo->lo_event);
> spin_lock_init(&lo->lo_lock);
> disk->major = LOOP_MAJOR;
> - disk->first_minor = i;
> + disk->first_minor = i << part_shift;
> disk->fops = &lo_fops;
> disk->private_data = lo;
> disk->queue = lo->lo_queue;
> @@ -1502,7 +1511,12 @@ static int __init loop_init(void)
> * themselves and have kernel automatically instantiate actual
> * device on-demand.
> */
> - if (max_loop > 1UL << MINORBITS)
> +
> + part_shift = 0;
> + if (loop_max_part > 0)
> + part_shift = fls(loop_max_part);
> +
> + if (max_loop > 1UL << (MINORBITS - part_shift))
> return -EINVAL;
>
> if (max_loop) {
> @@ -1510,7 +1524,7 @@ static int __init loop_init(void)
> range = max_loop;
> } else {
> nr = 8;
> - range = 1UL << MINORBITS;
> + range = 1UL << (MINORBITS - part_shift);
> }
>
> if (register_blkdev(LOOP_MAJOR, "loop"))
> @@ -1549,7 +1563,7 @@ static void __exit loop_exit(void)
> unsigned long range;
> struct loop_device *lo, *next;
>
> - range = max_loop ? max_loop : 1UL << MINORBITS;
> + range = max_loop ? max_loop : 1UL << (MINORBITS - part_shift);
>
> list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
> loop_del_one(lo);
> @@ -1569,4 +1583,19 @@ static int __init max_loop_setup(char *str)
> }
>
> __setup("max_loop=", max_loop_setup);
> +
> +static int __init max_part_setup(char *str)
> +{
> + loop_max_part = simple_strtol(str, NULL, 0);
> + if (loop_max_part > (1UL << (MINORBITS - 1))) {
> + /* we must keep at least one bit for loop device number */
> + printk(KERN_ERR
> + "loop: loop_max_part cannot be greater than %lu\n",
> + 1UL << (MINORBITS - 1));
> + return 0;
> + }
> + return 1;
> +}
> +
> +__setup("loop_max_part=", max_part_setup);
> #endif


--
Bill Davidsen <[email protected]>
"We have more to fear from the bungling of the incompetent than from
the machinations of the wicked." - from Slashdot

2008-03-19 21:44:48

by Randy Dunlap

[permalink] [raw]
Subject: Re: [PATCH][v4] Modify loop device to be able to manage partitions of the disk image

On Wed, 19 Mar 2008 13:36:07 +0100 Laurent Vivier wrote:

> This patch allows to use loop device with partitionned disk image.
>
> Original behavior of loop is not modified.
>
> A new parameter is introduced to define how many partition we want to be
> able to manage per loop device. This parameter is "max_part".

What happened to the update to Documentation/kernel-parameters.txt
that was in v3?


> For instance, to manage 63 partitions / loop device, we will do:
> # modprobe loop max_part=63
> # ls -l /dev/loop?*
> brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
> brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
> brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
> brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
> brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
> brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
> brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
> brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
>
> And to attach a raw partitionned disk image, the original losetup is used:
>
> # losetup -f etch.img
> # ls -l /dev/loop?*
> brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
> brw-rw---- 1 root disk 7, 1 2008-03-05 14:57 /dev/loop0p1
> brw-rw---- 1 root disk 7, 2 2008-03-05 14:57 /dev/loop0p2
> brw-rw---- 1 root disk 7, 5 2008-03-05 14:57 /dev/loop0p5
> brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
> brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
> brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
> brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
> brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
> brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
> brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
> # mount /dev/loop0p1 /mnt
> # ls /mnt
> bench cdrom home lib mnt root srv usr
> bin dev initrd lost+found opt sbin sys var
> boot etc initrd.img media proc selinux tmp vmlinuz
> # umount /mnt
> # losetup -d /dev/loop0
>
> Of course, the same behavior can be done using kpartx on a loop device,
> but modifying loop avoids to stack several layers of block device (loop +
> device mapper), this is a very light modification (40% of modifications
> are to manage the new parameter).
>
> Signed-off-by: Laurent Vivier <[email protected]>
> ---
> drivers/block/loop.c | 26 +++++++++++++++++++++-----
> 1 files changed, 21 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> index 91ebb00..f7f1635 100644
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -82,6 +82,9 @@
> static LIST_HEAD(loop_devices);
> static DEFINE_MUTEX(loop_devices_mutex);
>
> +static int max_part;
> +static int part_shift;
> +
> /*
> * Transfer functions
> */
> @@ -692,6 +695,8 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
> goto out_putf;
>
> fput(old_file);
> + if (max_part > 0)
> + ioctl_by_bdev(bdev, BLKRRPART, 0);
> return 0;
>
> out_putf:
> @@ -819,6 +824,8 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
> }
> lo->lo_state = Lo_bound;
> wake_up_process(lo->lo_thread);
> + if (max_part > 0)
> + ioctl_by_bdev(bdev, BLKRRPART, 0);
> return 0;
>
> out_clr:
> @@ -919,6 +926,8 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
> fput(filp);
> /* This is safe: open() is still holding a reference. */
> module_put(THIS_MODULE);
> + if (max_part > 0)
> + ioctl_by_bdev(bdev, BLKRRPART, 0);
> return 0;
> }
>
> @@ -1360,6 +1369,8 @@ static struct block_device_operations lo_fops = {
> static int max_loop;
> module_param(max_loop, int, 0);
> MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
> +module_param(max_part, int, 0);
> +MODULE_PARM_DESC(max_part, "Maximum number of partitions per loop device");
> MODULE_LICENSE("GPL");
> MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
>
> @@ -1412,7 +1423,7 @@ static struct loop_device *loop_alloc(int i)
> if (!lo->lo_queue)
> goto out_free_dev;
>
> - disk = lo->lo_disk = alloc_disk(1);
> + disk = lo->lo_disk = alloc_disk(1 << part_shift);
> if (!disk)
> goto out_free_queue;
>
> @@ -1422,7 +1433,7 @@ static struct loop_device *loop_alloc(int i)
> init_waitqueue_head(&lo->lo_event);
> spin_lock_init(&lo->lo_lock);
> disk->major = LOOP_MAJOR;
> - disk->first_minor = i;
> + disk->first_minor = i << part_shift;
> disk->fops = &lo_fops;
> disk->private_data = lo;
> disk->queue = lo->lo_queue;
> @@ -1502,7 +1513,12 @@ static int __init loop_init(void)
> * themselves and have kernel automatically instantiate actual
> * device on-demand.
> */
> - if (max_loop > 1UL << MINORBITS)
> +
> + part_shift = 0;
> + if (max_part > 0)
> + part_shift = fls(max_part);
> +
> + if (max_loop > 1UL << (MINORBITS - part_shift))
> return -EINVAL;
>
> if (max_loop) {
> @@ -1510,7 +1526,7 @@ static int __init loop_init(void)
> range = max_loop;
> } else {
> nr = 8;
> - range = 1UL << MINORBITS;
> + range = 1UL << (MINORBITS - part_shift);
> }
>
> if (register_blkdev(LOOP_MAJOR, "loop"))
> @@ -1549,7 +1565,7 @@ static void __exit loop_exit(void)
> unsigned long range;
> struct loop_device *lo, *next;
>
> - range = max_loop ? max_loop : 1UL << MINORBITS;
> + range = max_loop ? max_loop : 1UL << (MINORBITS - part_shift);
>
> list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
> loop_del_one(lo);
> --


---
~Randy

2008-03-19 21:55:52

by Laurent Vivier

[permalink] [raw]
Subject: Re: [PATCH][v4] Modify loop device to be able to manage partitions of the disk image


Le mercredi 19 mars 2008 à 13:11 -0700, Randy Dunlap a écrit :
> On Wed, 19 Mar 2008 13:36:07 +0100 Laurent Vivier wrote:
>
> > This patch allows to use loop device with partitionned disk image.
> >
> > Original behavior of loop is not modified.
> >
> > A new parameter is introduced to define how many partition we want to be
> > able to manage per loop device. This parameter is "max_part".
>
> What happened to the update to Documentation/kernel-parameters.txt
> that was in v3?

Well, perhaps I didn't understand the comment of Andrew:

"This shouldn't be needed."

I though it means I should remove it. So, Andrew ???

And to comment the changes between v3 and v4:

- remove modification from kernel-parameters.txt (as you saw)
- rename the parameter to max_part (according Andrew comments)
- add an "ioctl_by_bdev(bdev, BLKRRPART, 0);" on loop_clr_fd()
(to remove loopXpY from /dev/ on "losetup -d")

Laurent

>
> > For instance, to manage 63 partitions / loop device, we will do:
> > # modprobe loop max_part=63
> > # ls -l /dev/loop?*
> > brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
> > brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
> > brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
> > brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
> > brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
> > brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
> > brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
> > brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
> >
> > And to attach a raw partitionned disk image, the original losetup is used:
> >
> > # losetup -f etch.img
> > # ls -l /dev/loop?*
> > brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
> > brw-rw---- 1 root disk 7, 1 2008-03-05 14:57 /dev/loop0p1
> > brw-rw---- 1 root disk 7, 2 2008-03-05 14:57 /dev/loop0p2
> > brw-rw---- 1 root disk 7, 5 2008-03-05 14:57 /dev/loop0p5
> > brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
> > brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
> > brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
> > brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
> > brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
> > brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
> > brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
> > # mount /dev/loop0p1 /mnt
> > # ls /mnt
> > bench cdrom home lib mnt root srv usr
> > bin dev initrd lost+found opt sbin sys var
> > boot etc initrd.img media proc selinux tmp vmlinuz
> > # umount /mnt
> > # losetup -d /dev/loop0
> >
> > Of course, the same behavior can be done using kpartx on a loop device,
> > but modifying loop avoids to stack several layers of block device (loop +
> > device mapper), this is a very light modification (40% of modifications
> > are to manage the new parameter).
> >
> > Signed-off-by: Laurent Vivier <[email protected]>
> > ---
> > drivers/block/loop.c | 26 +++++++++++++++++++++-----
> > 1 files changed, 21 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> > index 91ebb00..f7f1635 100644
> > --- a/drivers/block/loop.c
> > +++ b/drivers/block/loop.c
> > @@ -82,6 +82,9 @@
> > static LIST_HEAD(loop_devices);
> > static DEFINE_MUTEX(loop_devices_mutex);
> >
> > +static int max_part;
> > +static int part_shift;
> > +
> > /*
> > * Transfer functions
> > */
> > @@ -692,6 +695,8 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
> > goto out_putf;
> >
> > fput(old_file);
> > + if (max_part > 0)
> > + ioctl_by_bdev(bdev, BLKRRPART, 0);
> > return 0;
> >
> > out_putf:
> > @@ -819,6 +824,8 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
> > }
> > lo->lo_state = Lo_bound;
> > wake_up_process(lo->lo_thread);
> > + if (max_part > 0)
> > + ioctl_by_bdev(bdev, BLKRRPART, 0);
> > return 0;
> >
> > out_clr:
> > @@ -919,6 +926,8 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
> > fput(filp);
> > /* This is safe: open() is still holding a reference. */
> > module_put(THIS_MODULE);
> > + if (max_part > 0)
> > + ioctl_by_bdev(bdev, BLKRRPART, 0);
> > return 0;
> > }
> >
> > @@ -1360,6 +1369,8 @@ static struct block_device_operations lo_fops = {
> > static int max_loop;
> > module_param(max_loop, int, 0);
> > MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
> > +module_param(max_part, int, 0);
> > +MODULE_PARM_DESC(max_part, "Maximum number of partitions per loop device");
> > MODULE_LICENSE("GPL");
> > MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
> >
> > @@ -1412,7 +1423,7 @@ static struct loop_device *loop_alloc(int i)
> > if (!lo->lo_queue)
> > goto out_free_dev;
> >
> > - disk = lo->lo_disk = alloc_disk(1);
> > + disk = lo->lo_disk = alloc_disk(1 << part_shift);
> > if (!disk)
> > goto out_free_queue;
> >
> > @@ -1422,7 +1433,7 @@ static struct loop_device *loop_alloc(int i)
> > init_waitqueue_head(&lo->lo_event);
> > spin_lock_init(&lo->lo_lock);
> > disk->major = LOOP_MAJOR;
> > - disk->first_minor = i;
> > + disk->first_minor = i << part_shift;
> > disk->fops = &lo_fops;
> > disk->private_data = lo;
> > disk->queue = lo->lo_queue;
> > @@ -1502,7 +1513,12 @@ static int __init loop_init(void)
> > * themselves and have kernel automatically instantiate actual
> > * device on-demand.
> > */
> > - if (max_loop > 1UL << MINORBITS)
> > +
> > + part_shift = 0;
> > + if (max_part > 0)
> > + part_shift = fls(max_part);
> > +
> > + if (max_loop > 1UL << (MINORBITS - part_shift))
> > return -EINVAL;
> >
> > if (max_loop) {
> > @@ -1510,7 +1526,7 @@ static int __init loop_init(void)
> > range = max_loop;
> > } else {
> > nr = 8;
> > - range = 1UL << MINORBITS;
> > + range = 1UL << (MINORBITS - part_shift);
> > }
> >
> > if (register_blkdev(LOOP_MAJOR, "loop"))
> > @@ -1549,7 +1565,7 @@ static void __exit loop_exit(void)
> > unsigned long range;
> > struct loop_device *lo, *next;
> >
> > - range = max_loop ? max_loop : 1UL << MINORBITS;
> > + range = max_loop ? max_loop : 1UL << (MINORBITS - part_shift);
> >
> > list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
> > loop_del_one(lo);
> > --
>
>
> ---
> ~Randy
>
--
------- [email protected] -------
"The best way to predict the future
is to invent it." - Alan Kay

2008-03-19 22:05:07

by Laurent Vivier

[permalink] [raw]
Subject: Re: [PATCH][RESEND][v3] Modify loop device to be able to manage partitions of the disk image


Le mercredi 19 mars 2008 à 16:24 -0400, Bill Davidsen a écrit :
> Laurent Vivier wrote:
> > v3 is an updated version of v2, replacing a "%d" by a "%lu".
> >
> > This patch allows to use loop device with partitionned disk image.
> >
> How does this compare in overhead to using nbd?

What do you mean ?

NBD doesn't manage partitions... but I also have a patch to do that.
NBD implies an NBD server and an NBD client in userspace, so loop is
better when disk image is in a raw format.

Laurent

> > Original behavior of loop is not modified.
> >
> > A new parameter is introduced to define how many partition we want to be
> > able to manage per loop device. This parameter is "loop_max_part".
> >
> > For instance, to manage 63 partitions / loop device, we will do:
> > # modprobe loop loop_max_part=63
> > # ls -l /dev/loop?
> > brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
> > brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
> > brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
> > brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
> > brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
> > brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
> > brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
> > brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
> >
> > And to attach a raw partitionned disk image, the original losetup is used:
> >
> > # losetup -f etch.img
> > EXT3 FS on loop0p1, internal journal
> > EXT3-fs: mounted filesystem with ordered data mode.
> > loop: module loaded
> > loop0: p1 p2 < p5 >
> > # ls -l /dev/loop?*
> > brw-rw---- 1 root disk 7, 0 2008-03-05 14:55 /dev/loop0
> > brw-rw---- 1 root disk 7, 1 2008-03-05 14:57 /dev/loop0p1
> > brw-rw---- 1 root disk 7, 2 2008-03-05 14:57 /dev/loop0p2
> > brw-rw---- 1 root disk 7, 5 2008-03-05 14:57 /dev/loop0p5
> > brw-rw---- 1 root disk 7, 64 2008-03-05 14:55 /dev/loop1
> > brw-rw---- 1 root disk 7, 128 2008-03-05 14:55 /dev/loop2
> > brw-rw---- 1 root disk 7, 192 2008-03-05 14:55 /dev/loop3
> > brw-rw---- 1 root disk 7, 256 2008-03-05 14:55 /dev/loop4
> > brw-rw---- 1 root disk 7, 320 2008-03-05 14:55 /dev/loop5
> > brw-rw---- 1 root disk 7, 384 2008-03-05 14:55 /dev/loop6
> > brw-rw---- 1 root disk 7, 448 2008-03-05 14:55 /dev/loop7
> > # mount /dev/loop0p1 /mnt
> > kjournald starting. Commit interval 5 seconds
> > EXT3 FS on loop0p1, internal journal
> > EXT3-fs: mounted filesystem with ordered data mode.
> > # ls /mnt
> > bench cdrom home lib mnt root srv usr
> > bin dev initrd lost+found opt sbin sys var
> > boot etc initrd.img media proc selinux tmp vmlinuz
> > # umount /mnt
> > # losetup -d /dev/loop0
> >
> > Of course, the same behavior can be done using kpartx on a loop device,
> > but modifying loop avoids to stack several layers of block device (loop +
> > device mapper), this is a very light modification (40% of modifications
> > are to manage the new parameter).
> >
> > Signed-off-by: Laurent Vivier <[email protected]>
> > ---
> > Documentation/kernel-parameters.txt | 4 +++
> > drivers/block/loop.c | 39 ++++++++++++++++++++++++++++++----
> > 2 files changed, 38 insertions(+), 5 deletions(-)
> >
> > diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
> > index 9a5b665..7f2fd52 100644
> > --- a/Documentation/kernel-parameters.txt
> > +++ b/Documentation/kernel-parameters.txt
> > @@ -1075,6 +1075,10 @@ and is between 256 and 4096 characters. It is defined in the file
> > be mounted
> > Format: <1-256>
> >
> > + loop_max_part= [LOOP] Maximum number of partitions per loopback device.
> > + Should be greater than 0, the maximum value depends
> > + on max_loop.
> > +
> > maxcpus= [SMP] Maximum number of processors that an SMP kernel
> > should make use of. maxcpus=n : n >= 0 limits the
> > kernel to using 'n' processors. n=0 is a special case,
> > diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> > index 91ebb00..16b2aa6 100644
> > --- a/drivers/block/loop.c
> > +++ b/drivers/block/loop.c
> > @@ -82,6 +82,9 @@
> > static LIST_HEAD(loop_devices);
> > static DEFINE_MUTEX(loop_devices_mutex);
> >
> > +static int loop_max_part;
> > +static int part_shift;
> > +
> > /*
> > * Transfer functions
> > */
> > @@ -692,6 +695,8 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
> > goto out_putf;
> >
> > fput(old_file);
> > + if (loop_max_part > 0)
> > + ioctl_by_bdev(bdev, BLKRRPART, 0);
> > return 0;
> >
> > out_putf:
> > @@ -819,6 +824,8 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
> > }
> > lo->lo_state = Lo_bound;
> > wake_up_process(lo->lo_thread);
> > + if (loop_max_part > 0)
> > + ioctl_by_bdev(bdev, BLKRRPART, 0);
> > return 0;
> >
> > out_clr:
> > @@ -1360,6 +1367,8 @@ static struct block_device_operations lo_fops = {
> > static int max_loop;
> > module_param(max_loop, int, 0);
> > MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
> > +module_param(loop_max_part, int, 0);
> > +MODULE_PARM_DESC(loop_max_part, "Maximum number of partitions per loop device");
> > MODULE_LICENSE("GPL");
> > MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
> >
> > @@ -1412,7 +1421,7 @@ static struct loop_device *loop_alloc(int i)
> > if (!lo->lo_queue)
> > goto out_free_dev;
> >
> > - disk = lo->lo_disk = alloc_disk(1);
> > + disk = lo->lo_disk = alloc_disk(1 << part_shift);
> > if (!disk)
> > goto out_free_queue;
> >
> > @@ -1422,7 +1431,7 @@ static struct loop_device *loop_alloc(int i)
> > init_waitqueue_head(&lo->lo_event);
> > spin_lock_init(&lo->lo_lock);
> > disk->major = LOOP_MAJOR;
> > - disk->first_minor = i;
> > + disk->first_minor = i << part_shift;
> > disk->fops = &lo_fops;
> > disk->private_data = lo;
> > disk->queue = lo->lo_queue;
> > @@ -1502,7 +1511,12 @@ static int __init loop_init(void)
> > * themselves and have kernel automatically instantiate actual
> > * device on-demand.
> > */
> > - if (max_loop > 1UL << MINORBITS)
> > +
> > + part_shift = 0;
> > + if (loop_max_part > 0)
> > + part_shift = fls(loop_max_part);
> > +
> > + if (max_loop > 1UL << (MINORBITS - part_shift))
> > return -EINVAL;
> >
> > if (max_loop) {
> > @@ -1510,7 +1524,7 @@ static int __init loop_init(void)
> > range = max_loop;
> > } else {
> > nr = 8;
> > - range = 1UL << MINORBITS;
> > + range = 1UL << (MINORBITS - part_shift);
> > }
> >
> > if (register_blkdev(LOOP_MAJOR, "loop"))
> > @@ -1549,7 +1563,7 @@ static void __exit loop_exit(void)
> > unsigned long range;
> > struct loop_device *lo, *next;
> >
> > - range = max_loop ? max_loop : 1UL << MINORBITS;
> > + range = max_loop ? max_loop : 1UL << (MINORBITS - part_shift);
> >
> > list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
> > loop_del_one(lo);
> > @@ -1569,4 +1583,19 @@ static int __init max_loop_setup(char *str)
> > }
> >
> > __setup("max_loop=", max_loop_setup);
> > +
> > +static int __init max_part_setup(char *str)
> > +{
> > + loop_max_part = simple_strtol(str, NULL, 0);
> > + if (loop_max_part > (1UL << (MINORBITS - 1))) {
> > + /* we must keep at least one bit for loop device number */
> > + printk(KERN_ERR
> > + "loop: loop_max_part cannot be greater than %lu\n",
> > + 1UL << (MINORBITS - 1));
> > + return 0;
> > + }
> > + return 1;
> > +}
> > +
> > +__setup("loop_max_part=", max_part_setup);
> > #endif
>
>
--
------- [email protected] -------
"The best way to predict the future
is to invent it." - Alan Kay

2008-03-19 23:03:20

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH][v4] Modify loop device to be able to manage partitions of the disk image

On Wed, 19 Mar 2008 21:24:41 +0100
Laurent Vivier <[email protected]> wrote:

> Le mercredi 19 mars 2008 __ 13:11 -0700, Randy Dunlap a __crit :
> > On Wed, 19 Mar 2008 13:36:07 +0100 Laurent Vivier wrote:
> >
> > > This patch allows to use loop device with partitionned disk image.
> > >
> > > Original behavior of loop is not modified.
> > >
> > > A new parameter is introduced to define how many partition we want to be
> > > able to manage per loop device. This parameter is "max_part".
> >
> > What happened to the update to Documentation/kernel-parameters.txt
> > that was in v3?
>
> Well, perhaps I didn't understand the comment of Andrew:
>
> "This shouldn't be needed."
>
> I though it means I should remove it. So, Andrew ???

No, given that all module_param() options are available via the boot
command line when the module is linked into vmlinux, we don't document them
separately.

There should be a way of auto-generating all the documentation for all the
module parameters from their MODULE_PARM_DESC's. And there probably is,
but I'm not sure how this is done (?)

(does `make help', fails to spot it).

You can do `modinfo loop' but that probably doesn't work if
CONFIG_BLK_DEV_LOOP=y?



I assume you tested the "loop.max_part=N" option?

2008-03-19 23:11:15

by Laurent Vivier

[permalink] [raw]
Subject: Re: [PATCH][v4] Modify loop device to be able to manage partitions of the disk image


Le mercredi 19 mars 2008 à 14:28 -0700, Andrew Morton a écrit :
> On Wed, 19 Mar 2008 21:24:41 +0100
> Laurent Vivier <[email protected]> wrote:
>
> > Le mercredi 19 mars 2008 __ 13:11 -0700, Randy Dunlap a __crit :
> > > On Wed, 19 Mar 2008 13:36:07 +0100 Laurent Vivier wrote:
> > >
> > > > This patch allows to use loop device with partitionned disk image.
> > > >
> > > > Original behavior of loop is not modified.
> > > >
> > > > A new parameter is introduced to define how many partition we want to be
> > > > able to manage per loop device. This parameter is "max_part".
> > >
> > > What happened to the update to Documentation/kernel-parameters.txt
> > > that was in v3?
> >
> > Well, perhaps I didn't understand the comment of Andrew:
> >
> > "This shouldn't be needed."
> >
> > I though it means I should remove it. So, Andrew ???
>
> No, given that all module_param() options are available via the boot
> command line when the module is linked into vmlinux, we don't document them
> separately.

"No" is "To document max_part is not needed"

or

"No" is "you must not remove parameter documentation from your patch" ?

> There should be a way of auto-generating all the documentation for all the
> module parameters from their MODULE_PARM_DESC's. And there probably is,
> but I'm not sure how this is done (?)
>
> (does `make help', fails to spot it).
>
> You can do `modinfo loop' but that probably doesn't work if
> CONFIG_BLK_DEV_LOOP=y?
>
>
>
> I assume you tested the "loop.max_part=N" option?

Yes, I did (with N=63)

Regards,
Laurent
--
------------- [email protected] ---------------
"The best way to predict the future is to invent it."
- Alan Kay

2008-03-19 23:18:34

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH][v4] Modify loop device to be able to manage partitions of the disk image

On Wed, 19 Mar 2008 22:39:10 +0100
Laurent Vivier <[email protected]> wrote:

> > > > What happened to the update to Documentation/kernel-parameters.txt
> > > > that was in v3?
> > >
> > > Well, perhaps I didn't understand the comment of Andrew:
> > >
> > > "This shouldn't be needed."
> > >
> > > I though it means I should remove it. So, Andrew ???
> >
> > No, given that all module_param() options are available via the boot
> > command line when the module is linked into vmlinux, we don't document them
> > separately.
>
> "No" is "To document max_part is not needed"
>
> or
>
> "No" is "you must not remove parameter documentation from your patch" ?

The former ;)

2008-03-20 00:05:28

by Randy Dunlap

[permalink] [raw]
Subject: Re: [PATCH][v4] Modify loop device to be able to manage partitions of the disk image

Andrew Morton wrote:
> On Wed, 19 Mar 2008 21:24:41 +0100
> Laurent Vivier <[email protected]> wrote:
>
>> Le mercredi 19 mars 2008 __ 13:11 -0700, Randy Dunlap a __crit :
>>> On Wed, 19 Mar 2008 13:36:07 +0100 Laurent Vivier wrote:
>>>
>>>> This patch allows to use loop device with partitionned disk image.
>>>>
>>>> Original behavior of loop is not modified.
>>>>
>>>> A new parameter is introduced to define how many partition we want to be
>>>> able to manage per loop device. This parameter is "max_part".
>>> What happened to the update to Documentation/kernel-parameters.txt
>>> that was in v3?
>> Well, perhaps I didn't understand the comment of Andrew:
>>
>> "This shouldn't be needed."
>>
>> I though it means I should remove it. So, Andrew ???

First of all, I didn't see Andrew's message until awhile after yours,
due to some kind of email problems...

> No, given that all module_param() options are available via the boot
> command line when the module is linked into vmlinux, we don't document them
> separately.

Thanks. That's news to me. Not that I mind the news.

> There should be a way of auto-generating all the documentation for all the
> module parameters from their MODULE_PARM_DESC's. And there probably is,
> but I'm not sure how this is done (?)

No, nothing in tree like that.

Would such an auto-generator use source files or compiled modules?
Using the latter means that (a) something like allmodconfig must be done
and (b) it only works for the compiled $ARCH(es), whereas using source code
has neither of those "problems."

I can work on updating
http://www.xenotime.net/linux/scripts/module-params (from Oct-2006).
Comments welcome.


> (does `make help', fails to spot it).
>
> You can do `modinfo loop' but that probably doesn't work if
> CONFIG_BLK_DEV_LOOP=y?


--
~Randy

2008-03-20 21:37:36

by Bill Davidsen

[permalink] [raw]
Subject: Re: [PATCH][v4] Modify loop device to be able to manage partitions of the disk image

Andrew Morton wrote:
> On Wed, 19 Mar 2008 21:24:41 +0100
> Laurent Vivier <[email protected]> wrote:
>
>> Le mercredi 19 mars 2008 __ 13:11 -0700, Randy Dunlap a __crit :
>>> On Wed, 19 Mar 2008 13:36:07 +0100 Laurent Vivier wrote:
>>>
>>>> This patch allows to use loop device with partitionned disk image.
>>>>
>>>> Original behavior of loop is not modified.
>>>>
>>>> A new parameter is introduced to define how many partition we want to be
>>>> able to manage per loop device. This parameter is "max_part".
>>> What happened to the update to Documentation/kernel-parameters.txt
>>> that was in v3?
>> Well, perhaps I didn't understand the comment of Andrew:
>>
>> "This shouldn't be needed."
>>
>> I though it means I should remove it. So, Andrew ???
>
> No, given that all module_param() options are available via the boot
> command line when the module is linked into vmlinux, we don't document them
> separately.
>
I totally don't understand this comment, where is the file with the list
of canonical module parameters now? I must have missed the discussion of
why it is changed. And what has the boot command line or linking modules
to do with the documentation file?

> There should be a way of auto-generating all the documentation for all the
> module parameters from their MODULE_PARM_DESC's. And there probably is,
> but I'm not sure how this is done (?)
>
> (does `make help', fails to spot it).


--
Bill Davidsen <[email protected]>
"We have more to fear from the bungling of the incompetent than from
the machinations of the wicked." - from Slashdot

2008-03-23 23:33:42

by Bill Davidsen

[permalink] [raw]
Subject: Re: [PATCH][RESEND][v3] Modify loop device to be able to manage partitions of the disk image

Laurent Vivier wrote:
> Le mercredi 19 mars 2008 à 16:24 -0400, Bill Davidsen a écrit :
>> Laurent Vivier wrote:
>>> v3 is an updated version of v2, replacing a "%d" by a "%lu".
>>>
>>> This patch allows to use loop device with partitionned disk image.
>>>
>> How does this compare in overhead to using nbd?
>
> What do you mean ?
>
> NBD doesn't manage partitions... but I also have a patch to do that.
> NBD implies an NBD server and an NBD client in userspace, so loop is
> better when disk image is in a raw format.
>
Actually the usual partitioning tools will create partitions on nbd
volumes, but without inodes they are not useful. I thought we used to
have that working, to work on virtual machine "disk" files which were
partitioned, but that was several years ago and I could be
misremembering. I did use fdisk on an nbd device before I asked about
overhead, but I didn't try to use the partitions.

In any case, if you have code to make nbd partitions work in a currently
useful way, that might be useful for keeping disk images handy for
mount. The kvm copy on write might let the fresh install image be shared
and VMs customize as needed.

--
Bill Davidsen <[email protected]>
"We have more to fear from the bungling of the incompetent than from
the machinations of the wicked." - from Slashdot

2008-03-25 10:32:41

by Laurent Vivier

[permalink] [raw]
Subject: [PATCH] Modify Network Block Device (nbd) to be able to manage partitions

This patch allows to use partitions with network block devices (NBD).

A new parameter is introduced to define how many partition we want to be
able to manage per network block device. This parameter is "max_part".

For instance, to manage 63 partitions / loop device, we will do:

[on the server side]
# nbd-server 1234 /dev/sdb
[on the client side]
# modprobe nbd max_part=63
# ls -l /dev/nbd*
brw-rw---- 1 root disk 43, 0 2008-03-25 11:14 /dev/nbd0
brw-rw---- 1 root disk 43, 64 2008-03-25 11:11 /dev/nbd1
brw-rw---- 1 root disk 43, 640 2008-03-25 11:11 /dev/nbd10
brw-rw---- 1 root disk 43, 704 2008-03-25 11:11 /dev/nbd11
brw-rw---- 1 root disk 43, 768 2008-03-25 11:11 /dev/nbd12
brw-rw---- 1 root disk 43, 832 2008-03-25 11:11 /dev/nbd13
brw-rw---- 1 root disk 43, 896 2008-03-25 11:11 /dev/nbd14
brw-rw---- 1 root disk 43, 960 2008-03-25 11:11 /dev/nbd15
brw-rw---- 1 root disk 43, 128 2008-03-25 11:11 /dev/nbd2
brw-rw---- 1 root disk 43, 192 2008-03-25 11:11 /dev/nbd3
brw-rw---- 1 root disk 43, 256 2008-03-25 11:11 /dev/nbd4
brw-rw---- 1 root disk 43, 320 2008-03-25 11:11 /dev/nbd5
brw-rw---- 1 root disk 43, 384 2008-03-25 11:11 /dev/nbd6
brw-rw---- 1 root disk 43, 448 2008-03-25 11:11 /dev/nbd7
brw-rw---- 1 root disk 43, 512 2008-03-25 11:11 /dev/nbd8
brw-rw---- 1 root disk 43, 576 2008-03-25 11:11 /dev/nbd9
# nbd-client localhost 1234 /dev/nbd0
Negotiation: ..size = 80418240KB
bs=1024, sz=80418240

-------NOTE, RFC: partition table is not automatically read.
The driver sets bdev->bd_invalidated to 1 to force the read of the partition
table of the device, but this is done only on an open of the device.
So we have to do a "touch /dev/nbdX" or something like that.
It can't be done from the nbd-client or nbd driver because at this
level we can't ask to read the partition table and to serve the request
at the same time (-> deadlock)

If someone has a better idea, I'm open to any suggestion.
-------NOTE, RFC

# fdisk -l /dev/nbd0

Disk /dev/nbd0: 82.3 GB, 82348277760 bytes
255 heads, 63 sectors/track, 10011 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/nbd0p1 * 1 9965 80043831 83 Linux
/dev/nbd0p2 9966 10011 369495 5 Extended
/dev/nbd0p5 9966 10011 369463+ 82 Linux swap / Solaris

# ls -l /dev/nbd0*
brw-rw---- 1 root disk 43, 0 2008-03-25 11:16 /dev/nbd0
brw-rw---- 1 root disk 43, 1 2008-03-25 11:16 /dev/nbd0p1
brw-rw---- 1 root disk 43, 2 2008-03-25 11:16 /dev/nbd0p2
brw-rw---- 1 root disk 43, 5 2008-03-25 11:16 /dev/nbd0p5
# mount /dev/nbd0p1 /mnt
# ls /mnt
bin dev initrd lost+found opt sbin sys var
boot etc initrd.img media proc selinux tmp vmlinuz
cdrom home lib mnt root srv usr
# umount /mnt
# nbd-client -d /dev/nbd0
# ls -l /dev/nbd0*
brw-rw---- 1 root disk 43, 0 2008-03-25 11:16 /dev/nbd0
-------NOTE
On "nbd-client -d", we can do an iocl(BLKRRPART) to update partition table:
as the size of the device is 0, we don't have to serve the partition manager
request (-> no deadlock).
-------NOTE

Signed-off-by: Laurent Vivier <[email protected]>
---
drivers/block/nbd.c | 25 ++++++++++++++++++++++---
1 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index b53fdb0..36070d5 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -55,6 +55,7 @@ static unsigned int debugflags;

static unsigned int nbds_max = 16;
static struct nbd_device *nbd_dev;
+static int max_part;

/*
* Use just one lock (or at most 1 per NIC). Two arguments for this:
@@ -565,10 +566,13 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
error = -EINVAL;
file = fget(arg);
if (file) {
+ struct block_device *bdev = inode->i_bdev;
inode = file->f_path.dentry->d_inode;
if (S_ISSOCK(inode->i_mode)) {
lo->file = file;
lo->sock = SOCKET_I(inode);
+ if (max_part > 0)
+ bdev->bd_invalidated = 1;
error = 0;
} else {
fput(file);
@@ -613,6 +617,8 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
lo->bytesize = 0;
inode->i_bdev->bd_inode->i_size = 0;
set_capacity(lo->disk, 0);
+ if (max_part > 0)
+ ioctl_by_bdev(inode->i_bdev, BLKRRPART, 0);
return lo->harderror;
case NBD_CLEAR_QUE:
/*
@@ -646,6 +652,7 @@ static int __init nbd_init(void)
{
int err = -ENOMEM;
int i;
+ int part_shift;

BUILD_BUG_ON(sizeof(struct nbd_request) != 28);

@@ -653,8 +660,17 @@ static int __init nbd_init(void)
if (!nbd_dev)
return -ENOMEM;

+ if (max_part < 0) {
+ printk(KERN_CRIT "nbd: max_part must be >= 0\n");
+ return -EINVAL;
+ }
+
+ part_shift = 0;
+ if (max_part > 0)
+ part_shift = fls(max_part);
+
for (i = 0; i < nbds_max; i++) {
- struct gendisk *disk = alloc_disk(1);
+ struct gendisk *disk = alloc_disk(1 << part_shift);
elevator_t *old_e;
if (!disk)
goto out;
@@ -696,10 +712,11 @@ static int __init nbd_init(void)
nbd_dev[i].blksize = 1024;
nbd_dev[i].bytesize = 0;
disk->major = NBD_MAJOR;
- disk->first_minor = i;
+ disk->first_minor = i << part_shift;
disk->fops = &nbd_fops;
disk->private_data = &nbd_dev[i];
- disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
+ if (max_part == 0)
+ disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
sprintf(disk->disk_name, "nbd%d", i);
set_capacity(disk, 0);
add_disk(disk);
@@ -738,6 +755,8 @@ MODULE_LICENSE("GPL");

module_param(nbds_max, int, 0444);
MODULE_PARM_DESC(nbds_max, "How many network block devices to initialize.");
+module_param(max_part, int, 0444);
+MODULE_PARM_DESC(max_part, "How many partitions by device.");
#ifndef NDEBUG
module_param(debugflags, int, 0644);
MODULE_PARM_DESC(debugflags, "flags for controlling debug output");
--
1.5.2.4