public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
       [not found] <200705212200.l4LM0tYK021050@shell0.pdx.osdl.net>
@ 2007-05-22  0:18 ` Al Viro
  2007-05-22  1:30   ` Ken Chen
  0 siblings, 1 reply; 12+ messages in thread
From: Al Viro @ 2007-05-22  0:18 UTC (permalink / raw)
  To: akpm; +Cc: mm-commits, kenchen, viro, linux-kernel

On Mon, May 21, 2007 at 03:00:55PM -0700, akpm@linux-foundation.org wrote:
> +	if (register_blkdev(LOOP_MAJOR, "loop"))
> +		return -EIO;
> +	blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
> +				  THIS_MODULE, loop_probe, NULL, NULL);
> +
> +	for (i = 0; i < nr; i++) {
> +		if (!loop_init_one(i))
> +			goto err;
> +	}
> +
> +	printk(KERN_INFO "loop: module loaded\n");
> +	return 0;
> +err:
> +	loop_exit();

This isn't good.  You *can't* fail once a single disk has been registered.
Anyone could've opened it by now.

IOW, you need to
	* register region *after* you are past the point of no return
	* either not fail on failing loop_init_one() here, or separate
allocations and actual add_disk().

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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-22  0:18 ` + loop-preallocate-eight-loop-devices.patch added to -mm tree Al Viro
@ 2007-05-22  1:30   ` Ken Chen
  2007-05-22  1:48     ` Al Viro
  0 siblings, 1 reply; 12+ messages in thread
From: Ken Chen @ 2007-05-22  1:30 UTC (permalink / raw)
  To: Al Viro; +Cc: akpm, mm-commits, viro, linux-kernel

On 5/21/07, Al Viro <viro@ftp.linux.org.uk> wrote:
> On Mon, May 21, 2007 at 03:00:55PM -0700, akpm@linux-foundation.org wrote:
> > +     if (register_blkdev(LOOP_MAJOR, "loop"))
> > +             return -EIO;
> > +     blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
> > +                               THIS_MODULE, loop_probe, NULL, NULL);
> > +
> > +     for (i = 0; i < nr; i++) {
> > +             if (!loop_init_one(i))
> > +                     goto err;
> > +     }
> > +
> > +     printk(KERN_INFO "loop: module loaded\n");
> > +     return 0;
> > +err:
> > +     loop_exit();
>
> This isn't good.  You *can't* fail once a single disk has been registered.
> Anyone could've opened it by now.
>
> IOW, you need to
>         * register region *after* you are past the point of no return

That option is a lot harder than I thought.  This requires an array to
keep intermediate result of preallocated "lo" device, blk_queue, and
disk structure before calling add_disk() or register region.  And this
array could be potentially 1 million entries.  Maybe I will use
vmalloc for it, but seems rather sick.

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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-22  1:30   ` Ken Chen
@ 2007-05-22  1:48     ` Al Viro
  2007-05-22  2:14       ` Ken Chen
  0 siblings, 1 reply; 12+ messages in thread
From: Al Viro @ 2007-05-22  1:48 UTC (permalink / raw)
  To: Ken Chen; +Cc: akpm, mm-commits, viro, linux-kernel

On Mon, May 21, 2007 at 06:30:15PM -0700, Ken Chen wrote:
> On 5/21/07, Al Viro <viro@ftp.linux.org.uk> wrote:
> >On Mon, May 21, 2007 at 03:00:55PM -0700, akpm@linux-foundation.org wrote:
> >> +     if (register_blkdev(LOOP_MAJOR, "loop"))
> >> +             return -EIO;
> >> +     blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
> >> +                               THIS_MODULE, loop_probe, NULL, NULL);
> >> +
> >> +     for (i = 0; i < nr; i++) {
> >> +             if (!loop_init_one(i))
> >> +                     goto err;
> >> +     }
> >> +
> >> +     printk(KERN_INFO "loop: module loaded\n");
> >> +     return 0;
> >> +err:
> >> +     loop_exit();
> >
> >This isn't good.  You *can't* fail once a single disk has been registered.
> >Anyone could've opened it by now.
> >
> >IOW, you need to
> >        * register region *after* you are past the point of no return
> 
> That option is a lot harder than I thought.  This requires an array to
> keep intermediate result of preallocated "lo" device, blk_queue, and
> disk structure before calling add_disk() or register region.  And this
> array could be potentially 1 million entries.  Maybe I will use
> vmalloc for it, but seems rather sick.

