Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target...
[cascardo/linux.git] / drivers / block / loop.c
index f47dccb..747bb2a 100644 (file)
@@ -162,12 +162,13 @@ static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = {
 
 static loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file)
 {
-       loff_t size, loopsize;
+       loff_t loopsize;
 
        /* Compute loopsize in bytes */
-       size = i_size_read(file->f_mapping->host);
-       loopsize = size - offset;
-       /* offset is beyond i_size, wierd but possible */
+       loopsize = i_size_read(file->f_mapping->host);
+       if (offset > 0)
+               loopsize -= offset;
+       /* offset is beyond i_size, weird but possible */
        if (loopsize < 0)
                return 0;
 
@@ -190,6 +191,7 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
 {
        loff_t size = get_size(offset, sizelimit, lo->lo_backing_file);
        sector_t x = (sector_t)size;
+       struct block_device *bdev = lo->lo_device;
 
        if (unlikely((loff_t)x != size))
                return -EFBIG;
@@ -198,6 +200,9 @@ figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
        if (lo->lo_sizelimit != sizelimit)
                lo->lo_sizelimit = sizelimit;
        set_capacity(lo->lo_disk, x);
+       bd_set_size(bdev, (loff_t)get_capacity(bdev->bd_disk) << 9);
+       /* let user-space know about the new size */
+       kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
        return 0;
 }
 
@@ -1091,10 +1096,10 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
                return err;
 
        if (lo->lo_offset != info->lo_offset ||
-           lo->lo_sizelimit != info->lo_sizelimit) {
+           lo->lo_sizelimit != info->lo_sizelimit)
                if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit))
                        return -EFBIG;
-       }
+
        loop_config_discard(lo);
 
        memcpy(lo->lo_file_name, info->lo_file_name, LO_NAME_SIZE);
@@ -1271,28 +1276,10 @@ loop_get_status64(struct loop_device *lo, struct loop_info64 __user *arg) {
 
 static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
 {
-       int err;
-       sector_t sec;
-       loff_t sz;
-
-       err = -ENXIO;
        if (unlikely(lo->lo_state != Lo_bound))
-               goto out;
-       err = figure_loop_size(lo, lo->lo_offset, lo->lo_sizelimit);
-       if (unlikely(err))
-               goto out;
-       sec = get_capacity(lo->lo_disk);
-       /* the width of sector_t may be narrow for bit-shift */
-       sz = sec;
-       sz <<= 9;
-       mutex_lock(&bdev->bd_mutex);
-       bd_set_size(bdev, sz);
-       /* let user-space know about the new size */
-       kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
-       mutex_unlock(&bdev->bd_mutex);
+               return -ENXIO;
 
- out:
-       return err;
+       return figure_loop_size(lo, lo->lo_offset, lo->lo_sizelimit);
 }
 
 static int lo_ioctl(struct block_device *bdev, fmode_t mode,
@@ -1845,11 +1832,15 @@ static int __init loop_init(void)
                max_part = (1UL << part_shift) - 1;
        }
 
-       if ((1UL << part_shift) > DISK_MAX_PARTS)
-               return -EINVAL;
+       if ((1UL << part_shift) > DISK_MAX_PARTS) {
+               err = -EINVAL;
+               goto misc_out;
+       }
 
-       if (max_loop > 1UL << (MINORBITS - part_shift))
-               return -EINVAL;
+       if (max_loop > 1UL << (MINORBITS - part_shift)) {
+               err = -EINVAL;
+               goto misc_out;
+       }
 
        /*
         * If max_loop is specified, create that many devices upfront.
@@ -1867,8 +1858,10 @@ static int __init loop_init(void)
                range = 1UL << MINORBITS;
        }
 
-       if (register_blkdev(LOOP_MAJOR, "loop"))
-               return -EIO;
+       if (register_blkdev(LOOP_MAJOR, "loop")) {
+               err = -EIO;
+               goto misc_out;
+       }
 
        blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
                                  THIS_MODULE, loop_probe, NULL, NULL);
@@ -1881,6 +1874,10 @@ static int __init loop_init(void)
 
        printk(KERN_INFO "loop: module loaded\n");
        return 0;
+
+misc_out:
+       misc_deregister(&loop_misc);
+       return err;
 }
 
 static int loop_exit_cb(int id, void *ptr, void *data)