NFSv4.1: generic read
authorAndy Adamson <andros@netapp.com>
Tue, 1 Mar 2011 01:34:16 +0000 (01:34 +0000)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 11 Mar 2011 20:38:42 +0000 (15:38 -0500)
Separate the rpc run portion of nfs_read_rpcsetup into a new function
nfs_initiate_read that is called for normal NFS I/O.

Add a pNFS read_pagelist function that is called instead of nfs_intitate_read
for pNFS reads.

Signed-off-by: Andy Adamson <andros@citi.umich.edu>
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
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: Mike Sager <sager@netapp.com>
Signed-off-by: Mingyang Guo <guomingyang@nrchpc.ac.cn>
Signed-off-by: Ricardo Labiaga <Ricardo.Labiaga@netapp.com>
Signed-off-by: Tao Guo <guotao@nrchpc.ac.cn>
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/read.c
include/linux/nfs_iostat.h
include/linux/nfs_xdr.h

index 77966ecb0a2ccdf97efd2a0f0b875cadc475e63e..86c154bad5db307254b0f90d2348aadc93ead7d5 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/nfs_fs.h>
 #include "internal.h"
 #include "pnfs.h"
+#include "iostat.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PNFS
 
@@ -879,6 +880,33 @@ pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode)
        pgio->pg_test = (ld && ld->pg_test) ? pnfs_read_pg_test : NULL;
 }
 
+/*
+ * Call the appropriate parallel I/O subsystem read function.
+ */
+enum pnfs_try_status
+pnfs_try_to_read_data(struct nfs_read_data *rdata,
+                      const struct rpc_call_ops *call_ops)
+{
+       struct inode *inode = rdata->inode;
+       struct nfs_server *nfss = NFS_SERVER(inode);
+       enum pnfs_try_status trypnfs;
+
+       rdata->mds_ops = call_ops;
+
+       dprintk("%s: Reading ino:%lu %u@%llu\n",
+               __func__, inode->i_ino, rdata->args.count, rdata->args.offset);
+
+       trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata);
+       if (trypnfs == PNFS_NOT_ATTEMPTED) {
+               put_lseg(rdata->lseg);
+               rdata->lseg = NULL;
+       } else {
+               nfs_inc_stats(inode, NFSIOS_PNFS_READ);
+       }
+       dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs);
+       return trypnfs;
+}
+
 /*
  * Device ID cache. Currently supports one layout type per struct nfs_client.
  * Add layout type to the lookup key to expand to support multiple types.
index 5107d14db4855f55e573b886622b94994343de31..585023fabb5500a17d577e5eb00b89f872737334 100644 (file)
@@ -45,6 +45,11 @@ struct pnfs_layout_segment {
        struct pnfs_layout_hdr *pls_layout;
 };
 
+enum pnfs_try_status {
+       PNFS_ATTEMPTED     = 0,
+       PNFS_NOT_ATTEMPTED = 1,
+};
+
 #ifdef CONFIG_NFS_V4_1
 
 #define LAYOUT_NFSV4_1_MODULE_PREFIX "nfs-layouttype4"
@@ -70,6 +75,12 @@ struct pnfs_layoutdriver_type {
 
        /* test for nfs page cache coalescing */
        int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
+
+       /*
+        * Return PNFS_ATTEMPTED to indicate the layout code has attempted
+        * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS
+        */
+       enum pnfs_try_status (*read_pagelist) (struct nfs_read_data *nfs_data);
 };
 
 struct pnfs_layout_hdr {
@@ -157,6 +168,8 @@ pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
                   enum pnfs_iomode access_type);
 void set_pnfs_layoutdriver(struct nfs_server *, u32 id);
 void unset_pnfs_layoutdriver(struct nfs_server *);
+enum pnfs_try_status pnfs_try_to_read_data(struct nfs_read_data *,
+                                           const struct rpc_call_ops *);
 void pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *);
 int pnfs_layout_process(struct nfs4_layoutget *lgp);
 void pnfs_free_lseg_list(struct list_head *tmp_list);
@@ -227,6 +240,13 @@ pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx,
        return NULL;
 }
 