No, it doesn't.  Really.  It's easy to split; untested incremental to your
patch follows:

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 0aae8d8..2300490 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1394,16 +1394,11 @@ int loop_unregister_transfer(int number)
 EXPORT_SYMBOL(loop_register_transfer);
 EXPORT_SYMBOL(loop_unregister_transfer);
 
-static struct loop_device *loop_init_one(int i)
+static struct loop_device *loop_alloc(int i)
 {
 	struct loop_device *lo;
 	struct gendisk *disk;
 
-	list_for_each_entry(lo, &loop_devices, lo_list) {
-		if (lo->lo_number == i)
-			return lo;
-	}
-
 	lo = kzalloc(sizeof(*lo), GFP_KERNEL);
 	if (!lo)
 		goto out;
@@ -1427,8 +1422,6 @@ static struct loop_device *loop_init_one(int i)
 	disk->private_data	= lo;
 	disk->queue		= lo->lo_queue;
 	sprintf(disk->disk_name, "loop%d", i);
-	add_disk(disk);
-	list_add_tail(&lo->lo_list, &loop_devices);
 	return lo;
 
 out_free_queue:
@@ -1439,6 +1432,23 @@ out:
 	return NULL;
 }
 
+static struct loop_device *loop_init_one(int i)
+{
+	struct loop_device *lo;
+
+	list_for_each_entry(lo, &loop_devices, lo_list) {
+		if (lo->lo_number == i)
+			return lo;
+	}
+
+	lo = loop_alloc(i);
+	if (lo) {
+		add_disk(lo->lo_disk);
+		list_add_tail(&lo->lo_list, &loop_devices);
+	}
+	return lo;
+}
+
 static void loop_del_one(struct loop_device *lo)
 {
 	del_gendisk(lo->lo_disk);
@@ -1481,6 +1491,7 @@ static int __init loop_init(void)
 {
 	int i, nr;
 	unsigned long range;
+	struct loop_device *lo;
 
 	/*
 	 * loop module now has a feature to instantiate underlying device
@@ -1506,19 +1517,34 @@ static int __init loop_init(void)
 
 	if (register_blkdev(LOOP_MAJOR, "loop"))
 		return -EIO;
-	blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
-				  THIS_MODULE, loop_probe, NULL, NULL);
 
 	for (i = 0; i < nr; i++) {
-		if (!loop_init_one(i))
-			goto err;
+		lo = loop_alloc(i);
+		if (!lo)
+			goto Enomem;
+		list_add_tail(&lo->lo_list, &loop_devices);
 	}
 
+	/* point of no return */
+
+	list_for_each_entry(lo, &loop_devices, lo_list)
+		add_disk(lo->lo_disk);
+
+	blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
+				  THIS_MODULE, loop_probe, NULL, NULL);
+
 	printk(KERN_INFO "loop: module loaded\n");
 	return 0;
-err:
-	loop_exit();
+
+Enomem:
 	printk(KERN_INFO "loop: out of memory\n");
+
+	while(!list_empty(&loop_devices)) {
+		lo = list_entry(loop_devices.next, struct loop_device, lo_list);
+		loop_del_one(lo);
+	}
+
+	unregister_blkdev(LOOP_MAJOR, "loop");
 	return -ENOMEM;
 }
 

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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-22  1:48     ` Al Viro
@ 2007-05-22  2:14       ` Ken Chen
  2007-05-22  2:40         ` Ken Chen
  0 siblings, 1 reply; 12+ messages in thread
From: Ken Chen @ 2007-05-22  2:14 UTC (permalink / raw)
  To: Al Viro; +Cc: akpm, mm-commits, viro, linux-kernel

On 5/21/07, Al Viro <viro@ftp.linux.org.uk> wrote:
> No, it doesn't.  Really.  It's easy to split; untested incremental to your
> patch follows:
>
>         for (i = 0; i < nr; i++) {
> -               if (!loop_init_one(i))
> -                       goto err;
> +               lo = loop_alloc(i);
> +               if (!lo)
> +                       goto Enomem;
> +               list_add_tail(&lo->lo_list, &loop_devices);
>         }

ah, yes, use the loop_device list_head to link all the pending devices.


> +       /* point of no return */
> +
> +       list_for_each_entry(lo, &loop_devices, lo_list)
> +               add_disk(lo->lo_disk);
> +
> +       blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
> +                                 THIS_MODULE, loop_probe, NULL, NULL);
> +
>         printk(KERN_INFO "loop: module loaded\n");
>         return 0;
> -err:
> -       loop_exit();
> +
> +Enomem:
>         printk(KERN_INFO "loop: out of memory\n");
> +
> +       while(!list_empty(&loop_devices)) {
> +               lo = list_entry(loop_devices.next, struct loop_device, lo_list);
> +               loop_del_one(lo);
> +       }
> +
> +       unregister_blkdev(LOOP_MAJOR, "loop");
>         return -ENOMEM;
>  }

I suppose the loop_del_one call in Enomem label needs to be split up
too since in the error path, it hasn't done add_disk() yet?

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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-22  2:14       ` Ken Chen
@ 2007-05-22  2:40         ` Ken Chen
  2007-05-22  4:18           ` Al Viro
  2007-05-31 16:05           ` walt
  0 siblings, 2 replies; 12+ messages in thread
From: Ken Chen @ 2007-05-22  2:40 UTC (permalink / raw)
  To: Al Viro; +Cc: akpm, mm-commits, viro, linux-kernel

On 5/21/07, Ken Chen <kenchen@google.com> wrote:
> On 5/21/07, Al Viro <viro@ftp.linux.org.uk> wrote:
> > No, it doesn't.  Really.  It's easy to split; untested incremental to your
> > patch follows:
> >
> >         for (i = 0; i < nr; i++) {
> > -               if (!loop_init_one(i))
> > -                       goto err;
> > +               lo = loop_alloc(i);
> > +               if (!lo)
> > +                       goto Enomem;
> > +               list_add_tail(&lo->lo_list, &loop_devices);
> >         }
>
> ah, yes, use the loop_device list_head to link all the pending devices.
>
>
> > +       /* point of no return */
> > +
> > +       list_for_each_entry(lo, &loop_devices, lo_list)
> > +               add_disk(lo->lo_disk);
> > +
> > +       blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
> > +                                 THIS_MODULE, loop_probe, NULL, NULL);
> > +
> >         printk(KERN_INFO "loop: module loaded\n");
> >         return 0;
> > -err:
> > -       loop_exit();
> > +
> > +Enomem:
> >         printk(KERN_INFO "loop: out of memory\n");
> > +
> > +       while(!list_empty(&loop_devices)) {
> > +               lo = list_entry(loop_devices.next, struct loop_device, lo_list);
> > +               loop_del_one(lo);
> > +       }
> > +
> > +       unregister_blkdev(LOOP_MAJOR, "loop");
> >         return -ENOMEM;
> >  }
>
> I suppose the loop_del_one call in Enomem label needs to be split up
> too since in the error path, it hasn't done add_disk() yet?


tested, like this?

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 5526ead..0ed5470 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1354,7 +1354,7 @@ #endif
  */
 static int max_loop;
 module_param(max_loop, int, 0);
-MODULE_PARM_DESC(max_loop, "obsolete, loop device is created on-demand");
+MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);

@@ -1394,16 +1394,11 @@ int loop_unregister_transfer
 EXPORT_SYMBOL(loop_register_transfer);
 EXPORT_SYMBOL(loop_unregister_transfer);

-static struct loop_device *loop_init_one(int i)
+static struct loop_device *loop_alloc(int i)
 {
 	struct loop_device *lo;
 	struct gendisk *disk;

-	list_for_each_entry(lo, &loop_devices, lo_list) {
-		if (lo->lo_number == i)
-			return lo;
-	}
-
 	lo = kzalloc(sizeof(*lo), GFP_KERNEL);
 	if (!lo)
 		goto out;
@@ -1427,8 +1422,6 @@ static struct loop_device *loop_init_one
 	disk->private_data	= lo;
 	disk->queue		= lo->lo_queue;
 	sprintf(disk->disk_name, "loop%d", i);
-	add_disk(disk);
-	list_add_tail(&lo->lo_list, &loop_devices);
 	return lo;

 out_free_queue:
@@ -1439,15 +1432,37 @@ out:
 	return NULL;
 }

-static void loop_del_one(struct loop_device *lo)
+static void loop_free(struct loop_device *lo)
 {
-	del_gendisk(lo->lo_disk);
 	blk_cleanup_queue(lo->lo_queue);
 	put_disk(lo->lo_disk);
 	list_del(&lo->lo_list);
 	kfree(lo);
 }

+static struct loop_device *loop_init_one(int i)
+{
+	struct loop_device *lo;
+
+	list_for_each_entry(lo, &loop_devices, lo_list) {
+		if (lo->lo_number == i)
+			return lo;
+	}
+
+	lo = loop_alloc(i);
+	if (lo) {
+		add_disk(lo->lo_disk);
+		list_add_tail(&lo->lo_list, &loop_devices);
+	}
+	return lo;
+}
+
+static void loop_del_one(struct loop_device *lo)
+{
+	del_gendisk(lo->lo_disk);
+	loop_free(lo);
+}
+
 static struct kobject *loop_probe(dev_t dev, int *part, void *data)
 {
 	struct loop_device *lo;
@@ -1464,28 +1479,77 @@ static struct kobject *loop_probe

 static int __init loop_init(void)
 {
-	if (register_blkdev(LOOP_MAJOR, "loop"))
-		return -EIO;
-	blk_register_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS,
-				  THIS_MODULE, loop_probe, NULL, NULL);
+	int i, nr;
+	unsigned long range;
+	struct loop_device *lo, *next;
+
+	/*
+	 * loop module now has a feature to instantiate underlying device
+	 * structure on-demand, provided that there is an access dev node.
+	 * However, this will not work well with user space tool that doesn't
+	 * know about such "feature".  In order to not break any existing
+	 * tool, we do the following:
+	 *
+	 * (1) if max_loop is specified, create that many upfront, and this
+	 *     also becomes a hard limit.
+	 * (2) if max_loop is not specified, create 8 loop device on module
+	 *     load, user can further extend loop device by create dev node
+	 *     themselves and have kernel automatically instantiate actual
+	 *     device on-demand.
+	 */
+	if (max_loop > 1UL << MINORBITS)
+		return -EINVAL;

 	if (max_loop) {
-		printk(KERN_INFO "loop: the max_loop option is obsolete "
-				 "and will be removed in March 2008\n");
+		nr = max_loop;
+		range = max_loop;
+	} else {
+		nr = 8;
+		range = 1UL << MINORBITS;
+	}
+
+	if (register_blkdev(LOOP_MAJOR, "loop"))
+		return -EIO;

+	for (i = 0; i < nr; i++) {
+		lo = loop_alloc(i);
+		if (!lo)
+			goto Enomem;
+		list_add_tail(&lo->lo_list, &loop_devices);
 	}
+
+	/* point of no return */
+
+	list_for_each_entry(lo, &loop_devices, lo_list)
+		add_disk(lo->lo_disk);
+
+	blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
+				  THIS_MODULE, loop_probe, NULL, NULL);
+
 	printk(KERN_INFO "loop: module loaded\n");
 	return 0;
+
+Enomem:
+	printk(KERN_INFO "loop: out of memory\n");
+
+	list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
+		loop_free(lo);
+
+	unregister_blkdev(LOOP_MAJOR, "loop");
+	return -ENOMEM;
 }

 static void __exit loop_exit(void)
 {
+	unsigned long range;
 	struct loop_device *lo, *next;

+	range = max_loop ? max_loop :  1UL << MINORBITS;
+
 	list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
 		loop_del_one(lo);

-	blk_unregister_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS);
+	blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
 	if (unregister_blkdev(LOOP_MAJOR, "loop"))
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 }

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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-22  2:40         ` Ken Chen
@ 2007-05-22  4:18           ` Al Viro
  2007-05-31 16:05           ` walt
  1 sibling, 0 replies; 12+ messages in thread
