diff options
author | Andy Adamson <andros@netapp.com> | 2012-04-27 17:53:46 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-05-19 17:54:20 -0400 |
commit | e7dd79af01e7ca932c5168a708e77750659f7a9e (patch) | |
tree | dfacd16bce6df877ecae697cd7dbf5f8e0561872 /fs/nfs/nfs4filelayout.c | |
parent | 98fc685ae2aa24eae98526e9196b3229d519083a (diff) |
NFSv4.1: mark deviceid invalid on filelayout DS connection errors
This prevents the use of any layout for i/o that references the deviceid.
I/O is redirected through the MDS.
Redirect the unhandled failed I/O to the MDS without marking either the
layout or the deviceid invalid.
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4filelayout.c')
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 130 |
1 files changed, 97 insertions, 33 deletions
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 0db8c0783039..f503cbe5a21a 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -82,29 +82,77 @@ filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset) | |||
82 | BUG(); | 82 | BUG(); |
83 | } | 83 | } |
84 | 84 | ||
85 | static void filelayout_reset_write(struct nfs_write_data *data) | ||
86 | { | ||
87 | struct nfs_pgio_header *hdr = data->header; | ||
88 | struct inode *inode = hdr->inode; | ||
89 | struct rpc_task *task = &data->task; | ||
90 | |||
91 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { | ||
92 | dprintk("%s Reset task %5u for i/o through MDS " | ||
93 | "(req %s/%lld, %u bytes @ offset %llu)\n", __func__, | ||
94 | data->task.tk_pid, | ||
95 | inode->i_sb->s_id, | ||
96 | (long long)NFS_FILEID(inode), | ||
97 | data->args.count, | ||
98 | (unsigned long long)data->args.offset); | ||
99 | |||
100 | task->tk_status = pnfs_write_done_resend_to_mds(hdr->inode, | ||
101 | &hdr->pages, | ||
102 | hdr->completion_ops); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | static void filelayout_reset_read(struct nfs_read_data *data) | ||
107 | { | ||
108 | struct nfs_pgio_header *hdr = data->header; | ||
109 | struct inode *inode = hdr->inode; | ||
110 | struct rpc_task *task = &data->task; | ||
111 | |||
112 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { | ||
113 | dprintk("%s Reset task %5u for i/o through MDS " | ||
114 | "(req %s/%lld, %u bytes @ offset %llu)\n", __func__, | ||
115 | data->task.tk_pid, | ||
116 | inode->i_sb->s_id, | ||
117 | (long long)NFS_FILEID(inode), | ||
118 | data->args.count, | ||
119 | (unsigned long long)data->args.offset); | ||
120 | |||
121 | task->tk_status = pnfs_read_done_resend_to_mds(hdr->inode, | ||
122 | &hdr->pages, | ||
123 | hdr->completion_ops); | ||
124 | } | ||
125 | } | ||
126 | |||
85 | static int filelayout_async_handle_error(struct rpc_task *task, | 127 | static int filelayout_async_handle_error(struct rpc_task *task, |
86 | struct nfs4_state *state, | 128 | struct nfs4_state *state, |
87 | struct nfs_client *clp, | 129 | struct nfs_client *clp, |
88 | int *reset) | 130 | struct pnfs_layout_segment *lseg) |
89 | { | 131 | { |
90 | struct nfs_server *mds_server = NFS_SERVER(state->inode); | 132 | struct inode *inode = lseg->pls_layout->plh_inode; |
133 | struct nfs_server *mds_server = NFS_SERVER(inode); | ||
134 | struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg); | ||
91 | struct nfs_client *mds_client = mds_server->nfs_client; | 135 | struct nfs_client *mds_client = mds_server->nfs_client; |
92 | 136 | ||
93 | if (task->tk_status >= 0) | 137 | if (task->tk_status >= 0) |
94 | return 0; | 138 | return 0; |
95 | *reset = 0; | ||
96 | 139 | ||
97 | switch (task->tk_status) { | 140 | switch (task->tk_status) { |
98 | /* MDS state errors */ | 141 | /* MDS state errors */ |
99 | case -NFS4ERR_DELEG_REVOKED: | 142 | case -NFS4ERR_DELEG_REVOKED: |
100 | case -NFS4ERR_ADMIN_REVOKED: | 143 | case -NFS4ERR_ADMIN_REVOKED: |
101 | case -NFS4ERR_BAD_STATEID: | 144 | case -NFS4ERR_BAD_STATEID: |
145 | if (state == NULL) | ||
146 | break; | ||
102 | nfs_remove_bad_delegation(state->inode); | 147 | nfs_remove_bad_delegation(state->inode); |
103 | case -NFS4ERR_OPENMODE: | 148 | case -NFS4ERR_OPENMODE: |
149 | if (state == NULL) | ||
150 | break; | ||
104 | nfs4_schedule_stateid_recovery(mds_server, state); | 151 | nfs4_schedule_stateid_recovery(mds_server, state); |
105 | goto wait_on_recovery; | 152 | goto wait_on_recovery; |
106 | case -NFS4ERR_EXPIRED: | 153 | case -NFS4ERR_EXPIRED: |
107 | nfs4_schedule_stateid_recovery(mds_server, state); | 154 | if (state != NULL) |
155 | nfs4_schedule_stateid_recovery(mds_server, state); | ||
108 | nfs4_schedule_lease_recovery(mds_client); | 156 | nfs4_schedule_lease_recovery(mds_client); |
109 | goto wait_on_recovery; | 157 | goto wait_on_recovery; |
110 | /* DS session errors */ | 158 | /* DS session errors */ |
@@ -127,11 +175,22 @@ static int filelayout_async_handle_error(struct rpc_task *task, | |||
127 | break; | 175 | break; |
128 | case -NFS4ERR_RETRY_UNCACHED_REP: | 176 | case -NFS4ERR_RETRY_UNCACHED_REP: |
129 | break; | 177 | break; |
178 | /* RPC connection errors */ | ||
179 | case -ECONNREFUSED: | ||
180 | case -EHOSTDOWN: | ||
181 | case -EHOSTUNREACH: | ||
182 | case -ENETUNREACH: | ||
183 | case -EIO: | ||
184 | case -ETIMEDOUT: | ||
185 | case -EPIPE: | ||
186 | dprintk("%s DS connection error %d\n", __func__, | ||
187 | task->tk_status); | ||
188 | filelayout_mark_devid_invalid(devid); | ||
189 | /* fall through */ | ||
130 | default: | 190 | default: |
131 | dprintk("%s DS error. Retry through MDS %d\n", __func__, | 191 | dprintk("%s Retry through MDS. Error %d\n", __func__, |
132 | task->tk_status); | 192 | task->tk_status); |
133 | *reset = 1; | 193 | return -NFS4ERR_RESET_TO_MDS; |
134 | break; | ||
135 | } | 194 | } |
136 | out: | 195 | out: |
137 | task->tk_status = 0; | 196 | task->tk_status = 0; |
@@ -148,16 +207,17 @@ wait_on_recovery: | |||
148 | static int filelayout_read_done_cb(struct rpc_task *task, | 207 | static int filelayout_read_done_cb(struct rpc_task *task, |
149 | struct nfs_read_data *data) | 208 | struct nfs_read_data *data) |
150 | { | 209 | { |
151 | int reset = 0; | 210 | struct nfs_pgio_header *hdr = data->header; |
211 | int err; | ||
152 | 212 | ||
153 | dprintk("%s DS read\n", __func__); | 213 | err = filelayout_async_handle_error(task, data->args.context->state, |
214 | data->ds_clp, hdr->lseg); | ||
154 | 215 | ||
155 | if (filelayout_async_handle_error(task, data->args.context->state, | 216 | switch (err) { |
156 | data->ds_clp, &reset) == -EAGAIN) { | 217 | case -NFS4ERR_RESET_TO_MDS: |
157 | dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n", | 218 | filelayout_reset_read(data); |
158 | __func__, data->ds_clp, data->ds_clp->cl_session); | 219 | return task->tk_status; |
159 | if (reset) | 220 | case -EAGAIN: |
160 | nfs4_reset_read(task, data); | ||
161 | rpc_restart_call_prepare(task); | 221 | rpc_restart_call_prepare(task); |
162 | return -EAGAIN; | 222 | return -EAGAIN; |
163 | } | 223 | } |
@@ -230,14 +290,17 @@ static void filelayout_read_release(void *data) | |||
230 | static int filelayout_write_done_cb(struct rpc_task *task, | 290 | static int filelayout_write_done_cb(struct rpc_task *task, |
231 | struct nfs_write_data *data) | 291 | struct nfs_write_data *data) |
232 | { | 292 | { |
233 | int reset = 0; | 293 | struct nfs_pgio_header *hdr = data->header; |
234 | 294 | int err; | |
235 | if (filelayout_async_handle_error(task, data->args.context->state, | 295 | |
236 | data->ds_clp, &reset) == -EAGAIN) { | 296 | err = filelayout_async_handle_error(task, data->args.context->state, |
237 | dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n", | 297 | data->ds_clp, hdr->lseg); |
238 | __func__, data->ds_clp, data->ds_clp->cl_session); | 298 | |
239 | if (reset) | 299 | switch (err) { |
240 | nfs4_reset_write(task, data); | 300 | case -NFS4ERR_RESET_TO_MDS: |
301 | filelayout_reset_write(data); | ||
302 | return task->tk_status; | ||
303 | case -EAGAIN: | ||
241 | rpc_restart_call_prepare(task); | 304 | rpc_restart_call_prepare(task); |
242 | return -EAGAIN; | 305 | return -EAGAIN; |
243 | } | 306 | } |
@@ -260,16 +323,17 @@ static void prepare_to_resend_writes(struct nfs_commit_data *data) | |||
260 | static int filelayout_commit_done_cb(struct rpc_task *task, | 323 | static int filelayout_commit_done_cb(struct rpc_task *task, |
261 | struct nfs_commit_data *data) | 324 | struct nfs_commit_data *data) |
262 | { | 325 | { |
263 | int reset = 0; | 326 | int err; |
264 | 327 | ||
265 | if (filelayout_async_handle_error(task, data->context->state, | 328 | err = filelayout_async_handle_error(task, NULL, data->ds_clp, |
266 | data->ds_clp, &reset) == -EAGAIN) { | 329 | data->lseg); |
267 | dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n", | 330 | |
268 | __func__, data->ds_clp, data->ds_clp->cl_session); | 331 | switch (err) { |
269 | if (reset) | 332 | case -NFS4ERR_RESET_TO_MDS: |
270 | prepare_to_resend_writes(data); | 333 | prepare_to_resend_writes(data); |
271 | else | 334 | return -EAGAIN; |
272 | rpc_restart_call_prepare(task); | 335 | case -EAGAIN: |
336 | rpc_restart_call_prepare(task); | ||
273 | return -EAGAIN; | 337 | return -EAGAIN; |
274 | } | 338 | } |
275 | 339 | ||