]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/nfs/pnfs.c
Merge tag 'nfs-for-3.16-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[karo-tx-linux.git] / fs / nfs / pnfs.c
index fd9536e494bc202184178449b5316c780a1b8e8f..6fdcd233d6f7b2bd7cf254016af820b997b0e6ed 100644 (file)
@@ -1388,11 +1388,6 @@ pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *r
 
        WARN_ON_ONCE(pgio->pg_lseg != NULL);
 
-       if (req->wb_offset != req->wb_pgbase) {
-               nfs_pageio_reset_read_mds(pgio);
-               return;
-       }
-
        if (pgio->pg_dreq == NULL)
                rd_size = i_size_read(pgio->pg_inode) - req_offset(req);
        else
@@ -1417,11 +1412,6 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
 {
        WARN_ON_ONCE(pgio->pg_lseg != NULL);
 
-       if (req->wb_offset != req->wb_pgbase) {
-               nfs_pageio_reset_write_mds(pgio);
-               return;
-       }
-
        pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
                                           req->wb_context,
                                           req_offset(req),
@@ -1434,56 +1424,49 @@ pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio,
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write);
 
-void
-pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode,
-                     const struct nfs_pgio_completion_ops *compl_ops)
-{
-       struct nfs_server *server = NFS_SERVER(inode);
-       struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
-
-       if (ld == NULL)
-               nfs_pageio_init_read(pgio, inode, compl_ops);
-       else
-               nfs_pageio_init(pgio, inode, ld->pg_read_ops, compl_ops, server->rsize, 0);
-}
-
-void
-pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode,
-                      int ioflags,
-                      const struct nfs_pgio_completion_ops *compl_ops)
-{
-       struct nfs_server *server = NFS_SERVER(inode);
-       struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld;
-
-       if (ld == NULL)
-               nfs_pageio_init_write(pgio, inode, ioflags, compl_ops);
-       else
-               nfs_pageio_init(pgio, inode, ld->pg_write_ops, compl_ops, server->wsize, ioflags);
-}
-
-bool
+/*
+ * Return 0 if @req cannot be coalesced into @pgio, otherwise return the number
+ * of bytes (maximum @req->wb_bytes) that can be coalesced.
+ */
+size_t
 pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
                     struct nfs_page *req)
 {
-       if (pgio->pg_lseg == NULL)
-               return nfs_generic_pg_test(pgio, prev, req);
+       unsigned int size;
+       u64 seg_end, req_start, seg_left;
+
+       size = nfs_generic_pg_test(pgio, prev, req);
+       if (!size)
+               return 0;
 
        /*
-        * Test if a nfs_page is fully contained in the pnfs_layout_range.
-        * Note that this test makes several assumptions:
-        * - that the previous nfs_page in the struct nfs_pageio_descriptor
-        *   is known to lie within the range.
-        *   - that the nfs_page being tested is known to be contiguous with the
-        *   previous nfs_page.
-        *   - Layout ranges are page aligned, so we only have to test the
-        *   start offset of the request.
+        * 'size' contains the number of bytes left in the current page (up
+        * to the original size asked for in @req->wb_bytes).
+        *
+        * Calculate how many bytes are left in the layout segment
+        * and if there are less bytes than 'size', return that instead.
         *
         * Please also note that 'end_offset' is actually the offset of the
         * first byte that lies outside the pnfs_layout_range. FIXME?
         *
         */
-       return req_offset(req) < end_offset(pgio->pg_lseg->pls_range.offset,
-                                        pgio->pg_lseg->pls_range.length);
+       if (pgio->pg_lseg) {
+               seg_end = end_offset(pgio->pg_lseg->pls_range.offset,
+                                    pgio->pg_lseg->pls_range.length);
+               req_start = req_offset(req);
+               WARN_ON_ONCE(req_start > seg_end);
+               /* start of request is past the last byte of this segment */
+               if (req_start >= seg_end)
+                       return 0;
+
+               /* adjust 'size' iff there are fewer bytes left in the
+                * segment than what nfs_generic_pg_test returned */
+               seg_left = seg_end - req_start;
+               if (seg_left < size)
+                       size = (unsigned int)seg_left;
+       }
+
+       return size;
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_pg_test);
 
