]> git.ipfire.org Git - people/ms/linux.git/blobdiff - fs/direct-io.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[people/ms/linux.git] / fs / direct-io.c
index 18e7554cf94cac57d1eb3dc17ba4001e75cef5f6..1c75a3a07f8f02a2ddd3b85e02c74866ff5b1f08 100644 (file)
@@ -109,6 +109,8 @@ struct dio_submit {
 struct dio {
        int flags;                      /* doesn't change */
        int rw;
+       blk_qc_t bio_cookie;
+       struct block_device *bio_bdev;
        struct inode *inode;
        loff_t i_size;                  /* i_size when submitted */
        dio_iodone_t *end_io;           /* IO completion function */
@@ -397,11 +399,14 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio)
        if (dio->is_async && dio->rw == READ && dio->should_dirty)
                bio_set_pages_dirty(bio);
 
-       if (sdio->submit_io)
+       dio->bio_bdev = bio->bi_bdev;
+
+       if (sdio->submit_io) {
                sdio->submit_io(dio->rw, bio, dio->inode,
                               sdio->logical_offset_in_bio);
-       else
-               submit_bio(dio->rw, bio);
+               dio->bio_cookie = BLK_QC_T_NONE;
+       } else
+               dio->bio_cookie = submit_bio(dio->rw, bio);
 
        sdio->bio = NULL;
        sdio->boundary = 0;
@@ -440,7 +445,8 @@ static struct bio *dio_await_one(struct dio *dio)
                __set_current_state(TASK_UNINTERRUPTIBLE);
                dio->waiter = current;
                spin_unlock_irqrestore(&dio->bio_lock, flags);
-               io_schedule();
+               if (!blk_poll(bdev_get_queue(dio->bio_bdev), dio->bio_cookie))
+                       io_schedule();
                /* wake up sets us TASK_RUNNING */
                spin_lock_irqsave(&dio->bio_lock, flags);
                dio->waiter = NULL;
@@ -1163,6 +1169,15 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
                }
        }
 
+       /* Once we sampled i_size check for reads beyond EOF */
+       dio->i_size = i_size_read(inode);
+       if (iov_iter_rw(iter) == READ && offset >= dio->i_size) {
+               if (dio->flags & DIO_LOCKING)
+                       mutex_unlock(&inode->i_mutex);
+               kmem_cache_free(dio_cache, dio);
+               goto out;
+       }
+
        /*
         * For file extending writes updating i_size before data writeouts
         * complete can expose uninitialized blocks in dumb filesystems.
@@ -1216,7 +1231,6 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
        sdio.next_block_for_io = -1;
 
        dio->iocb = iocb;
-       dio->i_size = i_size_read(inode);
 
        spin_lock_init(&dio->bio_lock);
        dio->refcount = 1;