From: Al Viro @ 2007-05-22  4:18 UTC (permalink / raw)
  To: Ken Chen; +Cc: akpm, mm-commits, viro, linux-kernel

On Mon, May 21, 2007 at 07:40:14PM -0700, Ken Chen wrote:
> tested, like this?
 
ACK.  Could merge loop_init_one() into the only remaining caller,
but it won't make the code simpler, so let's leave it at that.

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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-22  2:40         ` Ken Chen
  2007-05-22  4:18           ` Al Viro
@ 2007-05-31 16:05           ` walt
  2007-05-31 16:51             ` Ken Chen
  1 sibling, 1 reply; 12+ messages in thread
From: walt @ 2007-05-31 16:05 UTC (permalink / raw)
  To: linux-kernel

Ken Chen wrote:
> On 5/21/07, Ken Chen <kenchen@google.com> wrote:
...
> tested, like this?

Ken, your patch below works for me.  Are you going to send this
on to Linus?

> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> index 5526ead..0ed5470 100644
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -1354,7 +1354,7 @@ #endif
>  */
> static int max_loop;
> module_param(max_loop, int, 0);
> -MODULE_PARM_DESC(max_loop, "obsolete, loop device is created on-demand");
> +MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
> MODULE_LICENSE("GPL");
> MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
> 
> @@ -1394,16 +1394,11 @@ int loop_unregister_transfer
> EXPORT_SYMBOL(loop_register_transfer);
> EXPORT_SYMBOL(loop_unregister_transfer);
> 
> -static struct loop_device *loop_init_one(int i)
> +static struct loop_device *loop_alloc(int i)
> {
>     struct loop_device *lo;
>     struct gendisk *disk;
> 
> -    list_for_each_entry(lo, &loop_devices, lo_list) {
> -        if (lo->lo_number == i)
> -            return lo;
> -    }
> -
>     lo = kzalloc(sizeof(*lo), GFP_KERNEL);
>     if (!lo)
>         goto out;
> @@ -1427,8 +1422,6 @@ static struct loop_device *loop_init_one
>     disk->private_data    = lo;
>     disk->queue        = lo->lo_queue;
>     sprintf(disk->disk_name, "loop%d", i);
> -    add_disk(disk);
> -    list_add_tail(&lo->lo_list, &loop_devices);
>     return lo;
> 
> out_free_queue:
> @@ -1439,15 +1432,37 @@ out:
>     return NULL;
> }
> 
> -static void loop_del_one(struct loop_device *lo)
> +static void loop_free(struct loop_device *lo)
> {
> -    del_gendisk(lo->lo_disk);
>     blk_cleanup_queue(lo->lo_queue);
>     put_disk(lo->lo_disk);
>     list_del(&lo->lo_list);
>     kfree(lo);
> }
> 
> +static struct loop_device *loop_init_one(int i)
> +{
> +    struct loop_device *lo;
> +
> +    list_for_each_entry(lo, &loop_devices, lo_list) {
> +        if (lo->lo_number == i)
> +            return lo;
> +    }
> +
> +    lo = loop_alloc(i);
> +    if (lo) {
> +        add_disk(lo->lo_disk);
> +        list_add_tail(&lo->lo_list, &loop_devices);
> +    }
> +    return lo;
> +}
> +
> +static void loop_del_one(struct loop_device *lo)
> +{
> +    del_gendisk(lo->lo_disk);
> +    loop_free(lo);
> +}
> +
> static struct kobject *loop_probe(dev_t dev, int *part, void *data)
> {
>     struct loop_device *lo;
> @@ -1464,28 +1479,77 @@ static struct kobject *loop_probe
> 
> static int __init loop_init(void)
> {
> -    if (register_blkdev(LOOP_MAJOR, "loop"))
> -        return -EIO;
> -    blk_register_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS,
> -                  THIS_MODULE, loop_probe, NULL, NULL);
> +    int i, nr;
> +    unsigned long range;
> +    struct loop_device *lo, *next;
> +
> +    /*
> +     * loop module now has a feature to instantiate underlying device
> +     * structure on-demand, provided that there is an access dev node.
> +     * However, this will not work well with user space tool that doesn't
> +     * know about such "feature".  In order to not break any existing
> +     * tool, we do the following:
> +     *
> +     * (1) if max_loop is specified, create that many upfront, and this
> +     *     also becomes a hard limit.
> +     * (2) if max_loop is not specified, create 8 loop device on module
> +     *     load, user can further extend loop device by create dev node
> +     *     themselves and have kernel automatically instantiate actual
> +     *     device on-demand.
> +     */
> +    if (max_loop > 1UL << MINORBITS)
> +        return -EINVAL;
> 
>     if (max_loop) {
> -        printk(KERN_INFO "loop: the max_loop option is obsolete "
> -                 "and will be removed in March 2008\n");
> +        nr = max_loop;
> +        range = max_loop;
> +    } else {
> +        nr = 8;
> +        range = 1UL << MINORBITS;
> +    }
> +
> +    if (register_blkdev(LOOP_MAJOR, "loop"))
> +        return -EIO;
> 
> +    for (i = 0; i < nr; i++) {
> +        lo = loop_alloc(i);
> +        if (!lo)
> +            goto Enomem;
> +        list_add_tail(&lo->lo_list, &loop_devices);
>     }
> +
> +    /* point of no return */
> +
> +    list_for_each_entry(lo, &loop_devices, lo_list)
> +        add_disk(lo->lo_disk);
> +
> +    blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
> +                  THIS_MODULE, loop_probe, NULL, NULL);
> +
>     printk(KERN_INFO "loop: module loaded\n");
>     return 0;
> +
> +Enomem:
> +    printk(KERN_INFO "loop: out of memory\n");
> +
> +    list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
> +        loop_free(lo);
> +
> +    unregister_blkdev(LOOP_MAJOR, "loop");
> +    return -ENOMEM;
> }
> 
> static void __exit loop_exit(void)
> {
> +    unsigned long range;
>     struct loop_device *lo, *next;
> 
> +    range = max_loop ? max_loop :  1UL << MINORBITS;
> +
>     list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
>         loop_del_one(lo);
> 
> -    blk_unregister_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS);
> +    blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
>     if (unregister_blkdev(LOOP_MAJOR, "loop"))
>         printk(KERN_WARNING "loop: cannot unregister blkdev\n");
> }




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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-31 16:05           ` walt
@ 2007-05-31 16:51             ` Ken Chen
  2007-05-31 18:10               ` Andrew Morton
  0 siblings, 1 reply; 12+ messages in thread
From: Ken Chen @ 2007-05-31 16:51 UTC (permalink / raw)
  To: walt, Andrew Morton; +Cc: linux-kernel

On 5/31/07, walt <wa1ter@myrealbox.com> wrote:
> Ken Chen wrote:
> > On 5/21/07, Ken Chen <kenchen@google.com> wrote:
> ...
> > tested, like this?
>
> Ken, your patch below works for me.  Are you going to send this
> on to Linus?

I think akpm will route this to Linus.  andrew?

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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-31 16:51             ` Ken Chen
@ 2007-05-31 18:10               ` Andrew Morton
  2007-05-31 18:23                 ` Ken Chen
  0 siblings, 1 reply; 12+ messages in thread
