]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/nfs/direct.c
Merge tag 'nfs-for-3.16-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[karo-tx-linux.git] / fs / nfs / direct.c
index b8797ae6831ff3e1be4c4b3f85c2c38e34252498..4ad7bc3886791b0078ebc3ae4b326ed5e4c6566b 100644 (file)
@@ -108,6 +108,97 @@ static inline int put_dreq(struct nfs_direct_req *dreq)
        return atomic_dec_and_test(&dreq->io_count);
 }
 
+/*
+ * nfs_direct_select_verf - select the right verifier
+ * @dreq - direct request possibly spanning multiple servers
+ * @ds_clp - nfs_client of data server or NULL if MDS / non-pnfs
+ * @ds_idx - index of data server in data server list, only valid if ds_clp set
+ *
+ * returns the correct verifier to use given the role of the server
+ */
+static struct nfs_writeverf *
+nfs_direct_select_verf(struct nfs_direct_req *dreq,
+                      struct nfs_client *ds_clp,
+                      int ds_idx)
+{
+       struct nfs_writeverf *verfp = &dreq->verf;
+
+#ifdef CONFIG_NFS_V4_1
+       if (ds_clp) {
+               /* pNFS is in use, use the DS verf */
+               if (ds_idx >= 0 && ds_idx < dreq->ds_cinfo.nbuckets)
+                       verfp = &dreq->ds_cinfo.buckets[ds_idx].direct_verf;
+               else
+                       WARN_ON_ONCE(1);
+       }
+#endif
+       return verfp;
+}
+
+
+/*
+ * nfs_direct_set_hdr_verf - set the write/commit verifier
+ * @dreq - direct request possibly spanning multiple servers
+ * @hdr - pageio header to validate against previously seen verfs
+ *
+ * Set the server's (MDS or DS) "seen" verifier
+ */
+static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq,
+                                   struct nfs_pgio_header *hdr)
+{
+       struct nfs_writeverf *verfp;
+
+       verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp,
+                                     hdr->data->ds_idx);
+       WARN_ON_ONCE(verfp->committed >= 0);
+       memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
+       WARN_ON_ONCE(verfp->committed < 0);
+}
+
+/*
+ * nfs_direct_cmp_hdr_verf - compare verifier for pgio header
+ * @dreq - direct request possibly spanning multiple servers
+ * @hdr - pageio header to validate against previously seen verf
+ *
+ * set the server's "seen" verf if not initialized.
+ * returns result of comparison between @hdr->verf and the "seen"
+ * verf of the server used by @hdr (DS or MDS)
+ */
+static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq,
+                                         struct nfs_pgio_header *hdr)
+{
+       struct nfs_writeverf *verfp;
+
+       verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp,
+                                        hdr->data->ds_idx);
+       if (verfp->committed < 0) {
+               nfs_direct_set_hdr_verf(dreq, hdr);
+               return 0;
+       }
+       return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
+}
+
+#if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4)
+/*
+ * nfs_direct_cmp_commit_data_verf - compare verifier for commit data
+ * @dreq - direct request possibly spanning multiple servers
+ * @data - commit data to validate against previously seen verf
+ *
+ * returns result of comparison between @data->verf and the verf of
+ * the server used by @data (DS or MDS)
+ */
+static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
+                                          struct nfs_commit_data *data)
+{
+       struct nfs_writeverf *verfp;
+
+       verfp = nfs_direct_select_verf(dreq, data->ds_clp,
+                                        data->ds_commit_index);
+       WARN_ON_ONCE(verfp->committed < 0);
+       return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf));
+}
+#endif
+
 /**
  * nfs_direct_IO - NFS address space operation for direct I/O
  * @rw: direction (read or write)
@@ -168,6 +259,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
        kref_get(&dreq->kref);
        init_completion(&dreq->completion);
        INIT_LIST_HEAD(&dreq->mds_cinfo.list);
+       dreq->verf.committed = NFS_INVALID_STABLE_HOW;  /* not set yet */
        INIT_WORK(&dreq->work, nfs_direct_write_schedule_work);
        spin_lock_init(&dreq->lock);
 
