X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fblock%2Floop.c;h=3efc2ea7ad64395b71a41da99ca0ab7f3edfea4a;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=f1250943c167f52700fcb5086380d7a117ecab2c;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f1250943c..3efc2ea7a 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -47,7 +47,7 @@ #include #include - +#include #include #include #include @@ -293,7 +293,7 @@ lo_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset, unsigned long size) { unsigned long count = desc->count; - struct lo_read_data *p = (struct lo_read_data*)desc->buf; + struct lo_read_data *p = desc->arg.data; struct loop_device *lo = p->lo; sector_t IV; @@ -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);