On 3/30/07, Jan Engelhardt <[EMAIL PROTECTED]> wrote:
> lo->lo_device = NULL;
> lo->lo_backing_file = NULL;
> lo->lo_flags = 0;
> -     set_capacity(disks[lo->lo_number], 0);
> +     set_capacity(lo->lo_disk, 0);
> invalidate_bdev(bdev, 0);
> bd_set_size(bdev, 0);
> mapping_set_gfp_mask(mapping, lo->old_gfp_mask);

Welcome to Google Mail, we eat your whitespace :-)

Oh, crap.  Google mail is innocent.  It was me who did some ugly
copy-paste between apps.

> +     sprintf(disk->disk_name, "loop%d", i);

Let's make this %u, no?

I don't mind either way, this thing won't be bigger than 1^20 anyway.
Oh, which reminds me that we probably should explicitly test and cap
that limit (1^20 that is).

> +static struct kobject *loop_probe(dev_t dev, int *part, void *data)
> +{
> +     unsigned int number = dev & MINORMASK;
> +     struct loop_device *lo;
>
> -     for (i = 0; i < max_loop; i++) {
> -             disks[i] = alloc_disk(1);
> -             if (!disks[i])
> -                     goto out_mem3;
> -     }

Could not we use kobject_uevent(), like I did (though perhaps without
the k.oops), to make udev create a node?

Well, I go with a version that doesn't panic kernel, which is a
deciding factor here ;-)


Full patch attached.

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 6b5b642..1e87aea 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -77,9 +77,8 @@

#include <asm/uaccess.h>

-static int max_loop = 8;
-static struct loop_device *loop_dev;
-static struct gendisk **disks;
+static LIST_HEAD(loop_devices);
+static DEFINE_MUTEX(loop_devices_mutex);

/*
 * Transfer functions
@@ -183,7 +182,7 @@ figure_loop_size(struct loop_device *lo)
        if (unlikely((loff_t)x != size))
                return -EFBIG;

-       set_capacity(disks[lo->lo_number], x);
+       set_capacity(lo->lo_disk, x);
        return 0;                                       
}

@@ -812,7 +811,7 @@ static int loop_set_fd
        lo->lo_queue->queuedata = lo;
        lo->lo_queue->unplug_fn = loop_unplug;

-       set_capacity(disks[lo->lo_number], size);
+       set_capacity(lo->lo_disk, size);
        bd_set_size(bdev, size << 9);

        set_blocksize(bdev, lo_blocksize);
@@ -832,7 +831,7 @@ out_clr:
        lo->lo_device = NULL;
        lo->lo_backing_file = NULL;
        lo->lo_flags = 0;
-       set_capacity(disks[lo->lo_number], 0);
+       set_capacity(lo->lo_disk, 0);
        invalidate_bdev(bdev, 0);
        bd_set_size(bdev, 0);
        mapping_set_gfp_mask(mapping, lo->old_gfp_mask);
@@ -918,7 +917,7 @@ static int loop_clr_fd
        memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
        memset(lo->lo_file_name, 0, LO_NAME_SIZE);
        invalidate_bdev(bdev, 0);
-       set_capacity(disks[lo->lo_number], 0);
+       set_capacity(lo->lo_disk, 0);
        bd_set_size(bdev, 0);
        mapping_set_gfp_mask(filp->f_mapping, gfp);
        lo->lo_state = Lo_unbound;
@@ -1322,6 +1321,18 @@ static long lo_compat_ioctl
}
#endif

+static struct loop_device *loop_find_dev(int number)
+{
+       struct loop_device *lo;
+
+       list_for_each_entry(lo, &loop_devices, lo_list) {
+               if (lo->lo_number == number)
+                       return lo;
+       }
+       return NULL;
+}
+
+static struct loop_device *loop_init_one(int i);
static int lo_open(struct inode *inode, struct file *file)
{
        struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
@@ -1330,6 +1341,11 @@ static int lo_open
        lo->lo_refcnt++;
        mutex_unlock(&lo->lo_ctl_mutex);

+       mutex_lock(&loop_device_mutex);
+       if (!loop_find_dev(lo->lo_number + 1))
+               loop_init_one(lo->lo_number + 1);
+       mutex_unlock(&loop_device_mutex);
+
        return 0;
}

@@ -1357,8 +1373,6 @@ static struct block_device_operations lo_fops
/*
 * And now the modules code and kernel interface.
 */
-module_param(max_loop, int, 0);
-MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-256)");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);

@@ -1383,7 +1397,7 @@ int loop_unregister_transfer(int number)

        xfer_funcs[n] = NULL;