@@ -1496,7 +1479,7 @@ int pnfs_write_done_resend_to_mds(struct inode *inode,
        LIST_HEAD(failed);
 
        /* Resend all requests through the MDS */
-       nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, compl_ops);
+       nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, true, compl_ops);
        pgio.pg_dreq = dreq;
        while (!list_empty(head)) {
                struct nfs_page *req = nfs_list_entry(head->next);
@@ -1519,7 +1502,7 @@ int pnfs_write_done_resend_to_mds(struct inode *inode,
 }
 EXPORT_SYMBOL_GPL(pnfs_write_done_resend_to_mds);
 
-static void pnfs_ld_handle_write_error(struct nfs_write_data *data)
+static void pnfs_ld_handle_write_error(struct nfs_pgio_data *data)
 {
        struct nfs_pgio_header *hdr = data->header;
 
@@ -1538,7 +1521,7 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data)
 /*
  * Called by non rpc-based layout drivers
  */
-void pnfs_ld_write_done(struct nfs_write_data *data)
+void pnfs_ld_write_done(struct nfs_pgio_data *data)
 {
        struct nfs_pgio_header *hdr = data->header;
 
@@ -1554,7 +1537,7 @@ EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
 
 static void
 pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
-               struct nfs_write_data *data)
+               struct nfs_pgio_data *data)
 {
        struct nfs_pgio_header *hdr = data->header;
 
@@ -1563,11 +1546,11 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
                nfs_pageio_reset_write_mds(desc);
                desc->pg_recoalesce = 1;
        }
-       nfs_writedata_release(data);
+       nfs_pgio_data_release(data);
 }
 
 static enum pnfs_try_status