From: Andrew Morton @ 2007-05-31 18:10 UTC (permalink / raw)
  To: Ken Chen; +Cc: walt, linux-kernel

On Thu, 31 May 2007 09:51:36 -0700
"Ken Chen" <kenchen@google.com> wrote:

> On 5/31/07, walt <wa1ter@myrealbox.com> wrote:
> > Ken Chen wrote:
> > > On 5/21/07, Ken Chen <kenchen@google.com> wrote:
> > ...
> > > tested, like this?
> >
> > Ken, your patch below works for me.  Are you going to send this
> > on to Linus?
> 
> I think akpm will route this to Linus.  andrew?

I have a note here that it needs additional work.  This discussion:

http://lkml.org/lkml/2007/5/21/602

seemed to peter out and go nowhere?

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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-31 18:10               ` Andrew Morton
@ 2007-05-31 18:23                 ` Ken Chen
  2007-05-31 18:34                   ` Andrew Morton
  0 siblings, 1 reply; 12+ messages in thread
From: Ken Chen @ 2007-05-31 18:23 UTC (permalink / raw)
  To: Andrew Morton; +Cc: walt, linux-kernel

On 5/31/07, Andrew Morton <akpm@linux-foundation.org> wrote:
> I have a note here that it needs additional work.  This discussion:
>
> http://lkml.org/lkml/2007/5/21/602
>
> seemed to peter out and go nowhere?

The first rev went in -mm needs work and the above url is the result
of feedback from Al Viro.  He also acked the patch in the follow on
thread:
http://lkml.org/lkml/2007/5/22/5

Not sure how widely it was tested on that last patch, I see a few
reports that the patch works out OK.

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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-31 18:23                 ` Ken Chen
@ 2007-05-31 18:34                   ` Andrew Morton
  2007-06-01 16:29                     ` Ken Chen
  0 siblings, 1 reply; 12+ messages in thread