+static inline enum pnfs_try_status
+pnfs_try_to_read_data(struct nfs_read_data *data,
+                     const struct rpc_call_ops *call_ops)
+{
+       return PNFS_NOT_ATTEMPTED;
+}
+
 static inline bool
 pnfs_roc(struct inode *ino)
 {
index 6dc9eaf00e5c78a0f072b85719333feed793b59e..4127a1c0eec6ba7afd94bf2733524685e9bde4cd 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
+#include <linux/smp_lock.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include "pnfs.h"
@@ -155,25 +157,20 @@ static void nfs_readpage_release(struct nfs_page *req)
        nfs_release_request(req);
 }
 
-/*
- * Set up the NFS read request struct
- */
-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,
-               struct pnfs_layout_segment *lseg)
+static int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt,
+                     const struct rpc_call_ops *call_ops)
 {
-       struct inode *inode = req->wb_context->path.dentry->d_inode;
+       struct inode *inode = data->inode;
        int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0;
        struct rpc_task *task;
        struct rpc_message msg = {
                .rpc_argp = &data->args,
                .rpc_resp = &data->res,
-               .rpc_cred = req->wb_context->cred,
+               .rpc_cred = data->cred,
        };
        struct rpc_task_setup task_setup_data = {
                .task = &data->task,
-               .rpc_client = NFS_CLIENT(inode),
+               .rpc_client = clnt,
                .rpc_message = &msg,
                .callback_ops = call_ops,
                .callback_data = data,
@@ -181,9 +178,37 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
                .flags = RPC_TASK_ASYNC | swap_flags,
        };
 
+       /* Set up the initial task struct. */
+       NFS_PROTO(inode)->read_setup(data, &msg);
+
+       dprintk("NFS: %5u initiated read call (req %s/%lld, %u bytes @ "
+                       "offset %llu)\n",
+                       data->task.tk_pid,
+                       inode->i_sb->s_id,
+                       (long long)NFS_FILEID(inode),
+                       data->args.count,
+                       (unsigned long long)data->args.offset);
+
+       task = rpc_run_task(&task_setup_data);
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       rpc_put_task(task);
+       return 0;
+}
+
+/*
+ * Set up the NFS read request struct
+ */
+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,
+               struct pnfs_layout_segment *lseg)
+{
+       struct inode *inode = req->wb_context->path.dentry->d_inode;
+
        data->req         = req;
        data->inode       = inode;
-       data->cred        = msg.rpc_cred;
+       data->cred        = req->wb_context->cred;
        data->lseg        = get_lseg(lseg);
 
        data->args.fh     = NFS_FH(inode);
@@ -199,21 +224,11 @@ static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
        data->res.eof     = 0;
        nfs_fattr_init(&data->fattr);
 
-       /* Set up the initial task struct. */
-       NFS_PROTO(inode)->read_setup(data, &msg);
-
-       dprintk("NFS: %5u initiated read call (req %s/%Ld, %u bytes @ offset %Lu)\n",
-                       data->task.tk_pid,
-                       inode->i_sb->s_id,
-                       (long long)NFS_FILEID(inode),
-                       count,
-                       (unsigned long long)data->args.offset);
+       if (data->lseg &&
+           (pnfs_try_to_read_data(data, call_ops) == PNFS_ATTEMPTED))
+               return 0;
 
-       task = rpc_run_task(&task_setup_data);
-       if (IS_ERR(task))
-               return PTR_ERR(task);
-       rpc_put_task(task);
-       return 0;
+       return nfs_initiate_read(data, NFS_CLIENT(inode), call_ops);
 }
 
 static void
index 68b10f5f8907fe0517d0bc5352686b34dd5be9e3..37a143732d023f523d07823a1c5d22784896c3b1 100644 (file)
@@ -113,6 +113,7 @@ enum nfs_stat_eventcounters {
        NFSIOS_SHORTREAD,
        NFSIOS_SHORTWRITE,
        NFSIOS_DELAY,
+       NFSIOS_PNFS_READ,
        __NFSIOS_COUNTSMAX,
 };
 
index 560923e2872373273e4bd6e550fd22cf6b4728bc..9d2b9dae277d317309578ebc060d5ea0f0ccc63e 100644 (file)
@@ -1018,6 +1018,7 @@ struct nfs_read_data {
        struct nfs_readres  res;
        unsigned long           timestamp;      /* For lease renewal */
        struct pnfs_layout_segment *lseg;
+       const struct rpc_call_ops *mds_ops;
        struct page             *page_array[NFS_PAGEVEC_SIZE];
 };