-pnfs_try_to_write_data(struct nfs_write_data *wdata,
+pnfs_try_to_write_data(struct nfs_pgio_data *wdata,
                        const struct rpc_call_ops *call_ops,
                        struct pnfs_layout_segment *lseg,
                        int how)
@@ -1589,41 +1572,36 @@ pnfs_try_to_write_data(struct nfs_write_data *wdata,
 }
 
 static void
-pnfs_do_multiple_writes(struct nfs_pageio_descriptor *desc, struct list_head *head, int how)
+pnfs_do_write(struct nfs_pageio_descriptor *desc,
+             struct nfs_pgio_header *hdr, int how)
 {
-       struct nfs_write_data *data;
+       struct nfs_pgio_data *data = hdr->data;
        const struct rpc_call_ops *call_ops = desc->pg_rpc_callops;
        struct pnfs_layout_segment *lseg = desc->pg_lseg;
+       enum pnfs_try_status trypnfs;
 
        desc->pg_lseg = NULL;
-       while (!list_empty(head)) {
-               enum pnfs_try_status trypnfs;
-
-               data = list_first_entry(head, struct nfs_write_data, list);
-               list_del_init(&data->list);
-
-               trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how);
-               if (trypnfs == PNFS_NOT_ATTEMPTED)
-                       pnfs_write_through_mds(desc, data);
-       }
+       trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how);
+       if (trypnfs == PNFS_NOT_ATTEMPTED)
+               pnfs_write_through_mds(desc, data);
        pnfs_put_lseg(lseg);
 }
 
 static void pnfs_writehdr_free(struct nfs_pgio_header *hdr)
 {
        pnfs_put_lseg(hdr->lseg);
-       nfs_writehdr_free(hdr);
+       nfs_rw_header_free(hdr);
 }
 EXPORT_SYMBOL_GPL(pnfs_writehdr_free);
 
 int
 pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
 {
-       struct nfs_write_header *whdr;
+       struct nfs_rw_header *whdr;
        struct nfs_pgio_header *hdr;
        int ret;
 
-       whdr = nfs_writehdr_alloc();
+       whdr = nfs_rw_header_alloc(desc->pg_rw_ops);
        if (!whdr) {
                desc->pg_completion_ops->error_cleanup(&desc->pg_list);
                pnfs_put_lseg(desc->pg_lseg);
@@ -1634,12 +1612,12 @@ pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc)
        nfs_pgheader_init(desc, hdr, pnfs_writehdr_free);
        hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
        atomic_inc(&hdr->refcnt);
-       ret = nfs_generic_flush(desc, hdr);
+       ret = nfs_generic_pgio(desc, hdr);
        if (ret != 0) {
                pnfs_put_lseg(desc->pg_lseg);
                desc->pg_lseg = NULL;
        } else
-               pnfs_do_multiple_writes(desc, &hdr->rpc_list, desc->pg_ioflags);
+               pnfs_do_write(desc, hdr, desc->pg_ioflags);
        if (atomic_dec_and_test(&hdr->refcnt))
                hdr->completion_ops->completion(hdr);
        return ret;
@@ -1655,7 +1633,7 @@ int pnfs_read_done_resend_to_mds(struct inode *inode,
        LIST_HEAD(failed);
 
        /* Resend all requests through the MDS */
-       nfs_pageio_init_read(&pgio, inode, compl_ops);
+       nfs_pageio_init_read(&pgio, inode, true, compl_ops);
        pgio.pg_dreq = dreq;
        while (!list_empty(head)) {
                struct nfs_page *req = nfs_list_entry(head->next);
@@ -1674,7 +1652,7 @@ int pnfs_read_done_resend_to_mds(struct inode *inode,
 }
 EXPORT_SYMBOL_GPL(pnfs_read_done_resend_to_mds);
 
-static void pnfs_ld_handle_read_error(struct nfs_read_data *data)
+static void pnfs_ld_handle_read_error(struct nfs_pgio_data *data)
 {
        struct nfs_pgio_header *hdr = data->header;
 
@@ -1693,7 +1671,7 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data)
 /*
  * Called by non rpc-based layout drivers
  */
-void pnfs_ld_read_done(struct nfs_read_data *data)
+void pnfs_ld_read_done(struct nfs_pgio_data *data)
 {
        struct nfs_pgio_header *hdr = data->header;
 
@@ -1709,7 +1687,7 @@ EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
 
 static void
 pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
-               struct nfs_read_data *data)
+               struct nfs_pgio_data *data)
 {
        struct nfs_pgio_header *hdr = data->header;
 
@@ -1718,14 +1696,14 @@ pnfs_read_through_mds(struct nfs_pageio_descriptor *desc,
                nfs_pageio_reset_read_mds(desc);
                desc->pg_recoalesce = 1;
        }
-       nfs_readdata_release(data);
+       nfs_pgio_data_release(data);
 }
 
 /*
  * Call the appropriate parallel I/O subsystem read function.
  */
 static enum pnfs_try_status
-pnfs_try_to_read_data(struct nfs_read_data *rdata,
+pnfs_try_to_read_data(struct nfs_pgio_data *rdata,
                       const struct rpc_call_ops *call_ops,
                       struct pnfs_layout_segment *lseg)
 {
@@ -1747,41 +1725,35 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata,
 }
 
 static void
-pnfs_do_multiple_reads(struct nfs_pageio_descriptor *desc, struct list_head *head)
+pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
 {
-       struct nfs_read_data *data;
+       struct nfs_pgio_data *data = hdr->data;
        const struct rpc_call_ops *call_ops = desc->pg_rpc_callops;
        struct pnfs_layout_segment *lseg = desc->pg_lseg;
+       enum pnfs_try_status trypnfs;
 
        desc->pg_lseg = NULL;
-       while (!list_empty(head)) {
-               enum pnfs_try_status trypnfs;
-
-               data = list_first_entry(head, struct nfs_read_data, list);
-               list_del_init(&data->list);
-
-               trypnfs = pnfs_try_to_read_data(data, call_ops, lseg);
-               if (trypnfs == PNFS_NOT_ATTEMPTED)
-                       pnfs_read_through_mds(desc, data);
-       }
+       trypnfs = pnfs_try_to_read_data(data, call_ops, lseg);
+       if (trypnfs == PNFS_NOT_ATTEMPTED)
+               pnfs_read_through_mds(desc, data);
        pnfs_put_lseg(lseg);
 }
 
 static void pnfs_readhdr_free(struct nfs_pgio_header *hdr)
 {
        pnfs_put_lseg(hdr->lseg);
-       nfs_readhdr_free(hdr);
+       nfs_rw_header_free(hdr);
 }
 EXPORT_SYMBOL_GPL(pnfs_readhdr_free);
 
 int
 pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
 {
-       struct nfs_read_header *rhdr;
+       struct nfs_rw_header *rhdr;
        struct nfs_pgio_header *hdr;
        int ret;
 
-       rhdr = nfs_readhdr_alloc();
+       rhdr = nfs_rw_header_alloc(desc->pg_rw_ops);
        if (!rhdr) {
                desc->pg_completion_ops->error_cleanup(&desc->pg_list);
                ret = -ENOMEM;
@@ -1793,12 +1765,12 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
        nfs_pgheader_init(desc, hdr, pnfs_readhdr_free);
        hdr->lseg = pnfs_get_lseg(desc->pg_lseg);
        atomic_inc(&hdr->refcnt);
-       ret = nfs_generic_pagein(desc, hdr);
+       ret = nfs_generic_pgio(desc, hdr);
        if (ret != 0) {
                pnfs_put_lseg(desc->pg_lseg);
                desc->pg_lseg = NULL;
        } else
-               pnfs_do_multiple_reads(desc, &hdr->rpc_list);
+               pnfs_do_read(desc, hdr);
        if (atomic_dec_and_test(&hdr->refcnt))
                hdr->completion_ops->completion(hdr);
        return ret;
@@ -1848,7 +1820,7 @@ void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
 EXPORT_SYMBOL_GPL(pnfs_set_lo_fail);
 
 void
-pnfs_set_layoutcommit(struct nfs_write_data *wdata)
+pnfs_set_layoutcommit(struct nfs_pgio_data *wdata)
 {
        struct nfs_pgio_header *hdr = wdata->header;
        struct inode *inode = hdr->inode;