aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Adamson <andros@netapp.com>2011-02-28 20:34:20 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2011-03-11 15:38:43 -0500
commitcbdabc7f8bf14ca1d40ab1cb86f64b3bc09716e8 (patch)
tree16939b96996e8380d91d7e2743e811cf5c49f629
parentdc70d7b3189597f313df7bd2da849cfc39063b15 (diff)
NFSv4.1: filelayout async error handler
Use our own async error handler. Mark the layout as failed and retry i/o through the MDS on specified errors. Update the mds_offset in nfs_readpage_retry so that a failed short-read retry to a DS gets correctly resent through the MDS. Signed-off-by: Andy Adamson <andros@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/internal.h1
-rw-r--r--fs/nfs/nfs4filelayout.c81
-rw-r--r--fs/nfs/nfs4proc.c35
-rw-r--r--fs/nfs/nfs4state.c1
-rw-r--r--fs/nfs/read.c1
-rw-r--r--include/linux/nfs_xdr.h1
-rw-r--r--include/linux/sunrpc/clnt.h1
-rw-r--r--net/sunrpc/clnt.c8
8 files changed, 123 insertions, 6 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 5e9df992cd73..1a3228e9ea22 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -285,6 +285,7 @@ extern int nfs_migrate_page(struct address_space *,
285#endif 285#endif
286 286
287/* nfs4proc.c */ 287/* nfs4proc.c */
288extern void nfs4_reset_read(struct rpc_task *task, struct nfs_read_data *data);
288extern int nfs4_init_client(struct nfs_client *clp, 289extern int nfs4_init_client(struct nfs_client *clp,
289 const struct rpc_timeout *timeparms, 290 const struct rpc_timeout *timeparms,
290 const char *ip_addr, 291 const char *ip_addr,
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 3608411653dc..6a424c19abea 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -40,6 +40,8 @@ MODULE_LICENSE("GPL");
40MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>"); 40MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>");
41MODULE_DESCRIPTION("The NFSv4 file layout driver"); 41MODULE_DESCRIPTION("The NFSv4 file layout driver");
42 42
43#define FILELAYOUT_POLL_RETRY_MAX (15*HZ)
44
43static int 45static int
44filelayout_set_layoutdriver(struct nfs_server *nfss) 46filelayout_set_layoutdriver(struct nfs_server *nfss)
45{ 47{
@@ -100,6 +102,83 @@ filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset)
100 BUG(); 102 BUG();
101} 103}
102 104
105/* For data server errors we don't recover from */
106static void
107filelayout_set_lo_fail(struct pnfs_layout_segment *lseg)
108{
109 if (lseg->pls_range.iomode == IOMODE_RW) {
110 dprintk("%s Setting layout IOMODE_RW fail bit\n", __func__);
111 set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
112 } else {
113 dprintk("%s Setting layout IOMODE_READ fail bit\n", __func__);
114 set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
115 }
116}
117
118static int filelayout_async_handle_error(struct rpc_task *task,
119 struct nfs4_state *state,
120 struct nfs_client *clp,
121 int *reset)
122{
123 if (task->tk_status >= 0)
124 return 0;
125
126 *reset = 0;
127
128 switch (task->tk_status) {
129 case -NFS4ERR_BADSESSION:
130 case -NFS4ERR_BADSLOT:
131 case -NFS4ERR_BAD_HIGH_SLOT:
132 case -NFS4ERR_DEADSESSION:
133 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
134 case -NFS4ERR_SEQ_FALSE_RETRY:
135 case -NFS4ERR_SEQ_MISORDERED:
136 dprintk("%s ERROR %d, Reset session. Exchangeid "
137 "flags 0x%x\n", __func__, task->tk_status,
138 clp->cl_exchange_flags);
139 nfs4_schedule_session_recovery(clp->cl_session);
140 break;
141 case -NFS4ERR_DELAY:
142 case -NFS4ERR_GRACE:
143 case -EKEYEXPIRED:
144 rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
145 break;
146 default:
147 dprintk("%s DS error. Retry through MDS %d\n", __func__,
148 task->tk_status);
149 *reset = 1;
150 break;
151 }
152 task->tk_status = 0;
153 return -EAGAIN;
154}
155
156/* NFS_PROTO call done callback routines */
157
158static int filelayout_read_done_cb(struct rpc_task *task,
159 struct nfs_read_data *data)
160{
161 struct nfs_client *clp = data->ds_clp;
162 int reset = 0;
163
164 dprintk("%s DS read\n", __func__);
165
166 if (filelayout_async_handle_error(task, data->args.context->state,
167 data->ds_clp, &reset) == -EAGAIN) {
168 dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
169 __func__, data->ds_clp, data->ds_clp->cl_session);
170 if (reset) {
171 filelayout_set_lo_fail(data->lseg);
172 nfs4_reset_read(task, data);
173 clp = NFS_SERVER(data->inode)->nfs_client;
174 }
175 nfs_restart_rpc(task, clp);
176 return -EAGAIN;
177 }
178
179 return 0;
180}
181
103/* 182/*
104 * Call ops for the async read/write cases 183 * Call ops for the async read/write cases
105 * In the case of dense layouts, the offset needs to be reset to its 184 * In the case of dense layouts, the offset needs to be reset to its
@@ -109,6 +188,8 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
109{ 188{
110 struct nfs_read_data *rdata = (struct nfs_read_data *)data; 189 struct nfs_read_data *rdata = (struct nfs_read_data *)data;
111 190
191 rdata->read_done_cb = filelayout_read_done_cb;
192
112 if (nfs41_setup_sequence(rdata->ds_clp->cl_session, 193 if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
113 &rdata->args.seq_args, &rdata->res.seq_res, 194 &rdata->args.seq_args, &rdata->res.seq_res,
114 0, task)) 195 0, task))
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index d09623933302..1dc809039448 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3074,15 +3074,10 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
3074 return err; 3074 return err;
3075} 3075}
3076 3076
3077static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) 3077static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
3078{ 3078{
3079 struct nfs_server *server = NFS_SERVER(data->inode); 3079 struct nfs_server *server = NFS_SERVER(data->inode);
3080 3080
3081 dprintk("--> %s\n", __func__);
3082
3083 if (!nfs4_sequence_done(task, &data->res.seq_res))
3084 return -EAGAIN;
3085
3086 if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { 3081 if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
3087 nfs_restart_rpc(task, server->nfs_client); 3082 nfs_restart_rpc(task, server->nfs_client);
3088 return -EAGAIN; 3083 return -EAGAIN;
@@ -3094,12 +3089,40 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
3094 return 0; 3089 return 0;
3095} 3090}
3096 3091
3092static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
3093{
3094
3095 dprintk("--> %s\n", __func__);
3096
3097 if (!nfs4_sequence_done(task, &data->res.seq_res))
3098 return -EAGAIN;
3099
3100 return data->read_done_cb(task, data);
3101}
3102
3097static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg) 3103static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg)
3098{ 3104{
3099 data->timestamp = jiffies; 3105 data->timestamp = jiffies;
3106 data->read_done_cb = nfs4_read_done_cb;
3100 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; 3107 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
3101} 3108}
3102 3109
3110/* Reset the the nfs_read_data to send the read to the MDS. */
3111void nfs4_reset_read(struct rpc_task *task, struct nfs_read_data *data)
3112{
3113 dprintk("%s Reset task for i/o through\n", __func__);
3114 put_lseg(data->lseg);
3115 data->lseg = NULL;
3116 /* offsets will differ in the dense stripe case */
3117 data->args.offset = data->mds_offset;
3118 data->ds_clp = NULL;
3119 data->args.fh = NFS_FH(data->inode);
3120 data->read_done_cb = nfs4_read_done_cb;
3121 task->tk_ops = data->mds_ops;
3122 rpc_task_reset_client(task, NFS_CLIENT(data->inode));
3123}
3124EXPORT_SYMBOL_GPL(nfs4_reset_read);
3125
3103static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) 3126static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
3104{ 3127{
3105 struct inode *inode = data->inode; 3128 struct inode *inode = data->inode;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 69c836373124..ab1bf5bb021f 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1453,6 +1453,7 @@ void nfs4_schedule_session_recovery(struct nfs4_session *session)
1453{ 1453{
1454 nfs4_schedule_lease_recovery(session->clp); 1454 nfs4_schedule_lease_recovery(session->clp);
1455} 1455}
1456EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
1456 1457
1457void nfs41_handle_recall_slot(struct nfs_client *clp) 1458void nfs41_handle_recall_slot(struct nfs_client *clp)
1458{ 1459{
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index f4d0fcffcb5a..f40c7f4dc16b 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -391,6 +391,7 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data
391 return; 391 return;
392 392
393 /* Yes, so retry the read at the end of the data */ 393 /* Yes, so retry the read at the end of the data */
394 data->mds_offset += resp->count;
394 argp->offset += resp->count; 395 argp->offset += resp->count;
395 argp->pgbase += resp->count; 396 argp->pgbase += resp->count;
396 argp->count -= resp->count; 397 argp->count -= resp->count;
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index b63faef5052e..eb0e87084353 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1020,6 +1020,7 @@ struct nfs_read_data {
1020 struct pnfs_layout_segment *lseg; 1020 struct pnfs_layout_segment *lseg;
1021 struct nfs_client *ds_clp; /* pNFS data server */ 1021 struct nfs_client *ds_clp; /* pNFS data server */
1022 const struct rpc_call_ops *mds_ops; 1022 const struct rpc_call_ops *mds_ops;
1023 int (*read_done_cb) (struct rpc_task *task, struct nfs_read_data *data);
1023 __u64 mds_offset; 1024 __u64 mds_offset;
1024 struct page *page_array[NFS_PAGEVEC_SIZE]; 1025 struct page *page_array[NFS_PAGEVEC_SIZE];
1025}; 1026};
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index ef9476a36ff7..db7bcaf7c5bd 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -129,6 +129,7 @@ struct rpc_create_args {
129struct rpc_clnt *rpc_create(struct rpc_create_args *args); 129struct rpc_clnt *rpc_create(struct rpc_create_args *args);
130struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, 130struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
131 struct rpc_program *, u32); 131 struct rpc_program *, u32);
132void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
132struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); 133struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
133void rpc_shutdown_client(struct rpc_clnt *); 134void rpc_shutdown_client(struct rpc_clnt *);
134void rpc_release_client(struct rpc_clnt *); 135void rpc_release_client(struct rpc_clnt *);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 8b5a6b40d37c..edaf56e2ed29 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -597,6 +597,14 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
597 } 597 }
598} 598}
599 599
600void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt)
601{
602 rpc_task_release_client(task);
603 rpc_task_set_client(task, clnt);
604}
605EXPORT_SYMBOL_GPL(rpc_task_reset_client);
606
607
600static void 608static void
601rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg) 609rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg)
602{ 610{