patch 15/38: CLIENT: add ->setup_read() nfs_rpc_op for async read,

Kendrick M. Smith (kmsmith@umich.edu)
Tue, 13 Aug 2002 19:02:18 -0400 (EDT)


This is a nontrivial change to the NFS client.

In this patch, we finish modifying the async READ path so that it is
version-agnostic. We define a new nfs_rpc_op ->setup_read(), and move
the v2- and v3-specific code in nfs_read_rpcsetup() there. We also
have to change nfs_readpage() result so that the 'count' of bytes
read is a parameter. The extra parameter means that it can no longer
be ->tk_exit(). Instead, it is called from a version-specific ->tk_exit()
routine which is set in ->read_setup().

The upshot of all this is that the version-specific part of the
async READ path has been encapsulated in a new nfs_rpc_op
->read_setup(), and NFSv4 can share the logic for asynchronous
READ's with NFSv2 and v3.

--- old/fs/nfs/read.c Sat Aug 10 22:20:59 2002
+++ new/fs/nfs/read.c Thu Aug 8 18:26:06 2002
@@ -34,34 +34,6 @@

#define NFSDBG_FACILITY NFSDBG_PAGECACHE

-struct nfs_read_data {
- struct rpc_task task;
- struct inode *inode;
- struct rpc_cred *cred;
- struct nfs_fattr fattr; /* fattr storage */
- struct list_head pages; /* Coalesced read requests */
- struct page *pagevec[NFS_READ_MAXIOV];
- union {
- struct {
- struct nfs_readargs args;
- struct nfs_readres res;
- } v3; /* also v2 */
-#ifdef CONFIG_NFS_V4
- /* NFSv4 data will come here... */
-#endif
- } u;
-};
-
-/*
- * Local function declarations
- */
-static void nfs_readpage_result(struct rpc_task *task);
-
-/* Hack for future NFS swap support */
-#ifndef IS_SWAPFILE
-# define IS_SWAPFILE(inode) (0)
-#endif
-
static kmem_cache_t *nfs_rdata_cachep;

static __inline__ struct nfs_read_data *nfs_readdata_alloc(void)
@@ -80,7 +52,7 @@ static __inline__ void nfs_readdata_free
kmem_cache_free(nfs_rdata_cachep, p);
}