From: Andrew Morton @ 2007-05-31 18:34 UTC (permalink / raw)
  To: Ken Chen; +Cc: walt, linux-kernel

On Thu, 31 May 2007 11:23:32 -0700
"Ken Chen" <kenchen@google.com> wrote:

> On 5/31/07, Andrew Morton <akpm@linux-foundation.org> wrote:
> > I have a note here that it needs additional work.  This discussion:
> >
> > http://lkml.org/lkml/2007/5/21/602
> >
> > seemed to peter out and go nowhere?
> 
> The first rev went in -mm needs work and the above url is the result
> of feedback from Al Viro.  He also acked the patch in the follow on
> thread:
> http://lkml.org/lkml/2007/5/22/5
> 
> Not sure how widely it was tested on that last patch, I see a few
> reports that the patch works out OK.

Could you please send a fresh, shiny, new, changelogged patch against mainline?

Thanks.

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

* Re: + loop-preallocate-eight-loop-devices.patch added to -mm tree
  2007-05-31 18:34                   ` Andrew Morton
@ 2007-06-01 16:29                     ` Ken Chen
  0 siblings, 0 replies; 12+ messages in thread
From: Ken Chen @ 2007-06-01 16:29 UTC (permalink / raw)
  To: Andrew Morton; +Cc: walt, linux-kernel

