Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / fs / nfs / direct.c
index c7326c2..72b7d13 100644 (file)
@@ -196,6 +196,12 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq,
        WARN_ON_ONCE(verfp->committed < 0);
 }
 
+static int nfs_direct_cmp_verf(const struct nfs_writeverf *v1,
+               const struct nfs_writeverf *v2)
+{
+       return nfs_write_verifier_cmp(&v1->verifier, &v2->verifier);
+}
+
 /*
  * nfs_direct_cmp_hdr_verf - compare verifier for pgio header
  * @dreq - direct request possibly spanning multiple servers
@@ -215,7 +221,7 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq,
                nfs_direct_set_hdr_verf(dreq, hdr);
                return 0;
        }
-       return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
+       return nfs_direct_cmp_verf(verfp, &hdr->verf);
 }
 
 /*
@@ -238,15 +244,13 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
        if (verfp->committed < 0)
                return 1;
 
-       return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf));
+       return nfs_direct_cmp_verf(verfp, &data->verf);
 }
 
 /**
  * nfs_direct_IO - NFS address space operation for direct I/O
  * @iocb: target I/O control block
- * @iov: array of vectors that define I/O buffer
- * @pos: offset in file to begin the operation
- * @nr_segs: size of iovec array
+ * @iter: I/O buffer
  *
  * The presence of this routine in the address space ops vector means
  * the NFS client supports direct I/O. However, for most direct IO, we
@@ -368,22 +372,10 @@ out:
  * Synchronous I/O uses a stack-allocated iocb.  Thus we can't trust
  * the iocb is still valid here if this is a synchronous request.
  */
-static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write)
+static void nfs_direct_complete(struct nfs_direct_req *dreq)
 {
        struct inode *inode = dreq->inode;
 
-       if (dreq->iocb && write) {
-               loff_t pos = dreq->iocb->ki_pos + dreq->count;
-
-               spin_lock(&inode->i_lock);
-               if (i_size_read(inode) < pos)
-                       i_size_write(inode, pos);
-               spin_unlock(&inode->i_lock);
-       }
-
-       if (write)
-               nfs_zap_mapping(inode, inode->i_mapping);
-
        inode_dio_end(inode);
 
        if (dreq->iocb) {
@@ -438,7 +430,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
        }
 out_put:
        if (put_dreq(dreq))
-               nfs_direct_complete(dreq, false);
+               nfs_direct_complete(dreq);
        hdr->release(hdr);
 }
 
@@ -544,7 +536,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
        }
 
        if (put_dreq(dreq))
-               nfs_direct_complete(dreq, false);
+               nfs_direct_complete(dreq);
        return 0;
 }
 
@@ -585,17 +577,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
        if (!count)
                goto out;
 
-       inode_lock(inode);
-       result = nfs_sync_mapping(mapping);
-       if (result)
-               goto out_unlock;
-
        task_io_account_read(count);
 
        result = -ENOMEM;
        dreq = nfs_direct_req_alloc();
        if (dreq == NULL)
-               goto out_unlock;
+               goto out;
 
        dreq->inode = inode;
        dreq->bytes_left = dreq->max_count = count;
@@ -610,10 +597,12 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
+       nfs_start_io_direct(inode);
+
        NFS_I(inode)->read_io += count;
        result = nfs_direct_read_schedule_iovec(dreq, iter, iocb->ki_pos);
 
-       inode_unlock(inode);
+       nfs_end_io_direct(inode);
 
        if (!result) {
                result = nfs_direct_wait(dreq);
@@ -621,13 +610,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter)
                        iocb->ki_pos += result;
        }
 
-       nfs_direct_req_release(dreq);
-       return result;
-
 out_release:
        nfs_direct_req_release(dreq);
-out_unlock:
-       inode_unlock(inode);
 out:
        return result;
 }
@@ -659,6 +643,8 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
        nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo);
 
        dreq->count = 0;
+       dreq->verf.committed = NFS_INVALID_STABLE_HOW;
+       nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo);
        for (i = 0; i < dreq->mirror_count; i++)
                dreq->mirrors[i].count = 0;
        get_dreq(dreq);
@@ -777,7 +763,8 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)
                        nfs_direct_write_reschedule(dreq);
                        break;
                default:
-                       nfs_direct_complete(dreq, true);
+                       nfs_zap_mapping(dreq->inode, dreq->inode->i_mapping);
+                       nfs_direct_complete(dreq);
        }
 }
 
@@ -993,6 +980,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
 ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
 {
        ssize_t result = -EINVAL;
+       size_t count;
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = mapping->host;
@@ -1003,34 +991,24 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
        dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n",
                file, iov_iter_count(iter), (long long) iocb->ki_pos);
 
-       nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES,
-                     iov_iter_count(iter));
+       result = generic_write_checks(iocb, iter);
+       if (result <= 0)
+               return result;
+       count = result;
+       nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);
 
        pos = iocb->ki_pos;
        end = (pos + iov_iter_count(iter) - 1) >> PAGE_SHIFT;
 
-       inode_lock(inode);
-
-       result = nfs_sync_mapping(mapping);
-       if (result)
-               goto out_unlock;
-
-       if (mapping->nrpages) {
-               result = invalidate_inode_pages2_range(mapping,
-                                       pos >> PAGE_SHIFT, end);
-               if (result)
-                       goto out_unlock;
-       }
-
-       task_io_account_write(iov_iter_count(iter));
+       task_io_account_write(count);
 
        result = -ENOMEM;
        dreq = nfs_direct_req_alloc();
        if (!dreq)
-               goto out_unlock;
+               goto out;
 
        dreq->inode = inode;
-       dreq->bytes_left = dreq->max_count = iov_iter_count(iter);
+       dreq->bytes_left = dreq->max_count = count;
        dreq->io_start = pos;
        dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
        l_ctx = nfs_get_lock_context(dreq->ctx);
@@ -1042,6 +1020,8 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
+       nfs_start_io_direct(inode);
+
        result = nfs_direct_write_schedule_iovec(dreq, iter, pos);
 
        if (mapping->nrpages) {
@@ -1049,30 +1029,19 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter)
                                              pos >> PAGE_SHIFT, end);
        }
 
-       inode_unlock(inode);
+       nfs_end_io_direct(inode);
 
        if (!result) {
                result = nfs_direct_wait(dreq);
                if (result > 0) {
-                       struct inode *inode = mapping->host;
-
                        iocb->ki_pos = pos + result;
-                       spin_lock(&inode->i_lock);
-                       if (i_size_read(inode) < iocb->ki_pos)
-                               i_size_write(inode, iocb->ki_pos);
-                       spin_unlock(&inode->i_lock);
-
                        /* XXX: should check the generic_write_sync retval */
                        generic_write_sync(iocb, result);
                }
        }
-       nfs_direct_req_release(dreq);
-       return result;
-
 out_release:
        nfs_direct_req_release(dreq);
-out_unlock:
-       inode_unlock(inode);
+out:
        return result;
 }