PATCH: variable number of loopback devices

Russell Kroll (rkroll@exploits.org)
Mon, 9 Aug 1999 00:32:17 -0600


For a project at work involving CD towers that mount iso9660 images via
the /dev/loop* devices, I hit a limit in the kernel of 8. This was set
with a #define, but changing that line every time the kernel was upgraded
proved to be annoying. 8 makes sense since it keeps the array size down
for most users, but some situations demand much more capacity than that.

Here's a patch that will allow the use of "max_loop=n" as a parameter when
loading as a module. If you don't specify a number or compile it into the
kernel monolithically, the limit remains at 8 as before.

This patch has been tested by nailing it with many mount/umount operations
and reading/writing data on the looped filesystems while they were
mounted. At the top end of the limit, you actually hit a "too many
filesystems mounted" wall by default, but a sysctl tweak fixes that.

Max filesystem count aside, having more than 256 loop mounts will require
some interesting changes due to the major/minor situation. Hopefully my
users won't try to load that many images onto one box in the meantime.

--- linux/drivers/block/loop-orig.c Wed Aug 4 11:40:50 1999
+++ linux/drivers/block/loop.c Wed Aug 4 11:42:18 1999
@@ -21,6 +21,10 @@
* Make real block number available to downstream transfer functions, enables
* CBC (and relatives) mode encryption requiring unique IVs per data block.
* Reed H. Petty, rhp@draper.net
+ *
+ * Maximum number of loop devices now dynamic via max_loop module parameter.
+ * Still fixed at 8 devices when compiled into the kernel normally.
+ * Russell Kroll <rkroll@exploits.org> 19990701
*
* Still To Fix:
* - Advisory locking is ignored here.
@@ -61,10 +65,11 @@
#define TIMEOUT_VALUE (6 * HZ)
#include <linux/blk.h>

-#define MAX_LOOP 8
-static struct loop_device loop_dev[MAX_LOOP];
-static int loop_sizes[MAX_LOOP];
-static int loop_blksizes[MAX_LOOP];
+#include <linux/malloc.h>
+static int max_loop = 8;
+static struct loop_device *loop_dev;
+static int *loop_sizes;
+static int *loop_blksizes;

#define FALSE 0
#define TRUE (!FALSE)
@@ -169,7 +174,7 @@
INIT_REQUEST;
current_request=CURRENT;
CURRENT=current_request->next;
- if (MINOR(current_request->rq_dev) >= MAX_LOOP)
+ if (MINOR(current_request->rq_dev) >= max_loop)
goto error_out;
lo = &loop_dev[MINOR(current_request->rq_dev)];
if (!lo->lo_dentry || !lo->transfer)
@@ -578,7 +583,7 @@
return -ENODEV;
}
dev = MINOR(inode->i_rdev);
- if (dev >= MAX_LOOP)
+ if (dev >= max_loop)
return -ENODEV;
lo = &loop_dev[dev];
switch (cmd) {
@@ -615,7 +620,7 @@
return -ENODEV;
}
dev = MINOR(inode->i_rdev);
- if (dev >= MAX_LOOP) {
+ if (dev >= max_loop) {
return -ENODEV;
}
lo = &loop_dev[dev];
@@ -640,7 +645,7 @@
return 0;
}
dev = MINOR(inode->i_rdev);
- if (dev >= MAX_LOOP)
+ if (dev >= max_loop)
return 0;
err = fsync_dev(inode->i_rdev);
lo = &loop_dev[dev];
@@ -674,6 +679,8 @@
*/
#ifdef MODULE
#define loop_init init_module
+MODULE_PARM(max_loop, "i");
+MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)");
#endif

int loop_register_transfer(struct loop_func_table *funcs)
@@ -690,7 +697,7 @@

if ((unsigned)number >= MAX_LO_CRYPT)
return -EINVAL;
- for (lo = &loop_dev[0]; lo < &loop_dev[MAX_LOOP]; lo++) {
+ for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) {
int type = lo->lo_encrypt_type;
if (type == number) {
xfer_funcs[type]->release(lo);
@@ -714,17 +721,46 @@
MAJOR_NR);
return -EIO;
}
+
+ if ((max_loop < 1) || (max_loop > 255)) {
+ printk (KERN_WARNING "loop: max_loop must be between 1 and 255\n");
+ return -EINVAL;
+ }
+
#ifndef MODULE
printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR);
+#else
+ printk(KERN_INFO "loop: enabling %d loop devices\n", max_loop);
#endif

+ loop_dev = kmalloc (max_loop * sizeof(struct loop_device), GFP_KERNEL);
+ if (!loop_dev) {
+ printk (KERN_ERR "loop: Unable to create loop_dev\n");
+ return -ENOMEM;
+ }
+
+ loop_sizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL);
+ if (!loop_sizes) {
+ printk (KERN_ERR "loop: Unable to create loop_sizes\n");
+ kfree (loop_dev);
+ return -ENOMEM;
+ }
+
+ loop_blksizes = kmalloc (max_loop * sizeof(int), GFP_KERNEL);
+ if (!loop_blksizes) {
+ printk (KERN_ERR "loop: Unable to create loop_blksizes\n");
+ kfree (loop_dev);
+ kfree (loop_sizes);
+ return -ENOMEM;
+ }
+
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- for (i=0; i < MAX_LOOP; i++) {
+ for (i=0; i < max_loop; i++) {
memset(&loop_dev[i], 0, sizeof(struct loop_device));
loop_dev[i].lo_number = i;
}
- memset(&loop_sizes, 0, sizeof(loop_sizes));
- memset(&loop_blksizes, 0, sizeof(loop_blksizes));
+ memset(loop_sizes, 0, max_loop * sizeof(int));
+ memset(loop_blksizes, 0, max_loop * sizeof(int));
blk_size[MAJOR_NR] = loop_sizes;
blksize_size[MAJOR_NR] = loop_blksizes;

@@ -736,5 +772,9 @@
{
if (unregister_blkdev(MAJOR_NR, "loop") != 0)
printk(KERN_WARNING "loop: cannot unregister blkdev\n");
+
+ kfree (loop_dev);
+ kfree (loop_sizes);
+ kfree (loop_blksizes);
}
#endif

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