On 5/31/07, Andrew Morton <akpm@linux-foundation.org> wrote:
> Could you please send a fresh, shiny, new, changelogged patch against mainline?

OK, here it is.  It would be nice to merge this before final 2.6.22
release.  Thank you.


The kernel on-demand loop device instantiation breaks several user space
tools as the tools are not ready to cope with the "on-demand feature".  Fix
it by instantiate default 8 loop devices and also reinstate max_loop module
parameter.


Signed-off-by: Ken Chen <kenchen@google.com>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>


diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 5526ead..0ed5470 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1354,7 +1354,7 @@ #endif
  */
 static int max_loop;
 module_param(max_loop, int, 0);
-MODULE_PARM_DESC(max_loop, "obsolete, loop device is created on-demand");
+MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);

@@ -1394,16 +1394,11 @@ int loop_unregister_transfer
 EXPORT_SYMBOL(loop_register_transfer);
 EXPORT_SYMBOL(loop_unregister_transfer);

-static struct loop_device *loop_init_one(int i)
+static struct loop_device *loop_alloc(int i)
 {
 	struct loop_device *lo;
 	struct gendisk *disk;

-	list_for_each_entry(lo, &loop_devices, lo_list) {
-		if (lo->lo_number == i)
-			return lo;
-	}
-
 	lo = kzalloc(sizeof(*lo), GFP_KERNEL);
 	if (!lo)
 		goto out;
@@ -1427,8 +1422,6 @@ static struct loop_device *loop_init_one
 	disk->private_data	= lo;
 	disk->queue		= lo->lo_queue;
 	sprintf(disk->disk_name, "loop%d", i);
-	add_disk(disk);
-	list_add_tail(&lo->lo_list, &loop_devices);
 	return lo;

 out_free_queue:
@@ -1439,15 +1432,37 @@ out:
 	return NULL;
 }

