btrfs: handle transaction start error in btrfs_fileattr_set
[linux-2.6-microblaze.git] / fs / block_dev.c
index 4aa1f88..b8abccd 100644 (file)
@@ -79,7 +79,7 @@ static void kill_bdev(struct block_device *bdev)
 {
        struct address_space *mapping = bdev->bd_inode->i_mapping;
 
-       if (mapping->nrpages == 0 && mapping->nrexceptional == 0)
+       if (mapping_empty(mapping))
                return;
 
        invalidate_bh_lrus();
@@ -118,13 +118,22 @@ int truncate_bdev_range(struct block_device *bdev, fmode_t mode,
        if (!(mode & FMODE_EXCL)) {
                int err = bd_prepare_to_claim(bdev, truncate_bdev_range);
                if (err)
-                       return err;
+                       goto invalidate;
        }
 
        truncate_inode_pages_range(bdev->bd_inode->i_mapping, lstart, lend);
        if (!(mode & FMODE_EXCL))
                bd_abort_claiming(bdev, truncate_bdev_range);
        return 0;
+
+invalidate:
+       /*
+        * Someone else has handle exclusively open. Try invalidating instead.
+        * The 'end' argument is inclusive so the rounding is safe.
+        */
+       return invalidate_inode_pages2_range(bdev->bd_inode->i_mapping,
+                                            lstart >> PAGE_SHIFT,
+                                            lend >> PAGE_SHIFT);
 }
 
 static void set_init_blocksize(struct block_device *bdev)
@@ -266,6 +275,8 @@ __blkdev_direct_IO_simple(struct kiocb *iocb, struct iov_iter *iter,
                bio.bi_opf = dio_bio_write_op(iocb);
                task_io_account_write(ret);
        }
+       if (iocb->ki_flags & IOCB_NOWAIT)
+               bio.bi_opf |= REQ_NOWAIT;
        if (iocb->ki_flags & IOCB_HIPRI)
                bio_set_polled(&bio, iocb);
 
@@ -419,11 +430,13 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
                        bio->bi_opf = dio_bio_write_op(iocb);
                        task_io_account_write(bio->bi_iter.bi_size);
                }
+               if (iocb->ki_flags & IOCB_NOWAIT)
+                       bio->bi_opf |= REQ_NOWAIT;
 
                dio->size += bio->bi_iter.bi_size;
                pos += bio->bi_iter.bi_size;
 
-               nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_PAGES);
+               nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS);
                if (!nr_pages) {
                        bool polled = false;
 
@@ -491,8 +504,8 @@ blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        if (!iov_iter_count(iter))
                return 0;
 
-       nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_PAGES + 1);
-       if (is_sync_kiocb(iocb) && nr_pages <= BIO_MAX_PAGES)
+       nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS + 1);
+       if (is_sync_kiocb(iocb) && nr_pages <= BIO_MAX_VECS)
                return __blkdev_direct_IO_simple(iocb, iter, nr_pages);
 
        return __blkdev_direct_IO(iocb, iter, bio_max_segs(nr_pages));
@@ -1227,16 +1240,18 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part);
 int bdev_disk_changed(struct block_device *bdev, bool invalidate)
 {
        struct gendisk *disk = bdev->bd_disk;
-       int ret;
+       int ret = 0;
 
        lockdep_assert_held(&bdev->bd_mutex);
 
-       clear_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state);
-
 rescan:
-       ret = blk_drop_partitions(bdev);
-       if (ret)
-               return ret;
+       if (bdev->bd_part_count)
+               return -EBUSY;
+       sync_blockdev(bdev);
+       invalidate_bdev(bdev);
+       blk_drop_partitions(disk);
+
+       clear_bit(GD_NEED_PART_SCAN, &disk->state);
 
        /*
         * Historically we only set the capacity to zero for devices that
@@ -1250,9 +1265,6 @@ rescan:
                if (disk_part_scan_enabled(disk) ||
                    !(disk->flags & GENHD_FL_REMOVABLE))
                        set_capacity(disk, 0);
-       } else {
-               if (disk->fops->revalidate_disk)
-                       disk->fops->revalidate_disk(disk);
        }
 
        if (get_capacity(disk)) {
@@ -1424,10 +1436,6 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
        if (ret)
                return ERR_PTR(ret);
 
-       /*
-        * If we lost a race with 'disk' being deleted, try again.  See md.c.
-        */
-retry:
        bdev = blkdev_get_no_open(dev);
        if (!bdev)
                return ERR_PTR(-ENXIO);
@@ -1474,8 +1482,6 @@ abort_claiming:
        disk_unblock_events(disk);
 put_blkdev:
        blkdev_put_no_open(bdev);
-       if (ret == -ERESTARTSYS)
-               goto retry;
        return ERR_PTR(ret);
 }
 EXPORT_SYMBOL(blkdev_get_by_dev);
@@ -1671,6 +1677,7 @@ ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
        struct inode *bd_inode = bdev_file_inode(file);
        loff_t size = i_size_read(bd_inode);
        struct blk_plug plug;
+       size_t shorted = 0;
        ssize_t ret;
 
        if (bdev_read_only(I_BDEV(bd_inode)))
@@ -1688,12 +1695,17 @@ ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
        if ((iocb->ki_flags & (IOCB_NOWAIT | IOCB_DIRECT)) == IOCB_NOWAIT)
                return -EOPNOTSUPP;
 
-       iov_iter_truncate(from, size - iocb->ki_pos);
+       size -= iocb->ki_pos;
+       if (iov_iter_count(from) > size) {
+               shorted = iov_iter_count(from) - size;
+               iov_iter_truncate(from, size);
+       }
 
        blk_start_plug(&plug);
        ret = __generic_file_write_iter(iocb, from);
        if (ret > 0)
                ret = generic_write_sync(iocb, ret);
+       iov_iter_reexpand(from, iov_iter_count(from) + shorted);
        blk_finish_plug(&plug);
        return ret;
 }
@@ -1705,13 +1717,21 @@ ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
        struct inode *bd_inode = bdev_file_inode(file);
        loff_t size = i_size_read(bd_inode);
        loff_t pos = iocb->ki_pos;
+       size_t shorted = 0;
+       ssize_t ret;
 
        if (pos >= size)
                return 0;
 
        size -= pos;
-       iov_iter_truncate(to, size);
-       return generic_file_read_iter(iocb, to);
+       if (iov_iter_count(to) > size) {
+               shorted = iov_iter_count(to) - size;
+               iov_iter_truncate(to, size);
+       }
+
+       ret = generic_file_read_iter(iocb, to);
+       iov_iter_reexpand(to, iov_iter_count(to) + shorted);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(blkdev_read_iter);