vserver 1.9.5.x5
[linux-2.6.git] / drivers / block / loop.c
index 9467429..3efc2ea 100644 (file)
@@ -47,7 +47,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-
+#include <linux/moduleparam.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/file.h>
@@ -622,10 +622,17 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
        return error;
 }
 
+static inline int is_loop_device(struct file *file)
+{
+       struct inode *i = file->f_mapping->host;
+
+       return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR;
+}
+
 static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
                       struct block_device *bdev, unsigned int arg)
 {
-       struct file     *file;
+       struct file     *file, *f;
        struct inode    *inode;
        struct address_space *mapping;
        unsigned lo_blocksize;
@@ -636,15 +643,31 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
        /* This is safe, since we have a reference from open(). */
        __module_get(THIS_MODULE);
 
-       error = -EBUSY;
-       if (lo->lo_state != Lo_unbound)
-               goto out;
-
        error = -EBADF;
        file = fget(arg);
        if (!file)
                goto out;
 
+       error = -EBUSY;
+       if (lo->lo_state != Lo_unbound)
+               goto out_putf;
+
+       /* Avoid recursion */
+       f = file;
+       while (is_loop_device(f)) {
+               struct loop_device *l;
+
+               if (f->f_mapping->host->i_rdev == lo_file->f_mapping->host->i_rdev)
+                       goto out_putf;
+
+               l = f->f_mapping->host->i_bdev->bd_disk->private_data;
+               if (l->lo_state == Lo_unbound) {
+                       error = -EINVAL;
+                       goto out_putf;
+               }
+               f = l->lo_backing_file;
+       }
+
        mapping = file->f_mapping;
        inode = mapping->host;
 
@@ -1073,7 +1096,7 @@ static struct block_device_operations lo_fops = {
 /*
  * And now the modules code and kernel interface.
  */
-MODULE_PARM(max_loop, "i");
+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);