loop: preallocate eight loop devices
authorKen Chen <kenchen@google.com>
Fri, 8 Jun 2007 20:46:44 +0000 (13:46 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Sat, 9 Jun 2007 00:23:32 +0000 (17:23 -0700)
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>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/block/loop.c

index 5526ead..0ed5470 100644 (file)
@@ -1354,7 +1354,7 @@ static struct block_device_operations lo_fops = {
  */
 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(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,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(dev_t dev, int *part, void *data)
 
 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");
 }