-static void nfs_readdata_release(struct rpc_task *task)
+void nfs_readdata_release(struct rpc_task *task)
{
struct nfs_read_data *data = (struct nfs_read_data *)task->tk_calldata;
nfs_readdata_free(data);
@@ -196,6 +168,7 @@ nfs_readpage_async(struct file *file, st
static void
nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
{
+ struct inode *inode;
struct nfs_page *req;
struct page **pages;
unsigned int count;
@@ -203,23 +176,24 @@ nfs_read_rpcsetup(struct list_head *head
pages = data->pagevec;
count = 0;
while (!list_empty(head)) {
- struct nfs_page *req = nfs_list_entry(head->next);
+ req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages);
*pages++ = req->wb_page;
count += req->wb_bytes;
}
req = nfs_list_entry(data->pages.next);
- data->inode = req->wb_inode;
+ data->inode = inode = req->wb_inode;
data->cred = req->wb_cred;
- data->u.v3.args.fh = NFS_FH(req->wb_inode);
- data->u.v3.args.offset = page_offset(req->wb_page) + req->wb_offset;
- data->u.v3.args.pgbase = req->wb_offset;
- data->u.v3.args.pages = pages;
- data->u.v3.args.count = count;
- data->u.v3.res.fattr = &data->fattr;
- data->u.v3.res.count = count;
- data->u.v3.res.eof = 0;
+
+ NFS_PROTO(inode)->read_setup(data, count);
+
+ dprintk("NFS: %4d 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)page_offset(req->wb_page) + req->wb_offset);
}

static void
@@ -243,50 +217,20 @@ nfs_async_read_error(struct list_head *h
static int
nfs_pagein_one(struct list_head *head, struct inode *inode)
{
- struct rpc_task *task;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
struct nfs_read_data *data;
- struct rpc_message msg;
- int flags;
sigset_t oldset;

data = nfs_readdata_alloc();
if (!data)
goto out_bad;
- task = &data->task;
-
- /* N.B. Do we need to test? Never called for swapfile inode */
- flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);

nfs_read_rpcsetup(head, data);

- /* Finalize the task. */
- rpc_init_task(task, clnt, nfs_readpage_result, flags);
- task->tk_calldata = data;
- /* Release requests */
- task->tk_release = nfs_readdata_release;
-
-#ifdef CONFIG_NFS_V3
- msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
-#else
- msg.rpc_proc = NFSPROC_READ;
-#endif
- msg.rpc_argp = &data->u.v3.args;
- msg.rpc_resp = &data->u.v3.res;
- msg.rpc_cred = data->cred;
-
/* Start the async call */
- dprintk("NFS: %4d initiated read call (req %s/%Ld, %u bytes @ offset %Lu.\n",
- task->tk_pid,
- inode->i_sb->s_id,
- (long long)NFS_FILEID(inode),
- (unsigned int)data->u.v3.args.count,
- (unsigned long long)data->u.v3.args.offset);
-
rpc_clnt_sigmask(clnt, &oldset);
- rpc_call_setup(task, &msg, 0);
lock_kernel();
- rpc_execute(task);
+ rpc_execute(&data->task);
unlock_kernel();
rpc_clnt_sigunmask(clnt, &oldset);
return 0;
@@ -406,19 +350,15 @@ int nfs_pagein_inode(struct inode *inode
* This is the callback from RPC telling us whether a reply was
* received or some error occurred (timeout or socket shutdown).
*/
-static void
-nfs_readpage_result(struct rpc_task *task)
+void
+nfs_readpage_result(struct rpc_task *task, unsigned int count)
{
struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
struct inode *inode = data->inode;
- unsigned int count = data->u.v3.res.count;

dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
task->tk_pid, task->tk_status);

- if (nfs_async_handle_jukebox(task))
- return;
-
nfs_refresh_inode(inode, &data->fattr);
while (!list_empty(&data->pages)) {
struct nfs_page *req = nfs_list_entry(data->pages.next);
--- old/include/linux/nfs_fs.h Thu Aug 8 18:17:47 2002
+++ new/include/linux/nfs_fs.h Thu Aug 8 18:10:03 2002
@@ -352,6 +352,11 @@ nfs_wb_file(struct inode *inode, struct
return (error < 0) ? error : 0;
}

+/* Hack for future NFS swap support */
+#ifndef IS_SWAPFILE
+# define IS_SWAPFILE(inode) (0)
+#endif
+
/*
* linux/fs/nfs/read.c
*/
@@ -360,6 +365,8 @@ extern int nfs_pagein_inode(struct inod
extern int nfs_pagein_list(struct list_head *, int);
extern int nfs_scan_lru_read(struct nfs_server *, struct list_head *);
extern int nfs_scan_lru_read_timeout(struct nfs_server *, struct list_head *);
+extern void nfs_readpage_result(struct rpc_task *task, unsigned int count);
+extern void nfs_readdata_release(struct rpc_task *task);

/*
* linux/fs/mount_clnt.c
--- old/include/linux/nfs_xdr.h Thu Aug 8 18:17:47 2002
+++ new/include/linux/nfs_xdr.h Tue Aug 6 10:16:09 2002
@@ -298,6 +298,24 @@ struct nfs3_readdirres {
int plus;
};

+struct nfs_read_data {
+ struct rpc_task task;
+ struct inode *inode;
+ struct rpc_cred *cred;
+ struct nfs_fattr fattr; /* fattr storage */
+ struct list_head pages; /* Coalesced read requests */
+ struct page *pagevec[NFS_READ_MAXIOV];
+ union {
+ struct {
+ struct nfs_readargs args;
+ struct nfs_readres res;
+ } v3; /* also v2 */
+#ifdef CONFIG_NFS_V4
+ /* NFSv4 data will come here... */
+#endif
+ } u;
+};
+
/*
* RPC procedure vector for NFSv2/NFSv3 demuxing
*/
@@ -345,6 +361,7 @@ struct nfs_rpc_ops {
int (*statfs) (struct nfs_server *, struct nfs_fh *,
struct nfs_fsinfo *);
u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus);
+ void (*read_setup) (struct nfs_read_data *, unsigned int count);
};

/*
--- old/fs/nfs/proc.c Thu Aug 8 12:00:17 2002
+++ new/fs/nfs/proc.c Tue Aug 6 10:15:51 2002
@@ -41,6 +41,7 @@
#include <linux/nfs.h>
#include <linux/nfs2.h>
#include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
#include <linux/smp_lock.h>

#define NFSDBG_FACILITY NFSDBG_PROC
@@ -469,6 +470,48 @@ nfs_proc_statfs(struct nfs_server *serve

extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);

+static void
+nfs_read_done(struct rpc_task *task)
+{
+ struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
+ nfs_readpage_result(task, data->u.v3.res.count);
+}
+
+static void
+nfs_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+{
+ struct rpc_task *task = &data->task;
+ struct inode *inode = data->inode;
+ struct nfs_page *req;
+ int flags;
+ struct rpc_message msg;
+
+ req = nfs_list_entry(data->pages.next);
+ data->u.v3.args.fh = NFS_FH(inode);
+ data->u.v3.args.offset = page_offset(req->wb_page) + req->wb_offset;
+ data->u.v3.args.pgbase = req->wb_offset;
+ data->u.v3.args.pages = data->pagevec;
+ data->u.v3.args.count = count;
+ data->u.v3.res.fattr = &data->fattr;
+ data->u.v3.res.count = count;
+ data->u.v3.res.eof = 0;
+
+ /* N.B. Do we need to test? Never called for swapfile inode */
+ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
+
+ /* Finalize the task. */
+ rpc_init_task(task, NFS_CLIENT(inode), nfs_read_done, flags);
+ task->tk_calldata = data;
+ /* Release requests */
+ task->tk_release = nfs_readdata_release;
+
+ msg.rpc_proc = NFSPROC_READ;
+ msg.rpc_argp = &data->u.v3.args;
+ msg.rpc_resp = &data->u.v3.res;
+ msg.rpc_cred = data->cred;
+ rpc_call_setup(&data->task, &msg, 0);
+}
+
struct nfs_rpc_ops nfs_v2_clientops = {
version: 2, /* protocol version */
getroot: nfs_proc_get_root,
@@ -493,4 +536,5 @@ struct nfs_rpc_ops nfs_v2_clientops = {
mknod: nfs_proc_mknod,
statfs: nfs_proc_statfs,
decode_dirent: nfs_decode_dirent,
+ read_setup: nfs_proc_read_setup,
};
--- old/fs/nfs/nfs3proc.c Thu Aug 8 12:00:17 2002
+++ new/fs/nfs/nfs3proc.c Tue Aug 6 10:15:40 2002
@@ -14,6 +14,7 @@
#include <linux/nfs.h>
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
#include <linux/smp_lock.h>

#define NFSDBG_FACILITY NFSDBG_PROC
@@ -641,6 +642,51 @@ error:

extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);

+static void
+nfs3_read_done(struct rpc_task *task)
+{
+ struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
+
+ if (nfs_async_handle_jukebox(task))
+ return;
+ nfs_readpage_result(task, data->u.v3.res.count);
+}
+
+static void
+nfs3_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+{
+ struct rpc_task *task = &data->task;
+ struct inode *inode = data->inode;
+ struct nfs_page *req;
+ int flags;
+ struct rpc_message msg;
+
+ req = nfs_list_entry(data->pages.next);
+ data->u.v3.args.fh = NFS_FH(inode);
+ data->u.v3.args.offset = page_offset(req->wb_page) + req->wb_offset;
+ data->u.v3.args.pgbase = req->wb_offset;
+ data->u.v3.args.pages = data->pagevec;
+ data->u.v3.args.count = count;
+ data->u.v3.res.fattr = &data->fattr;
+ data->u.v3.res.count = count;
+ data->u.v3.res.eof = 0;
+
+ /* N.B. Do we need to test? Never called for swapfile inode */
+ flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
+
+ /* Finalize the task. */
+ rpc_init_task(task, NFS_CLIENT(inode), nfs3_read_done, flags);
+ task->tk_calldata = data;
+ /* Release requests */
+ task->tk_release = nfs_readdata_release;
+
+ msg.rpc_proc = NFS3PROC_READ;
+ msg.rpc_argp = &data->u.v3.args;
+ msg.rpc_resp = &data->u.v3.res;
+ msg.rpc_cred = data->cred;
+ rpc_call_setup(&data->task, &msg, 0);
+}
+
struct nfs_rpc_ops nfs_v3_clientops = {
version: 3, /* protocol version */
getroot: nfs3_proc_get_root,
@@ -664,4 +710,5 @@ struct nfs_rpc_ops nfs_v3_clientops = {
mknod: nfs3_proc_mknod,
statfs: nfs3_proc_statfs,
decode_dirent: nfs3_decode_dirent,
+ read_setup: nfs3_proc_read_setup,
};

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/