ext4: fix ext4_dax_read/write inode locking sequence for IOCB_NOWAIT
[platform/kernel/linux-rpi.git] / fs / block_dev.c
index 38b8ce0..c158bad 100644 (file)
@@ -104,6 +104,20 @@ void invalidate_bdev(struct block_device *bdev)
 }
 EXPORT_SYMBOL(invalidate_bdev);
 
+static void set_init_blocksize(struct block_device *bdev)
+{
+       unsigned bsize = bdev_logical_block_size(bdev);
+       loff_t size = i_size_read(bdev->bd_inode);
+
+       while (bsize < PAGE_SIZE) {
+               if (size & bsize)
+                       break;
+               bsize <<= 1;
+       }
+       bdev->bd_block_size = bsize;
+       bdev->bd_inode->i_blkbits = blksize_bits(bsize);
+}
+
 int set_blocksize(struct block_device *bdev, int size)
 {
        /* Size must be a power of two, and between 512 and PAGE_SIZE */
@@ -282,10 +296,10 @@ static void blkdev_bio_end_io(struct bio *bio)
        struct blkdev_dio *dio = bio->bi_private;
        bool should_dirty = dio->should_dirty;
 
-       if (dio->multi_bio && !atomic_dec_and_test(&dio->ref)) {
-               if (bio->bi_status && !dio->bio.bi_status)
-                       dio->bio.bi_status = bio->bi_status;
-       } else {
+       if (bio->bi_status && !dio->bio.bi_status)
+               dio->bio.bi_status = bio->bi_status;
+
+       if (!dio->multi_bio || atomic_dec_and_test(&dio->ref)) {
                if (!dio->is_sync) {
                        struct kiocb *iocb = dio->iocb;
                        ssize_t ret;
@@ -1314,11 +1328,7 @@ static void flush_disk(struct block_device *bdev, bool kill_dirty)
                       "resized disk %s\n",
                       bdev->bd_disk ? bdev->bd_disk->disk_name : "");
        }
-
-       if (!bdev->bd_disk)
-               return;
-       if (disk_part_scan_enabled(bdev->bd_disk))
-               bdev->bd_invalidated = 1;
+       bdev->bd_invalidated = 1;
 }
 
 /**
@@ -1408,23 +1418,27 @@ EXPORT_SYMBOL(check_disk_change);
 
 void bd_set_size(struct block_device *bdev, loff_t size)
 {
-       unsigned bsize = bdev_logical_block_size(bdev);
-
        inode_lock(bdev->bd_inode);
        i_size_write(bdev->bd_inode, size);
        inode_unlock(bdev->bd_inode);
-       while (bsize < PAGE_SIZE) {
-               if (size & bsize)
-                       break;
-               bsize <<= 1;
-       }
-       bdev->bd_block_size = bsize;
-       bdev->bd_inode->i_blkbits = blksize_bits(bsize);
 }
 EXPORT_SYMBOL(bd_set_size);
 
 static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part);
 
+static void bdev_disk_changed(struct block_device *bdev, bool invalidate)
+{
+       if (disk_part_scan_enabled(bdev->bd_disk)) {
+               if (invalidate)
+                       invalidate_partitions(bdev->bd_disk, bdev);
+               else
+                       rescan_partitions(bdev->bd_disk, bdev);
+       } else {
+               check_disk_size_change(bdev->bd_disk, bdev, !invalidate);
+               bdev->bd_invalidated = 0;
+       }
+}
+
 /*
  * bd_mutex locking:
  *
@@ -1496,8 +1510,10 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                                }
                        }
 
-                       if (!ret)
+                       if (!ret) {
                                bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);
+                               set_init_blocksize(bdev);
+                       }
 
                        /*
                         * If the device is invalidated, rescan partition
@@ -1505,12 +1521,9 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                         * The latter is necessary to prevent ghost
                         * partitions on a removed medium.
                         */
-                       if (bdev->bd_invalidated) {
-                               if (!ret)
-                                       rescan_partitions(disk, bdev);
-                               else if (ret == -ENOMEDIUM)
-                                       invalidate_partitions(disk, bdev);
-                       }
+                       if (bdev->bd_invalidated &&
+                           (!ret || ret == -ENOMEDIUM))
+                               bdev_disk_changed(bdev, ret == -ENOMEDIUM);
 
                        if (ret)
                                goto out_clear;
@@ -1532,6 +1545,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                                goto out_clear;
                        }
                        bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9);
+                       set_init_blocksize(bdev);
                }
 
                if (bdev->bd_bdi == &noop_backing_dev_info)
@@ -1542,12 +1556,9 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                        if (bdev->bd_disk->fops->open)
                                ret = bdev->bd_disk->fops->open(bdev, mode);
                        /* the same as first opener case, read comment there */
-                       if (bdev->bd_invalidated) {
-                               if (!ret)
-                                       rescan_partitions(bdev->bd_disk, bdev);
-                               else if (ret == -ENOMEDIUM)
-                                       invalidate_partitions(bdev->bd_disk, bdev);
-                       }
+                       if (bdev->bd_invalidated &&
+                           (!ret || ret == -ENOMEDIUM))
+                               bdev_disk_changed(bdev, ret == -ENOMEDIUM);
                        if (ret)
                                goto out_unlock_bdev;
                }