-static void loop_del_one(struct loop_device *lo)
+static void loop_free(struct loop_device *lo)
 {
-	del_gendisk(lo->lo_disk);
 	blk_cleanup_queue(lo->lo_queue);
 	put_disk(lo->lo_disk);
 	list_del(&lo->lo_list);
 	kfree(lo);
 }

+static struct loop_device *loop_init_one(int i)
+{
+	struct loop_device *lo;
+
+	list_for_each_entry(lo, &loop_devices, lo_list) {
+		if (lo->lo_number == i)
+			return lo;
+	}
+
+	lo = loop_alloc(i);
+	if (lo) {
+		add_disk(lo->lo_disk);
+		list_add_tail(&lo->lo_list, &loop_devices);
+	}
+	return lo;
+}
+
+static void loop_del_one(struct loop_device *lo)
+{
+	del_gendisk(lo->lo_disk);
+	loop_free(lo);
+}
+
 static struct kobject *loop_probe(dev_t dev, int *part, void *data)
 {
 	struct loop_device *lo;
@@ -1464,28 +1479,77 @@ static struct kobject *loop_probe

 static int __init loop_init(void)
 {
-	if (register_blkdev(LOOP_MAJOR, "loop"))
-		return -EIO;
-	blk_register_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS,
-				  THIS_MODULE, loop_probe, NULL, NULL);
+	int i, nr;
+	unsigned long range;
+	struct loop_device *lo, *next;
+
+	/*
+	 * loop module now has a feature to instantiate underlying device
+	 * structure on-demand, provided that there is an access dev node.
+	 * However, this will not work well with user space tool that doesn't
+	 * know about such "feature".  In order to not break any existing
+	 * tool, we do the following:
+	 *
+	 * (1) if max_loop is specified, create that many upfront, and this
+	 *     also becomes a hard limit.
+	 * (2) if max_loop is not specified, create 8 loop device on module
+	 *     load, user can further extend loop device by create dev node
+	 *     themselves and have kernel automatically instantiate actual
+	 *     device on-demand.
+	 */
+	if (max_loop > 1UL << MINORBITS)
+		return -EINVAL;

 	if (max_loop) {
-		printk(KERN_INFO "loop: the max_loop option is obsolete "
-				 "and will be removed in March 2008\n");
+		nr = max_loop;
+		range = max_loop;
+	} else {
+		nr = 8;
+		range = 1UL << MINORBITS;
+	}
+
+	if (register_blkdev(LOOP_MAJOR, "loop"))
+		return -EIO;

+	for (i = 0; i < nr; i++) {
+		lo = loop_alloc(i);
+		if (!lo)
+			goto Enomem;
+		list_add_tail(&lo->lo_list, &loop_devices);
 	}
+
+	/* point of no return */
+
+	list_for_each_entry(lo, &loop_devices, lo_list)
+		add_disk(lo->lo_disk);
+
+	blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
+				  THIS_MODULE, loop_probe, NULL, NULL);
+
 	printk(KERN_INFO "loop: module loaded\n");
 	return 0;
