NFSv4.1: shift pnfs_update_layout locations
authorFred Isaman <iisaman@netapp.com>
Tue, 1 Mar 2011 01:34:15 +0000 (01:34 +0000)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 11 Mar 2011 20:38:42 +0000 (15:38 -0500)
Move the pnfs_update_layout call location to nfs_pageio_do_add_request().
Grab the lseg sent in the doio function to nfs_read_rpcsetup and attach
it to each nfs_read_data so it can be sent to the layout driver.

Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Andy Adamson <andros@citi.umich.edu>
Signed-off-by: Dean Hildebrand <dhildeb@us.ibm.com>
Signed-off-by: Fred Isaman <iisaman@citi.umich.edu>
Signed-off-by: Fred Isaman <iisaman@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: Oleg Drokin <green@linuxhacker.ru>
Signed-off-by: Tao Guo <guotao@nrchpc.ac.cn>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/file.c
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/read.c
fs/nfs/write.c
include/linux/nfs_page.h
include/linux/nfs_xdr.h

index 7bf029ef4084c6e7f02e05e355382168e85e2cb8..d85a534b15cd1805175345a2e94538f2fcefe10e 100644 (file)
@@ -387,10 +387,6 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
                file->f_path.dentry->d_name.name,
                mapping->host->i_ino, len, (long long) pos);
 
-       pnfs_update_layout(mapping->host,
-                          nfs_file_open_context(file),
-                          IOMODE_RW);
-
 start:
        /*
         * Prevent starvation issues if someone is doing a consistency
index 9b9a65c9bb4f1a1541abe6ef5de1184c400eab3b..45b0fb8add39c00b75dfb28bba7fe6059fd720fb 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/nfs_mount.h>
 
 #include "internal.h"
+#include "pnfs.h"
 
 static struct kmem_cache *nfs_page_cachep;
 
@@ -213,7 +214,7 @@ nfs_wait_on_request(struct nfs_page *req)
  */
 void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
                     struct inode *inode,
-                    int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
+                    int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int, struct pnfs_layout_segment *),
                     size_t bsize,
                     int io_flags)
 {
@@ -315,7 +316,9 @@ static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
                                          nfs_page_array_len(desc->pg_base,
                                                             desc->pg_count),
                                          desc->pg_count,
-                                         desc->pg_ioflags);
+                                         desc->pg_ioflags,
+                                         desc->pg_lseg);
+               desc->pg_lseg = NULL;
                if (error < 0)
                        desc->pg_error = error;
                else
index 330cee115de0a3db6be57750df7e2a1f847e9162..77966ecb0a2ccdf97efd2a0f0b875cadc475e63e 100644 (file)
@@ -245,7 +245,7 @@ put_lseg_common(struct pnfs_layout_segment *lseg)
        rpc_wake_up(&NFS_SERVER(inode)->roc_rpcwaitq);
 }
 
-static void
+void
 put_lseg(struct pnfs_layout_segment *lseg)
 {
        struct inode *inode;
@@ -784,7 +784,6 @@ pnfs_update_layout(struct inode *ino,
 out:
        dprintk("%s end, state 0x%lx lseg %p\n", __func__,
                nfsi->layout ? nfsi->layout->plh_flags : -1, lseg);
-       put_lseg(lseg); /* STUB - callers currently ignore return value */
        return lseg;
 out_unlock:
        spin_unlock(&ino->i_lock);
@@ -858,20 +857,26 @@ out_forget_reply:
        goto out;
 }
 
-static void
-pnfs_set_pg_test(struct inode *inode, struct nfs_pageio_descriptor *pgio)
+static int pnfs_read_pg_test(struct nfs_pageio_descriptor *pgio,
+                            struct nfs_page *prev,
+                            struct nfs_page *req)
 {
-       struct pnfs_layoutdriver_type *ld;
-
-       ld = NFS_SERVER(inode)->pnfs_curr_ld;
-       pgio->pg_test = (ld ? ld->pg_test : NULL);
+       if (pgio->pg_count == prev->wb_bytes) {
+               /* This is first coelesce call for a series of nfs_pages */
+               pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
+                                                  prev->wb_context,
+                                                  IOMODE_READ);
+       }
+       return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req);
 }
 
 void
-pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio,
-                 struct inode *inode)
+pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode)
 {
-       pnfs_set_pg_test(inode, pgio);
+       struct pnfs_layoutdriver_type *ld;
+
+       ld = NFS_SERVER(inode)->pnfs_curr_ld;
+       pgio->pg_test = (ld && ld->pg_test) ? pnfs_read_pg_test : NULL;
 }
 
 /*
index db52d965857060b782c5072a2b4cf59f7ffe69cc..5107d14db4855f55e573b886622b94994343de31 100644 (file)
@@ -151,6 +151,7 @@ extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
 
 /* pnfs.c */
 void get_layout_hdr(struct pnfs_layout_hdr *lo);
+void put_lseg(struct pnfs_layout_segment *lseg);
 struct pnfs_layout_segment *
 pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
                   enum pnfs_iomode access_type);
index 2a2765975e1f4418f8026013bbf74f208496ac4b..6dc9eaf00e5c78a0f072b85719333feed793b59e 100644 (file)
 #include <linux/nfs_page.h>
 
 #include <asm/system.h>
+#include "pnfs.h"
 
 #include "nfs4_fs.h"
 #include "internal.h"
 #include "iostat.h"
 #include "fscache.h"
-#include "pnfs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
-static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int);
-static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int);
+static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int, struct pnfs_layout_segment *);
+static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int, struct pnfs_layout_segment *);
 static const struct rpc_call_ops nfs_read_partial_ops;
 static const struct rpc_call_ops nfs_read_full_ops;
 
@@ -69,6 +69,7 @@ void nfs_readdata_free(struct nfs_read_data *p)
 
 static void nfs_readdata_release(struct nfs_read_data *rdata)
 {
+       put_lseg(rdata->lseg);
        put_nfs_open_context(rdata->args.context);
        nfs_readdata_free(rdata);
 }
@@ -121,7 +122,6 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
        len = nfs_page_length(page);
        if (len == 0)
                return nfs_return_empty_page(page);
-       pnfs_update_layout(inode, ctx, IOMODE_READ);
        new = nfs_create_request(ctx, inode, page, 0, len);
        if (IS_ERR(new)) {
                unlock_page(page);
@@ -132,9 +132,9 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
 
        nfs_list_add_request(new, &one_request);
        if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
-               nfs_pagein_multi(inode, &one_request, 1, len, 0);
+               nfs_pagein_multi(inode, &one_request, 1, len, 0, NULL);
        else
-               nfs_pagein_one(inode, &one_request, 1, len, 0);
+               nfs_pagein_one(inode, &one_request, 1, len, 0, NULL);
        return 0;
 }
 
@@ -160,7 +160,8 @@ static void nfs_readpage_release(struct nfs_page *req)
  */
 static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
                const struct rpc_call_ops *call_ops,
-               unsigned int count, unsigned int offset)
+               unsigned int count, unsigned int offset,
+               struct pnfs_layout_segment *lseg)
 {
        struct inode *inode = req->wb_context->path.dentry->d_inode;
        int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0;
@@ -183,6 +184,7 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
        data->req         = req;
        data->inode       = inode;
        data->cred        = msg.rpc_cred;
+       data->lseg        = get_lseg(lseg);
 
        data->args.fh     = NFS_FH(inode);
        data->args.offset = req_offset(req) + offset;
@@ -240,7 +242,7 @@ nfs_async_read_error(struct list_head *head)
  * won't see the new data until our attribute cache is updated.  This is more
  * or less conventional NFS client behavior.
  */
-static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
+static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags, struct pnfs_layout_segment *lseg)
 {
        struct nfs_page *req = nfs_list_entry(head->next);
        struct page *page = req->wb_page;
@@ -266,6 +268,8 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne
        } while(nbytes != 0);
        atomic_set(&req->wb_complete, requests);
 
+       /* We know lseg==NULL */
+       lseg = pnfs_update_layout(inode, req->wb_context, IOMODE_READ);
        ClearPageError(page);
        offset = 0;
        nbytes = count;
