nfs: take i_mutex during direct I/O reads
authorChristoph Hellwig <hch@infradead.org>
Thu, 14 Nov 2013 16:50:33 +0000 (08:50 -0800)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 13 Jan 2014 22:29:50 +0000 (17:29 -0500)
We'll need the i_mutex to prevent i_dio_count from incrementing while
truncate is waiting for it to reach zero, and protects against having
the pagecache repopulated after we flushed it.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/direct.c

index cbfbd17..85e4e4b 100644 (file)
@@ -500,16 +500,17 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
        if (!count)
                goto out;
 
+       mutex_lock(&inode->i_mutex);
        result = nfs_sync_mapping(mapping);
        if (result)
-               goto out;
+               goto out_unlock;
 
        task_io_account_read(count);
 
        result = -ENOMEM;
        dreq = nfs_direct_req_alloc();
        if (dreq == NULL)
-               goto out;
+               goto out_unlock;
 
        dreq->inode = inode;
        dreq->bytes_left = iov_length(iov, nr_segs);
@@ -525,13 +526,22 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
 
        NFS_I(inode)->read_io += iov_length(iov, nr_segs);
        result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos, uio);
+
+       mutex_unlock(&inode->i_mutex);
+
        if (!result) {
                result = nfs_direct_wait(dreq);
                if (result > 0)
                        iocb->ki_pos = pos + result;
        }
+
+       nfs_direct_req_release(dreq);
+       return result;
+
 out_release:
        nfs_direct_req_release(dreq);
+out_unlock:
+       mutex_unlock(&inode->i_mutex);
 out:
        return result;
 }