+
+Enomem:
+	printk(KERN_INFO "loop: out of memory\n");
+
+	list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
+		loop_free(lo);
+
+	unregister_blkdev(LOOP_MAJOR, "loop");
+	return -ENOMEM;
 }

 static void __exit loop_exit(void)
 {
+	unsigned long range;
 	struct loop_device *lo, *next;

+	range = max_loop ? max_loop :  1UL << MINORBITS;
+
 	list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
 		loop_del_one(lo);

-	blk_unregister_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS);
+	blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
 	if (unregister_blkdev(LOOP_MAJOR, "loop"))
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 }

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

end of thread, other threads:[~2007-06-01 16:29 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <200705212200.l4LM0tYK021050@shell0.pdx.osdl.net>
2007-05-22  0:18 ` + loop-preallocate-eight-loop-devices.patch added to -mm tree Al Viro
2007-05-22  1:30   ` Ken Chen
2007-05-22  1:48     ` Al Viro
2007-05-22  2:14       ` Ken Chen
2007-05-22  2:40         ` Ken Chen
2007-05-22  4:18           ` Al Viro
2007-05-31 16:05           ` walt
2007-05-31 16:51             ` Ken Chen
2007-05-31 18:10               ` Andrew Morton
2007-05-31 18:23                 ` Ken Chen
2007-05-31 18:34                   ` Andrew Morton
2007-06-01 16:29                     ` Ken Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox