aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-11-13 18:20:28 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2018-11-29 21:08:14 -0500
commit4584ae96ae307613625e80cb9c7d9a981bed47a7 (patch)
tree3afe04fe4a054f74c7cfe1502cbfcee583b0d9ad /fs/afs
parentae3b7361dc0ee9a425bf7d77ce211f533500b39b (diff)
afs: Fix missing net error handling
kAFS can be given certain network errors (EADDRNOTAVAIL, EHOSTDOWN and ERFKILL) that it doesn't handle in its server/address rotation algorithms. They cause the probing and rotation to abort immediately rather than rotating. Fix this by: (1) Abstracting out the error prioritisation from the VL and FS rotation algorithms into a common function and expand usage into the server probing code. When multiple errors are available, this code selects the one we'd prefer to return. (2) Add handling for EADDRNOTAVAIL, EHOSTDOWN and ERFKILL. Fixes: 0fafdc9f888b ("afs: Fix file locking") Fixes: 0338747d8454 ("afs: Probe multiple fileservers simultaneously") Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/afs')
-rw-r--r--fs/afs/fs_probe.c39
-rw-r--r--fs/afs/internal.h9
-rw-r--r--fs/afs/misc.c52
-rw-r--r--fs/afs/rotate.c53
-rw-r--r--fs/afs/vl_probe.c45
-rw-r--r--fs/afs/vl_rotate.c50
6 files changed, 135 insertions, 113 deletions
diff --git a/fs/afs/fs_probe.c b/fs/afs/fs_probe.c
index d049cb459742..fde6b4d4121e 100644
--- a/fs/afs/fs_probe.c
+++ b/fs/afs/fs_probe.c
@@ -61,8 +61,11 @@ void afs_fileserver_probe_result(struct afs_call *call)
61 afs_io_error(call, afs_io_error_fs_probe_fail); 61 afs_io_error(call, afs_io_error_fs_probe_fail);
62 goto out; 62 goto out;
63 case -ECONNRESET: /* Responded, but call expired. */ 63 case -ECONNRESET: /* Responded, but call expired. */
64 case -ERFKILL:
65 case -EADDRNOTAVAIL:
64 case -ENETUNREACH: 66 case -ENETUNREACH:
65 case -EHOSTUNREACH: 67 case -EHOSTUNREACH:
68 case -EHOSTDOWN:
66 case -ECONNREFUSED: 69 case -ECONNREFUSED:
67 case -ETIMEDOUT: 70 case -ETIMEDOUT:
68 case -ETIME: 71 case -ETIME:
@@ -132,12 +135,14 @@ out:
132static int afs_do_probe_fileserver(struct afs_net *net, 135static int afs_do_probe_fileserver(struct afs_net *net,
133 struct afs_server *server, 136 struct afs_server *server,
134 struct key *key, 137 struct key *key,
135 unsigned int server_index) 138 unsigned int server_index,
139 struct afs_error *_e)
136{ 140{
137 struct afs_addr_cursor ac = { 141 struct afs_addr_cursor ac = {
138 .index = 0, 142 .index = 0,
139 }; 143 };
140 int ret; 144 bool in_progress = false;
145 int err;
141 146
142 _enter("%pU", &server->uuid); 147 _enter("%pU", &server->uuid);
143 148
@@ -151,15 +156,17 @@ static int afs_do_probe_fileserver(struct afs_net *net,
151 server->probe.rtt = UINT_MAX; 156 server->probe.rtt = UINT_MAX;
152 157
153 for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) { 158 for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) {
154 ret = afs_fs_get_capabilities(net, server, &ac, key, server_index, 159 err = afs_fs_get_capabilities(net, server, &ac, key, server_index,
155 true); 160 true);
156 if (ret != -EINPROGRESS) { 161 if (err == -EINPROGRESS)
157 afs_fs_probe_done(server); 162 in_progress = true;
158 return ret; 163 else
159 } 164 afs_prioritise_error(_e, err, ac.abort_code);
160 } 165 }
161 166
162 return 0; 167 if (!in_progress)
168 afs_fs_probe_done(server);
169 return in_progress;
163} 170}
164 171
165/* 172/*
@@ -169,21 +176,23 @@ int afs_probe_fileservers(struct afs_net *net, struct key *key,
169 struct afs_server_list *list) 176 struct afs_server_list *list)
170{ 177{
171 struct afs_server *server; 178 struct afs_server *server;
172 int i, ret; 179 struct afs_error e;
180 bool in_progress = false;
181 int i;
173 182
183 e.error = 0;
184 e.responded = false;
174 for (i = 0; i < list->nr_servers; i++) { 185 for (i = 0; i < list->nr_servers; i++) {
175 server = list->servers[i].server; 186 server = list->servers[i].server;
176 if (test_bit(AFS_SERVER_FL_PROBED, &server->flags)) 187 if (test_bit(AFS_SERVER_FL_PROBED, &server->flags))
177 continue; 188 continue;
178 189
179 if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING, &server->flags)) { 190 if (!test_and_set_bit_lock(AFS_SERVER_FL_PROBING, &server->flags) &&
180 ret = afs_do_probe_fileserver(net, server, key, i); 191 afs_do_probe_fileserver(net, server, key, i, &e))
181 if (ret) 192 in_progress = true;
182 return ret;
183 }
184 } 193 }
185 194
186 return 0; 195 return in_progress ? 0 : e.error;
187} 196}
188 197
189/* 198/*
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 5da3b09b7518..8871b9e8645f 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -696,6 +696,14 @@ struct afs_interface {
696}; 696};
697 697
698/* 698/*
699 * Error prioritisation and accumulation.
700 */
701struct afs_error {
702 short error; /* Accumulated error */
703 bool responded; /* T if server responded */
704};
705
706/*
699 * Cursor for iterating over a server's address list. 707 * Cursor for iterating over a server's address list.
700 */ 708 */
701struct afs_addr_cursor { 709struct afs_addr_cursor {
@@ -1015,6 +1023,7 @@ static inline void __afs_stat(atomic_t *s)
1015 * misc.c 1023 * misc.c
1016 */ 1024 */
1017extern int afs_abort_to_error(u32); 1025extern int afs_abort_to_error(u32);
1026extern void afs_prioritise_error(struct afs_error *, int, u32);
1018 1027
1019/* 1028/*
1020 * mntpt.c 1029 * mntpt.c
diff --git a/fs/afs/misc.c b/fs/afs/misc.c
index 700a5fa7f4ec..bbb1fd51b019 100644
--- a/fs/afs/misc.c
+++ b/fs/afs/misc.c
@@ -118,3 +118,55 @@ int afs_abort_to_error(u32 abort_code)
118 default: return -EREMOTEIO; 118 default: return -EREMOTEIO;
119 } 119 }
120} 120}
121
122/*
123 * Select the error to report from a set of errors.
124 */
125void afs_prioritise_error(struct afs_error *e, int error, u32 abort_code)
126{
127 switch (error) {
128 case 0:
129 return;
130 default:
131 if (e->error == -ETIMEDOUT ||
132 e->error == -ETIME)
133 return;
134 case -ETIMEDOUT:
135 case -ETIME:
136 if (e->error == -ENOMEM ||
137 e->error == -ENONET)
138 return;
139 case -ENOMEM:
140 case -ENONET:
141 if (e->error == -ERFKILL)
142 return;
143 case -ERFKILL:
144 if (e->error == -EADDRNOTAVAIL)
145 return;
146 case -EADDRNOTAVAIL:
147 if (e->error == -ENETUNREACH)
148 return;
149 case -ENETUNREACH:
150 if (e->error == -EHOSTUNREACH)
151 return;
152 case -EHOSTUNREACH:
153 if (e->error == -EHOSTDOWN)
154 return;
155 case -EHOSTDOWN:
156 if (e->error == -ECONNREFUSED)
157 return;
158 case -ECONNREFUSED:
159 if (e->error == -ECONNRESET)
160 return;
161 case -ECONNRESET: /* Responded, but call expired. */
162 if (e->responded)
163 return;
164 e->error = error;
165 return;
166
167 case -ECONNABORTED:
168 e->responded = true;
169 e->error = afs_abort_to_error(abort_code);
170 return;
171 }
172}
diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c
index 00504254c1c2..c3ae324781f8 100644
--- a/fs/afs/rotate.c
+++ b/fs/afs/rotate.c
@@ -136,7 +136,8 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
136 struct afs_addr_list *alist; 136 struct afs_addr_list *alist;
137 struct afs_server *server; 137 struct afs_server *server;
138 struct afs_vnode *vnode = fc->vnode; 138 struct afs_vnode *vnode = fc->vnode;
139 u32 rtt, abort_code; 139 struct afs_error e;
140 u32 rtt;
140 int error = fc->ac.error, i; 141 int error = fc->ac.error, i;
141 142
142 _enter("%lx[%d],%lx[%d],%d,%d", 143 _enter("%lx[%d],%lx[%d],%d,%d",
@@ -306,8 +307,11 @@ bool afs_select_fileserver(struct afs_fs_cursor *fc)
306 if (fc->error != -EDESTADDRREQ) 307 if (fc->error != -EDESTADDRREQ)
307 goto iterate_address; 308 goto iterate_address;
308 /* Fall through */ 309 /* Fall through */
310 case -ERFKILL:
311 case -EADDRNOTAVAIL:
309 case -ENETUNREACH: 312 case -ENETUNREACH:
310 case -EHOSTUNREACH: 313 case -EHOSTUNREACH:
314 case -EHOSTDOWN:
311 case -ECONNREFUSED: 315 case -ECONNREFUSED:
312 _debug("no conn"); 316 _debug("no conn");
313 fc->error = error; 317 fc->error = error;
@@ -446,50 +450,15 @@ no_more_servers:
446 if (fc->flags & AFS_FS_CURSOR_VBUSY) 450 if (fc->flags & AFS_FS_CURSOR_VBUSY)
447 goto restart_from_beginning; 451 goto restart_from_beginning;
448 452
449 abort_code = 0; 453 e.error = -EDESTADDRREQ;
450 error = -EDESTADDRREQ; 454 e.responded = false;
451 for (i = 0; i < fc->server_list->nr_servers; i++) { 455 for (i = 0; i < fc->server_list->nr_servers; i++) {
452 struct afs_server *s = fc->server_list->servers[i].server; 456 struct afs_server *s = fc->server_list->servers[i].server;
453 int probe_error = READ_ONCE(s->probe.error);
454 457
455 switch (probe_error) { 458 afs_prioritise_error(&e, READ_ONCE(s->probe.error),
456 case 0: 459 s->probe.abort_code);
457 continue;
458 default:
459 if (error == -ETIMEDOUT ||
460 error == -ETIME)
461 continue;
462 case -ETIMEDOUT:
463 case -ETIME:
464 if (error == -ENOMEM ||
465 error == -ENONET)
466 continue;
467 case -ENOMEM:
468 case -ENONET:
469 if (error == -ENETUNREACH)
470 continue;
471 case -ENETUNREACH:
472 if (error == -EHOSTUNREACH)
473 continue;
474 case -EHOSTUNREACH:
475 if (error == -ECONNREFUSED)
476 continue;
477 case -ECONNREFUSED:
478 if (error == -ECONNRESET)
479 continue;
480 case -ECONNRESET: /* Responded, but call expired. */
481 if (error == -ECONNABORTED)
482 continue;
483 case -ECONNABORTED:
484 abort_code = s->probe.abort_code;
485 error = probe_error;
486 continue;
487 }
488 } 460 }
489 461
490 if (error == -ECONNABORTED)
491 error = afs_abort_to_error(abort_code);
492
493failed_set_error: 462failed_set_error:
494 fc->error = error; 463 fc->error = error;
495failed: 464failed:
@@ -553,8 +522,11 @@ bool afs_select_current_fileserver(struct afs_fs_cursor *fc)
553 _leave(" = f [abort]"); 522 _leave(" = f [abort]");
554 return false; 523 return false;
555 524
525 case -ERFKILL:
526 case -EADDRNOTAVAIL:
556 case -ENETUNREACH: 527 case -ENETUNREACH:
557 case -EHOSTUNREACH: 528 case -EHOSTUNREACH:
529 case -EHOSTDOWN:
558 case -ECONNREFUSED: 530 case -ECONNREFUSED:
559 case -ETIMEDOUT: 531 case -ETIMEDOUT:
560 case -ETIME: 532 case -ETIME:
@@ -633,6 +605,7 @@ int afs_end_vnode_operation(struct afs_fs_cursor *fc)
633 struct afs_net *net = afs_v2net(fc->vnode); 605 struct afs_net *net = afs_v2net(fc->vnode);
634 606
635 if (fc->error == -EDESTADDRREQ || 607 if (fc->error == -EDESTADDRREQ ||
608 fc->error == -EADDRNOTAVAIL ||
636 fc->error == -ENETUNREACH || 609 fc->error == -ENETUNREACH ||
637 fc->error == -EHOSTUNREACH) 610 fc->error == -EHOSTUNREACH)
638 afs_dump_edestaddrreq(fc); 611 afs_dump_edestaddrreq(fc);
diff --git a/fs/afs/vl_probe.c b/fs/afs/vl_probe.c
index c0f616bd70cb..f0b032976487 100644
--- a/fs/afs/vl_probe.c
+++ b/fs/afs/vl_probe.c
@@ -61,8 +61,11 @@ void afs_vlserver_probe_result(struct afs_call *call)
61 afs_io_error(call, afs_io_error_vl_probe_fail); 61 afs_io_error(call, afs_io_error_vl_probe_fail);
62 goto out; 62 goto out;
63 case -ECONNRESET: /* Responded, but call expired. */ 63 case -ECONNRESET: /* Responded, but call expired. */
64 case -ERFKILL:
65 case -EADDRNOTAVAIL:
64 case -ENETUNREACH: 66 case -ENETUNREACH:
65 case -EHOSTUNREACH: 67 case -EHOSTUNREACH:
68 case -EHOSTDOWN:
66 case -ECONNREFUSED: 69 case -ECONNREFUSED:
67 case -ETIMEDOUT: 70 case -ETIMEDOUT:
68 case -ETIME: 71 case -ETIME:
@@ -129,15 +132,17 @@ out:
129 * Probe all of a vlserver's addresses to find out the best route and to 132 * Probe all of a vlserver's addresses to find out the best route and to
130 * query its capabilities. 133 * query its capabilities.
131 */ 134 */
132static int afs_do_probe_vlserver(struct afs_net *net, 135static bool afs_do_probe_vlserver(struct afs_net *net,
133 struct afs_vlserver *server, 136 struct afs_vlserver *server,
134 struct key *key, 137 struct key *key,
135 unsigned int server_index) 138 unsigned int server_index,
139 struct afs_error *_e)
136{ 140{
137 struct afs_addr_cursor ac = { 141 struct afs_addr_cursor ac = {
138 .index = 0, 142 .index = 0,
139 }; 143 };
140 int ret; 144 bool in_progress = false;
145 int err;
141 146
142 _enter("%s", server->name); 147 _enter("%s", server->name);
143 148
@@ -151,15 +156,17 @@ static int afs_do_probe_vlserver(struct afs_net *net,
151 server->probe.rtt = UINT_MAX; 156 server->probe.rtt = UINT_MAX;
152 157
153 for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) { 158 for (ac.index = 0; ac.index < ac.alist->nr_addrs; ac.index++) {
154 ret = afs_vl_get_capabilities(net, &ac, key, server, 159 err = afs_vl_get_capabilities(net, &ac, key, server,
155 server_index, true); 160 server_index, true);
156 if (ret != -EINPROGRESS) { 161 if (err == -EINPROGRESS)
157 afs_vl_probe_done(server); 162 in_progress = true;
158 return ret; 163 else
159 } 164 afs_prioritise_error(_e, err, ac.abort_code);
160 } 165 }
161 166
162 return 0; 167 if (!in_progress)
168 afs_vl_probe_done(server);
169 return in_progress;
163} 170}
164 171
165/* 172/*
@@ -169,21 +176,23 @@ int afs_send_vl_probes(struct afs_net *net, struct key *key,
169 struct afs_vlserver_list *vllist) 176 struct afs_vlserver_list *vllist)
170{ 177{
171 struct afs_vlserver *server; 178 struct afs_vlserver *server;
172 int i, ret; 179 struct afs_error e;
180 bool in_progress = false;
181 int i;
173 182
183 e.error = 0;
184 e.responded = false;
174 for (i = 0; i < vllist->nr_servers; i++) { 185 for (i = 0; i < vllist->nr_servers; i++) {
175 server = vllist->servers[i].server; 186 server = vllist->servers[i].server;
176 if (test_bit(AFS_VLSERVER_FL_PROBED, &server->flags)) 187 if (test_bit(AFS_VLSERVER_FL_PROBED, &server->flags))
177 continue; 188 continue;
178 189
179 if (!test_and_set_bit_lock(AFS_VLSERVER_FL_PROBING, &server->flags)) { 190 if (!test_and_set_bit_lock(AFS_VLSERVER_FL_PROBING, &server->flags) &&
180 ret = afs_do_probe_vlserver(net, server, key, i); 191 afs_do_probe_vlserver(net, server, key, i, &e))
181 if (ret) 192 in_progress = true;
182 return ret;
183 }
184 } 193 }
185 194
186 return 0; 195 return in_progress ? 0 : e.error;
187} 196}
188 197
189/* 198/*
diff --git a/fs/afs/vl_rotate.c b/fs/afs/vl_rotate.c
index b64a284b99d2..7adde83a0648 100644
--- a/fs/afs/vl_rotate.c
+++ b/fs/afs/vl_rotate.c
@@ -71,8 +71,9 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)
71{ 71{
72 struct afs_addr_list *alist; 72 struct afs_addr_list *alist;
73 struct afs_vlserver *vlserver; 73 struct afs_vlserver *vlserver;
74 struct afs_error e;
74 u32 rtt; 75 u32 rtt;
75 int error = vc->ac.error, abort_code, i; 76 int error = vc->ac.error, i;
76 77
77 _enter("%lx[%d],%lx[%d],%d,%d", 78 _enter("%lx[%d],%lx[%d],%d,%d",
78 vc->untried, vc->index, 79 vc->untried, vc->index,
@@ -119,8 +120,11 @@ bool afs_select_vlserver(struct afs_vl_cursor *vc)
119 goto failed; 120 goto failed;
120 } 121 }
121 122
123 case -ERFKILL:
124 case -EADDRNOTAVAIL:
122 case -ENETUNREACH: 125 case -ENETUNREACH:
123 case -EHOSTUNREACH: 126 case -EHOSTUNREACH:
127 case -EHOSTDOWN:
124 case -ECONNREFUSED: 128 case -ECONNREFUSED:
125 case -ETIMEDOUT: 129 case -ETIMEDOUT:
126 case -ETIME: 130 case -ETIME:
@@ -235,50 +239,15 @@ no_more_servers:
235 if (vc->flags & AFS_VL_CURSOR_RETRY) 239 if (vc->flags & AFS_VL_CURSOR_RETRY)
236 goto restart_from_beginning; 240 goto restart_from_beginning;
237 241
238 abort_code = 0; 242 e.error = -EDESTADDRREQ;
239 error = -EDESTADDRREQ; 243 e.responded = false;
240 for (i = 0; i < vc->server_list->nr_servers; i++) { 244 for (i = 0; i < vc->server_list->nr_servers; i++) {
241 struct afs_vlserver *s = vc->server_list->servers[i].server; 245 struct afs_vlserver *s = vc->server_list->servers[i].server;
242 int probe_error = READ_ONCE(s->probe.error);
243 246
244 switch (probe_error) { 247 afs_prioritise_error(&e, READ_ONCE(s->probe.error),
245 case 0: 248 s->probe.abort_code);
246 continue;
247 default:
248 if (error == -ETIMEDOUT ||
249 error == -ETIME)
250 continue;
251 case -ETIMEDOUT:
252 case -ETIME:
253 if (error == -ENOMEM ||
254 error == -ENONET)
255 continue;
256 case -ENOMEM:
257 case -ENONET:
258 if (error == -ENETUNREACH)
259 continue;
260 case -ENETUNREACH:
261 if (error == -EHOSTUNREACH)
262 continue;
263 case -EHOSTUNREACH:
264 if (error == -ECONNREFUSED)
265 continue;
266 case -ECONNREFUSED:
267 if (error == -ECONNRESET)
268 continue;
269 case -ECONNRESET: /* Responded, but call expired. */
270 if (error == -ECONNABORTED)
271 continue;
272 case -ECONNABORTED:
273 abort_code = s->probe.abort_code;
274 error = probe_error;
275 continue;
276 }
277 } 249 }
278 250
279 if (error == -ECONNABORTED)
280 error = afs_abort_to_error(abort_code);
281
282failed_set_error: 251failed_set_error:
283 vc->error = error; 252 vc->error = error;
284failed: 253failed:
@@ -341,6 +310,7 @@ int afs_end_vlserver_operation(struct afs_vl_cursor *vc)
341 struct afs_net *net = vc->cell->net; 310 struct afs_net *net = vc->cell->net;
342 311
343 if (vc->error == -EDESTADDRREQ || 312 if (vc->error == -EDESTADDRREQ ||
313 vc->error == -EADDRNOTAVAIL ||
344 vc->error == -ENETUNREACH || 314 vc->error == -ENETUNREACH ||
345 vc->error == -EHOSTUNREACH) 315 vc->error == -EHOSTUNREACH)
346 afs_vl_dump_edestaddrreq(vc); 316 afs_vl_dump_edestaddrreq(vc);