@@ -280,12 +284,13 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigne
                if (nbytes < rsize)
                        rsize = nbytes;
                ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
-                                 rsize, offset);
+                                        rsize, offset, lseg);
                if (ret == 0)
                        ret = ret2;
                offset += rsize;
                nbytes -= rsize;
        } while (nbytes != 0);
+       put_lseg(lseg);
 
        return ret;
 
@@ -300,7 +305,7 @@ out_bad:
        return -ENOMEM;
 }
 
-static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
+static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags, struct pnfs_layout_segment *lseg)
 {
        struct nfs_page         *req;
        struct page             **pages;
@@ -308,8 +313,10 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned
        int ret = -ENOMEM;
 
        data = nfs_readdata_alloc(npages);
-       if (!data)
-               goto out_bad;
+       if (!data) {
+               nfs_async_read_error(head);
+               goto out;
+       }
 
        pages = data->pagevec;
        while (!list_empty(head)) {
@@ -320,10 +327,12 @@ static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned
                *pages++ = req->wb_page;
        }
        req = nfs_list_entry(data->pages.next);
+       if ((!lseg) && list_is_singular(&data->pages))
+               lseg = pnfs_update_layout(inode, req->wb_context, IOMODE_READ);
 
-       return nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0);
-out_bad:
-       nfs_async_read_error(head);
+       ret = nfs_read_rpcsetup(req, data, &nfs_read_full_ops, count, 0, lseg);
+out:
+       put_lseg(lseg);
        return ret;
 }
 
@@ -625,7 +634,6 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
        if (ret == 0)
                goto read_complete; /* all pages were read */
 
-       pnfs_update_layout(inode, desc.ctx, IOMODE_READ);
        pnfs_pageio_init_read(&pgio, inode);
        if (rsize < PAGE_CACHE_SIZE)
                nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
index 40143c4747a5794d270ed982ed9ffd437e1cb7a3..f033fa0d7d33fe59fd7412a2f56e910ac170da46 100644 (file)
@@ -880,7 +880,7 @@ static void nfs_redirty_request(struct nfs_page *req)
  * Generate multiple small requests to write out a single
  * contiguous dirty area on one page.
  */
-static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
+static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how, struct pnfs_layout_segment *lseg)
 {
        struct nfs_page *req = nfs_list_entry(head->next);
        struct page *page = req->wb_page;
@@ -947,7 +947,7 @@ out_bad:
  * This is the case if nfs_updatepage detects a conflicting request
  * that has been written but not committed.
  */
-static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
+static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how, struct pnfs_layout_segment *lseg)
 {
        struct nfs_page         *req;
        struct page             **pages;
index 4eaf27a1282d28c1714a40ca43831e42acbcef48..ba88ff4f8186227b8bc8adf36e8d9136b05bdc2d 100644 (file)
@@ -59,7 +59,7 @@ struct nfs_pageio_descriptor {
        unsigned int            pg_base;
 
        struct inode            *pg_inode;
-       int                     (*pg_doio)(struct inode *, struct list_head *, unsigned int, size_t, int);
+       int                     (*pg_doio)(struct inode *, struct list_head *, unsigned int, size_t, int, struct pnfs_layout_segment *);
        int                     pg_ioflags;
        int                     pg_error;
        struct pnfs_layout_segment *pg_lseg;
@@ -81,7 +81,7 @@ extern        int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst,
                          pgoff_t idx_start, unsigned int npages, int tag);
 extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
                             struct inode *inode,
-                            int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
+                            int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int, struct pnfs_layout_segment *),
                             size_t bsize,
                             int how);
 extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *,
index d159fe7333815082deb4c8b835963a1a3756a115..560923e2872373273e4bd6e550fd22cf6b4728bc 100644 (file)
@@ -1017,6 +1017,7 @@ struct nfs_read_data {
        struct nfs_readargs args;
        struct nfs_readres  res;
        unsigned long           timestamp;      /* For lease renewal */
+       struct pnfs_layout_segment *lseg;
        struct page             *page_array[NFS_PAGEVEC_SIZE];
 };