@@ -380,8 +472,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *de
                        struct nfs_page *req;
                        unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
                        /* XXX do we need to do the eof zeroing found in async_filler? */
-                       req = nfs_create_request(dreq->ctx, dreq->inode,
-                                                pagevec[i],
+                       req = nfs_create_request(dreq->ctx, pagevec[i], NULL,
                                                 pgbase, req_len);
                        if (IS_ERR(req)) {
                                result = PTR_ERR(req);
@@ -424,7 +515,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
        size_t requested_bytes = 0;
        unsigned long seg;
 
-       NFS_PROTO(dreq->inode)->read_pageio_init(&desc, dreq->inode,
+       nfs_pageio_init_read(&desc, dreq->inode, false,
                             &nfs_direct_read_completion_ops);
        get_dreq(dreq);
        desc.pg_dreq = dreq;
@@ -564,7 +655,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
        dreq->count = 0;
        get_dreq(dreq);
 
-       NFS_PROTO(dreq->inode)->write_pageio_init(&desc, dreq->inode, FLUSH_STABLE,
+       nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE, false,
                              &nfs_direct_write_completion_ops);
        desc.pg_dreq = dreq;
 
@@ -603,7 +694,7 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
                dprintk("NFS: %5u commit failed with error %d.\n",
                        data->task.tk_pid, status);
                dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
-       } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) {
+       } else if (nfs_direct_cmp_commit_data_verf(dreq, data)) {
                dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid);
                dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
        }
@@ -750,8 +841,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *d
                        struct nfs_page *req;
                        unsigned int req_len = min_t(size_t, bytes, PAGE_SIZE - pgbase);
 
-                       req = nfs_create_request(dreq->ctx, dreq->inode,
-                                                pagevec[i],
+                       req = nfs_create_request(dreq->ctx, pagevec[i], NULL,
                                                 pgbase, req_len);
                        if (IS_ERR(req)) {
                                result = PTR_ERR(req);
@@ -813,13 +903,13 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
                        if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES)
                                bit = NFS_IOHDR_NEED_RESCHED;
                        else if (dreq->flags == 0) {
-                               memcpy(&dreq->verf, hdr->verf,
-                                      sizeof(dreq->verf));
+                               nfs_direct_set_hdr_verf(dreq, hdr);
                                bit = NFS_IOHDR_NEED_COMMIT;
                                dreq->flags = NFS_ODIRECT_DO_COMMIT;
                        } else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) {
-                               if (memcmp(&dreq->verf, hdr->verf, sizeof(dreq->verf))) {
-                                       dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
+                               if (nfs_direct_set_or_cmp_hdr_verf(dreq, hdr)) {
+                                       dreq->flags =
+                                               NFS_ODIRECT_RESCHED_WRITES;
                                        bit = NFS_IOHDR_NEED_RESCHED;
                                } else
                                        bit = NFS_IOHDR_NEED_COMMIT;
@@ -829,6 +919,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
        spin_unlock(&dreq->lock);
 
        while (!list_empty(&hdr->pages)) {
+               bool do_destroy = true;
+
                req = nfs_list_entry(hdr->pages.next);
                nfs_list_remove_request(req);
                switch (bit) {
@@ -836,6 +928,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
                case NFS_IOHDR_NEED_COMMIT:
                        kref_get(&req->wb_kref);
                        nfs_mark_request_commit(req, hdr->lseg, &cinfo);
+                       do_destroy = false;
                }
                nfs_unlock_and_release_request(req);
        }
@@ -874,7 +967,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
        size_t requested_bytes = 0;
        unsigned long seg;
 
-       NFS_PROTO(inode)->write_pageio_init(&desc, inode, FLUSH_COND_STABLE,
+       nfs_pageio_init_write(&desc, inode, FLUSH_COND_STABLE, false,
                              &nfs_direct_write_completion_ops);
        desc.pg_dreq = dreq;
        get_dreq(dreq);