-       for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) {
+       list_for_each_entry(lo, &loop_devices, lo_list) {
                mutex_lock(&lo->lo_ctl_mutex);

                if (lo->lo_encryption == xfer)
@@ -1398,102 +1412,106 @@ int loop_unregister_transfer(int number)
EXPORT_SYMBOL(loop_register_transfer);
EXPORT_SYMBOL(loop_unregister_transfer);

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

-       if (max_loop < 1 || max_loop > 256) {
-               printk(KERN_WARNING "loop: invalid max_loop (must be between"
-                                   " 1 and 256), using default (8)\n");
-               max_loop = 8;
-       }
+       lo = kzalloc(sizeof(*lo), GFP_KERNEL);
+       if (!lo)
+               goto out;

-       if (register_blkdev(LOOP_MAJOR, "loop"))
-               return -EIO;
+       lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
+       if (!lo->lo_queue)
+               goto out_free_dev;
+
+       disk = lo->lo_disk = alloc_disk(1);
+       if (!disk)
+               goto out_free_queue;
+
+       mutex_init(&lo->lo_ctl_mutex);
+       lo->lo_number                = i;
+       lo->lo_thread                = NULL;
+       init_waitqueue_head(&lo->lo_event);
+       spin_lock_init(&lo->lo_lock);
+       disk->major          = LOOP_MAJOR;
+       disk->first_minor    = i;
+       disk->fops           = &lo_fops;
+       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:
+       blk_cleanup_queue(lo->lo_queue);
+out_free_dev:
+       kfree(lo);
+out:
+       return ERR_PTR(-ENOMEM);
+}

-       loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
-       if (!loop_dev)
-               goto out_mem1;
-       memset(loop_dev, 0, max_loop * sizeof(struct loop_device));
+static void loop_del_one(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);
+}

-       disks = kmalloc(max_loop * sizeof(struct gendisk *), GFP_KERNEL);
-       if (!disks)
-               goto out_mem2;
+static struct kobject *loop_probe(dev_t dev, int *part, void *data)
+{
+       unsigned int number = dev & MINORMASK;
+       struct loop_device *lo;

-       for (i = 0; i < max_loop; i++) {
-               disks[i] = alloc_disk(1);
-               if (!disks[i])
-                       goto out_mem3;
-       }
+       mutex_lock(&loop_device_mutex);
+       lo = loop_find_dev(number);
+       if (lo == NULL)
+               lo = loop_init_one(number);
+       mutex_unlock(&loop_device_mutex);

-       for (i = 0; i < max_loop; i++) {
-               struct loop_device *lo = &loop_dev[i];
-               struct gendisk *disk = disks[i];
-
-               memset(lo, 0, sizeof(*lo));
-               lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
-               if (!lo->lo_queue)
-                       goto out_mem4;
-               mutex_init(&lo->lo_ctl_mutex);
-               lo->lo_number = i;
-               lo->lo_thread = NULL;
-               init_waitqueue_head(&lo->lo_event);
-               spin_lock_init(&lo->lo_lock);
-               disk->major = LOOP_MAJOR;
-               disk->first_minor = i;
-               disk->fops = &lo_fops;
-               sprintf(disk->disk_name, "loop%d", i);
-               disk->private_data = lo;
-               disk->queue = lo->lo_queue;
-       }
+       *part = 0;
+       if (IS_ERR(lo))
+               return (void *)lo;
+       else
+               return &lo->lo_disk->kobj;
+}
+
+static int __init loop_init(void)
+{
+       struct loop_device *lo;
+
+       if (register_blkdev(LOOP_MAJOR, "loop"))
+               return -EIO;
+       blk_register_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS,
+                                 THIS_MODULE, loop_probe, NULL, NULL);

-       /* We cannot fail after we call this, so another loop!*/
-       for (i = 0; i < max_loop; i++)
-               add_disk(disks[i]);
-       printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
+       lo = loop_init_one(0);
+       if (IS_ERR(lo))
+               goto out_free;
+
+       printk(KERN_INFO "loop: loaded");
        return 0;

-out_mem4:
-       while (i--)
-               blk_cleanup_queue(loop_dev[i].lo_queue);
-       i = max_loop;
-out_mem3:
-       while (i--)
-               put_disk(disks[i]);
-       kfree(disks);
-out_mem2:
-       kfree(loop_dev);
-out_mem1:
+out_free:
        unregister_blkdev(LOOP_MAJOR, "loop");
        printk(KERN_ERR "loop: ran out of memory\n");
        return -ENOMEM;
}

-static void loop_exit(void)
+static void __exit loop_exit(void)
{
-       int i;
+       struct loop_device *lo, *next;

-       for (i = 0; i < max_loop; i++) {
-               del_gendisk(disks[i]);
-               blk_cleanup_queue(loop_dev[i].lo_queue);
-               put_disk(disks[i]);
-       }
+       list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
+               loop_del_one(lo);
+
+       blk_unregister_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS);
        if (unregister_blkdev(LOOP_MAJOR, "loop"))
                printk(KERN_WARNING "loop: cannot unregister blkdev\n");
-
-       kfree(disks);
-       kfree(loop_dev);
}

module_init(loop_init);
module_exit(loop_exit);
-
-#ifndef MODULE
-static int __init max_loop_setup(char *str)
-{
-       max_loop = simple_strtol(str, NULL, 0);
-       return 1;
-}
-
-__setup("max_loop=", max_loop_setup);
-#endif
diff --git a/include/linux/loop.h b/include/linux/loop.h
index 191a595..0b99b31 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -64,6 +64,8 @@ struct loop_device {
        wait_queue_head_t       lo_event;

        request_queue_t         *lo_queue;
+       struct gendisk          *lo_disk;
+       struct list_head        lo_list;
};

#endif /* __KERNEL__ */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to