.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* Handle fileserver selection and rotation. |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. |
---|
4 | 5 | * Written by David Howells (dhowells@redhat.com) |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or |
---|
7 | | - * modify it under the terms of the GNU General Public Licence |
---|
8 | | - * as published by the Free Software Foundation; either version |
---|
9 | | - * 2 of the Licence, or (at your option) any later version. |
---|
10 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #include <linux/kernel.h> |
---|
.. | .. |
---|
19 | 15 | #include "afs_fs.h" |
---|
20 | 16 | |
---|
21 | 17 | /* |
---|
22 | | - * Initialise a filesystem server cursor for iterating over FS servers. |
---|
23 | | - */ |
---|
24 | | -static void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode) |
---|
25 | | -{ |
---|
26 | | - memset(fc, 0, sizeof(*fc)); |
---|
27 | | -} |
---|
28 | | - |
---|
29 | | -/* |
---|
30 | | - * Begin an operation on the fileserver. |
---|
31 | | - * |
---|
32 | | - * Fileserver operations are serialised on the server by vnode, so we serialise |
---|
33 | | - * them here also using the io_lock. |
---|
34 | | - */ |
---|
35 | | -bool afs_begin_vnode_operation(struct afs_fs_cursor *fc, struct afs_vnode *vnode, |
---|
36 | | - struct key *key) |
---|
37 | | -{ |
---|
38 | | - afs_init_fs_cursor(fc, vnode); |
---|
39 | | - fc->vnode = vnode; |
---|
40 | | - fc->key = key; |
---|
41 | | - fc->ac.error = SHRT_MAX; |
---|
42 | | - |
---|
43 | | - if (mutex_lock_interruptible(&vnode->io_lock) < 0) { |
---|
44 | | - fc->ac.error = -EINTR; |
---|
45 | | - fc->flags |= AFS_FS_CURSOR_STOP; |
---|
46 | | - return false; |
---|
47 | | - } |
---|
48 | | - |
---|
49 | | - if (vnode->lock_state != AFS_VNODE_LOCK_NONE) |
---|
50 | | - fc->flags |= AFS_FS_CURSOR_CUR_ONLY; |
---|
51 | | - return true; |
---|
52 | | -} |
---|
53 | | - |
---|
54 | | -/* |
---|
55 | 18 | * Begin iteration through a server list, starting with the vnode's last used |
---|
56 | 19 | * server if possible, or the last recorded good server if not. |
---|
57 | 20 | */ |
---|
58 | | -static bool afs_start_fs_iteration(struct afs_fs_cursor *fc, |
---|
| 21 | +static bool afs_start_fs_iteration(struct afs_operation *op, |
---|
59 | 22 | struct afs_vnode *vnode) |
---|
60 | 23 | { |
---|
61 | | - struct afs_cb_interest *cbi; |
---|
| 24 | + struct afs_server *server; |
---|
| 25 | + void *cb_server; |
---|
62 | 26 | int i; |
---|
63 | 27 | |
---|
64 | | - read_lock(&vnode->volume->servers_lock); |
---|
65 | | - fc->server_list = afs_get_serverlist(vnode->volume->servers); |
---|
66 | | - read_unlock(&vnode->volume->servers_lock); |
---|
| 28 | + read_lock(&op->volume->servers_lock); |
---|
| 29 | + op->server_list = afs_get_serverlist( |
---|
| 30 | + rcu_dereference_protected(op->volume->servers, |
---|
| 31 | + lockdep_is_held(&op->volume->servers_lock))); |
---|
| 32 | + read_unlock(&op->volume->servers_lock); |
---|
67 | 33 | |
---|
68 | | - cbi = vnode->cb_interest; |
---|
69 | | - if (cbi) { |
---|
| 34 | + op->untried = (1UL << op->server_list->nr_servers) - 1; |
---|
| 35 | + op->index = READ_ONCE(op->server_list->preferred); |
---|
| 36 | + |
---|
| 37 | + cb_server = vnode->cb_server; |
---|
| 38 | + if (cb_server) { |
---|
70 | 39 | /* See if the vnode's preferred record is still available */ |
---|
71 | | - for (i = 0; i < fc->server_list->nr_servers; i++) { |
---|
72 | | - if (fc->server_list->servers[i].cb_interest == cbi) { |
---|
73 | | - fc->start = i; |
---|
| 40 | + for (i = 0; i < op->server_list->nr_servers; i++) { |
---|
| 41 | + server = op->server_list->servers[i].server; |
---|
| 42 | + if (server == cb_server) { |
---|
| 43 | + op->index = i; |
---|
74 | 44 | goto found_interest; |
---|
75 | 45 | } |
---|
76 | 46 | } |
---|
.. | .. |
---|
79 | 49 | * serving this vnode, then we can't switch to another server |
---|
80 | 50 | * and have to return an error. |
---|
81 | 51 | */ |
---|
82 | | - if (fc->flags & AFS_FS_CURSOR_CUR_ONLY) { |
---|
83 | | - fc->ac.error = -ESTALE; |
---|
| 52 | + if (op->flags & AFS_OPERATION_CUR_ONLY) { |
---|
| 53 | + op->error = -ESTALE; |
---|
84 | 54 | return false; |
---|
85 | 55 | } |
---|
86 | 56 | |
---|
87 | 57 | /* Note that the callback promise is effectively broken */ |
---|
88 | 58 | write_seqlock(&vnode->cb_lock); |
---|
89 | | - ASSERTCMP(cbi, ==, vnode->cb_interest); |
---|
90 | | - vnode->cb_interest = NULL; |
---|
| 59 | + ASSERTCMP(cb_server, ==, vnode->cb_server); |
---|
| 60 | + vnode->cb_server = NULL; |
---|
91 | 61 | if (test_and_clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags)) |
---|
92 | 62 | vnode->cb_break++; |
---|
93 | 63 | write_sequnlock(&vnode->cb_lock); |
---|
94 | | - |
---|
95 | | - afs_put_cb_interest(afs_v2net(vnode), cbi); |
---|
96 | | - cbi = NULL; |
---|
97 | | - } else { |
---|
98 | | - fc->start = READ_ONCE(fc->server_list->index); |
---|
99 | 64 | } |
---|
100 | 65 | |
---|
101 | 66 | found_interest: |
---|
102 | | - fc->index = fc->start; |
---|
103 | 67 | return true; |
---|
104 | 68 | } |
---|
105 | 69 | |
---|
.. | .. |
---|
117 | 81 | default: m = "busy"; break; |
---|
118 | 82 | } |
---|
119 | 83 | |
---|
120 | | - pr_notice("kAFS: Volume %u '%s' is %s\n", volume->vid, volume->name, m); |
---|
| 84 | + pr_notice("kAFS: Volume %llu '%s' is %s\n", volume->vid, volume->name, m); |
---|
121 | 85 | } |
---|
122 | 86 | |
---|
123 | 87 | /* |
---|
124 | 88 | * Sleep and retry the operation to the same fileserver. |
---|
125 | 89 | */ |
---|
126 | | -static bool afs_sleep_and_retry(struct afs_fs_cursor *fc) |
---|
| 90 | +static bool afs_sleep_and_retry(struct afs_operation *op) |
---|
127 | 91 | { |
---|
128 | | - msleep_interruptible(1000); |
---|
129 | | - if (signal_pending(current)) { |
---|
130 | | - fc->ac.error = -ERESTARTSYS; |
---|
131 | | - return false; |
---|
| 92 | + if (!(op->flags & AFS_OPERATION_UNINTR)) { |
---|
| 93 | + msleep_interruptible(1000); |
---|
| 94 | + if (signal_pending(current)) { |
---|
| 95 | + op->error = -ERESTARTSYS; |
---|
| 96 | + return false; |
---|
| 97 | + } |
---|
| 98 | + } else { |
---|
| 99 | + msleep(1000); |
---|
132 | 100 | } |
---|
133 | 101 | |
---|
134 | 102 | return true; |
---|
.. | .. |
---|
138 | 106 | * Select the fileserver to use. May be called multiple times to rotate |
---|
139 | 107 | * through the fileservers. |
---|
140 | 108 | */ |
---|
141 | | -bool afs_select_fileserver(struct afs_fs_cursor *fc) |
---|
| 109 | +bool afs_select_fileserver(struct afs_operation *op) |
---|
142 | 110 | { |
---|
143 | 111 | struct afs_addr_list *alist; |
---|
144 | 112 | struct afs_server *server; |
---|
145 | | - struct afs_vnode *vnode = fc->vnode; |
---|
| 113 | + struct afs_vnode *vnode = op->file[0].vnode; |
---|
| 114 | + struct afs_error e; |
---|
| 115 | + u32 rtt; |
---|
| 116 | + int error = op->ac.error, i; |
---|
146 | 117 | |
---|
147 | | - _enter("%u/%u,%u/%u,%d,%d", |
---|
148 | | - fc->index, fc->start, |
---|
149 | | - fc->ac.index, fc->ac.start, |
---|
150 | | - fc->ac.error, fc->ac.abort_code); |
---|
| 118 | + _enter("%lx[%d],%lx[%d],%d,%d", |
---|
| 119 | + op->untried, op->index, |
---|
| 120 | + op->ac.tried, op->ac.index, |
---|
| 121 | + error, op->ac.abort_code); |
---|
151 | 122 | |
---|
152 | | - if (fc->flags & AFS_FS_CURSOR_STOP) { |
---|
| 123 | + if (op->flags & AFS_OPERATION_STOP) { |
---|
153 | 124 | _leave(" = f [stopped]"); |
---|
154 | 125 | return false; |
---|
155 | 126 | } |
---|
156 | 127 | |
---|
| 128 | + op->nr_iterations++; |
---|
| 129 | + |
---|
157 | 130 | /* Evaluate the result of the previous operation, if there was one. */ |
---|
158 | | - switch (fc->ac.error) { |
---|
| 131 | + switch (error) { |
---|
159 | 132 | case SHRT_MAX: |
---|
160 | 133 | goto start; |
---|
161 | 134 | |
---|
162 | 135 | case 0: |
---|
163 | 136 | default: |
---|
164 | 137 | /* Success or local failure. Stop. */ |
---|
165 | | - fc->flags |= AFS_FS_CURSOR_STOP; |
---|
166 | | - _leave(" = f [okay/local %d]", fc->ac.error); |
---|
| 138 | + op->error = error; |
---|
| 139 | + op->flags |= AFS_OPERATION_STOP; |
---|
| 140 | + _leave(" = f [okay/local %d]", error); |
---|
167 | 141 | return false; |
---|
168 | 142 | |
---|
169 | 143 | case -ECONNABORTED: |
---|
170 | 144 | /* The far side rejected the operation on some grounds. This |
---|
171 | 145 | * might involve the server being busy or the volume having been moved. |
---|
172 | 146 | */ |
---|
173 | | - switch (fc->ac.abort_code) { |
---|
| 147 | + switch (op->ac.abort_code) { |
---|
174 | 148 | case VNOVOL: |
---|
175 | 149 | /* This fileserver doesn't know about the volume. |
---|
176 | 150 | * - May indicate that the VL is wrong - retry once and compare |
---|
177 | 151 | * the results. |
---|
178 | 152 | * - May indicate that the fileserver couldn't attach to the vol. |
---|
179 | 153 | */ |
---|
180 | | - if (fc->flags & AFS_FS_CURSOR_VNOVOL) { |
---|
181 | | - fc->ac.error = -EREMOTEIO; |
---|
| 154 | + if (op->flags & AFS_OPERATION_VNOVOL) { |
---|
| 155 | + op->error = -EREMOTEIO; |
---|
182 | 156 | goto next_server; |
---|
183 | 157 | } |
---|
184 | 158 | |
---|
185 | | - write_lock(&vnode->volume->servers_lock); |
---|
186 | | - fc->server_list->vnovol_mask |= 1 << fc->index; |
---|
187 | | - write_unlock(&vnode->volume->servers_lock); |
---|
| 159 | + write_lock(&op->volume->servers_lock); |
---|
| 160 | + op->server_list->vnovol_mask |= 1 << op->index; |
---|
| 161 | + write_unlock(&op->volume->servers_lock); |
---|
188 | 162 | |
---|
189 | | - set_bit(AFS_VOLUME_NEEDS_UPDATE, &vnode->volume->flags); |
---|
190 | | - fc->ac.error = afs_check_volume_status(vnode->volume, fc->key); |
---|
191 | | - if (fc->ac.error < 0) |
---|
192 | | - goto failed; |
---|
| 163 | + set_bit(AFS_VOLUME_NEEDS_UPDATE, &op->volume->flags); |
---|
| 164 | + error = afs_check_volume_status(op->volume, op); |
---|
| 165 | + if (error < 0) |
---|
| 166 | + goto failed_set_error; |
---|
193 | 167 | |
---|
194 | | - if (test_bit(AFS_VOLUME_DELETED, &vnode->volume->flags)) { |
---|
195 | | - fc->ac.error = -ENOMEDIUM; |
---|
| 168 | + if (test_bit(AFS_VOLUME_DELETED, &op->volume->flags)) { |
---|
| 169 | + op->error = -ENOMEDIUM; |
---|
196 | 170 | goto failed; |
---|
197 | 171 | } |
---|
198 | 172 | |
---|
199 | 173 | /* If the server list didn't change, then assume that |
---|
200 | 174 | * it's the fileserver having trouble. |
---|
201 | 175 | */ |
---|
202 | | - if (vnode->volume->servers == fc->server_list) { |
---|
203 | | - fc->ac.error = -EREMOTEIO; |
---|
| 176 | + if (rcu_access_pointer(op->volume->servers) == op->server_list) { |
---|
| 177 | + op->error = -EREMOTEIO; |
---|
204 | 178 | goto next_server; |
---|
205 | 179 | } |
---|
206 | 180 | |
---|
207 | 181 | /* Try again */ |
---|
208 | | - fc->flags |= AFS_FS_CURSOR_VNOVOL; |
---|
| 182 | + op->flags |= AFS_OPERATION_VNOVOL; |
---|
209 | 183 | _leave(" = t [vnovol]"); |
---|
210 | 184 | return true; |
---|
211 | 185 | |
---|
.. | .. |
---|
215 | 189 | case VONLINE: |
---|
216 | 190 | case VDISKFULL: |
---|
217 | 191 | case VOVERQUOTA: |
---|
218 | | - fc->ac.error = afs_abort_to_error(fc->ac.abort_code); |
---|
| 192 | + op->error = afs_abort_to_error(op->ac.abort_code); |
---|
219 | 193 | goto next_server; |
---|
220 | 194 | |
---|
221 | 195 | case VOFFLINE: |
---|
222 | | - if (!test_and_set_bit(AFS_VOLUME_OFFLINE, &vnode->volume->flags)) { |
---|
223 | | - afs_busy(vnode->volume, fc->ac.abort_code); |
---|
224 | | - clear_bit(AFS_VOLUME_BUSY, &vnode->volume->flags); |
---|
| 196 | + if (!test_and_set_bit(AFS_VOLUME_OFFLINE, &op->volume->flags)) { |
---|
| 197 | + afs_busy(op->volume, op->ac.abort_code); |
---|
| 198 | + clear_bit(AFS_VOLUME_BUSY, &op->volume->flags); |
---|
225 | 199 | } |
---|
226 | | - if (fc->flags & AFS_FS_CURSOR_NO_VSLEEP) { |
---|
227 | | - fc->ac.error = -EADV; |
---|
| 200 | + if (op->flags & AFS_OPERATION_NO_VSLEEP) { |
---|
| 201 | + op->error = -EADV; |
---|
228 | 202 | goto failed; |
---|
229 | 203 | } |
---|
230 | | - if (fc->flags & AFS_FS_CURSOR_CUR_ONLY) { |
---|
231 | | - fc->ac.error = -ESTALE; |
---|
| 204 | + if (op->flags & AFS_OPERATION_CUR_ONLY) { |
---|
| 205 | + op->error = -ESTALE; |
---|
232 | 206 | goto failed; |
---|
233 | 207 | } |
---|
234 | 208 | goto busy; |
---|
.. | .. |
---|
239 | 213 | /* Retry after going round all the servers unless we |
---|
240 | 214 | * have a file lock we need to maintain. |
---|
241 | 215 | */ |
---|
242 | | - if (fc->flags & AFS_FS_CURSOR_NO_VSLEEP) { |
---|
243 | | - fc->ac.error = -EBUSY; |
---|
| 216 | + if (op->flags & AFS_OPERATION_NO_VSLEEP) { |
---|
| 217 | + op->error = -EBUSY; |
---|
244 | 218 | goto failed; |
---|
245 | 219 | } |
---|
246 | | - if (!test_and_set_bit(AFS_VOLUME_BUSY, &vnode->volume->flags)) { |
---|
247 | | - afs_busy(vnode->volume, fc->ac.abort_code); |
---|
248 | | - clear_bit(AFS_VOLUME_OFFLINE, &vnode->volume->flags); |
---|
| 220 | + if (!test_and_set_bit(AFS_VOLUME_BUSY, &op->volume->flags)) { |
---|
| 221 | + afs_busy(op->volume, op->ac.abort_code); |
---|
| 222 | + clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags); |
---|
249 | 223 | } |
---|
250 | 224 | busy: |
---|
251 | | - if (fc->flags & AFS_FS_CURSOR_CUR_ONLY) { |
---|
252 | | - if (!afs_sleep_and_retry(fc)) |
---|
| 225 | + if (op->flags & AFS_OPERATION_CUR_ONLY) { |
---|
| 226 | + if (!afs_sleep_and_retry(op)) |
---|
253 | 227 | goto failed; |
---|
254 | 228 | |
---|
255 | 229 | /* Retry with same server & address */ |
---|
.. | .. |
---|
257 | 231 | return true; |
---|
258 | 232 | } |
---|
259 | 233 | |
---|
260 | | - fc->flags |= AFS_FS_CURSOR_VBUSY; |
---|
| 234 | + op->flags |= AFS_OPERATION_VBUSY; |
---|
261 | 235 | goto next_server; |
---|
262 | 236 | |
---|
263 | 237 | case VMOVED: |
---|
.. | .. |
---|
268 | 242 | * We also limit the number of VMOVED hops we will |
---|
269 | 243 | * honour, just in case someone sets up a loop. |
---|
270 | 244 | */ |
---|
271 | | - if (fc->flags & AFS_FS_CURSOR_VMOVED) { |
---|
272 | | - fc->ac.error = -EREMOTEIO; |
---|
| 245 | + if (op->flags & AFS_OPERATION_VMOVED) { |
---|
| 246 | + op->error = -EREMOTEIO; |
---|
273 | 247 | goto failed; |
---|
274 | 248 | } |
---|
275 | | - fc->flags |= AFS_FS_CURSOR_VMOVED; |
---|
| 249 | + op->flags |= AFS_OPERATION_VMOVED; |
---|
276 | 250 | |
---|
277 | | - set_bit(AFS_VOLUME_WAIT, &vnode->volume->flags); |
---|
278 | | - set_bit(AFS_VOLUME_NEEDS_UPDATE, &vnode->volume->flags); |
---|
279 | | - fc->ac.error = afs_check_volume_status(vnode->volume, fc->key); |
---|
280 | | - if (fc->ac.error < 0) |
---|
281 | | - goto failed; |
---|
| 251 | + set_bit(AFS_VOLUME_WAIT, &op->volume->flags); |
---|
| 252 | + set_bit(AFS_VOLUME_NEEDS_UPDATE, &op->volume->flags); |
---|
| 253 | + error = afs_check_volume_status(op->volume, op); |
---|
| 254 | + if (error < 0) |
---|
| 255 | + goto failed_set_error; |
---|
282 | 256 | |
---|
283 | 257 | /* If the server list didn't change, then the VLDB is |
---|
284 | 258 | * out of sync with the fileservers. This is hopefully |
---|
.. | .. |
---|
289 | 263 | * |
---|
290 | 264 | * TODO: Retry a few times with sleeps. |
---|
291 | 265 | */ |
---|
292 | | - if (vnode->volume->servers == fc->server_list) { |
---|
293 | | - fc->ac.error = -ENOMEDIUM; |
---|
| 266 | + if (rcu_access_pointer(op->volume->servers) == op->server_list) { |
---|
| 267 | + op->error = -ENOMEDIUM; |
---|
294 | 268 | goto failed; |
---|
295 | 269 | } |
---|
296 | 270 | |
---|
297 | 271 | goto restart_from_beginning; |
---|
298 | 272 | |
---|
299 | 273 | default: |
---|
300 | | - clear_bit(AFS_VOLUME_OFFLINE, &vnode->volume->flags); |
---|
301 | | - clear_bit(AFS_VOLUME_BUSY, &vnode->volume->flags); |
---|
302 | | - fc->ac.error = afs_abort_to_error(fc->ac.abort_code); |
---|
| 274 | + clear_bit(AFS_VOLUME_OFFLINE, &op->volume->flags); |
---|
| 275 | + clear_bit(AFS_VOLUME_BUSY, &op->volume->flags); |
---|
| 276 | + op->error = afs_abort_to_error(op->ac.abort_code); |
---|
303 | 277 | goto failed; |
---|
304 | 278 | } |
---|
305 | 279 | |
---|
306 | | - case -ENETUNREACH: |
---|
307 | | - case -EHOSTUNREACH: |
---|
308 | | - case -ECONNREFUSED: |
---|
309 | 280 | case -ETIMEDOUT: |
---|
310 | 281 | case -ETIME: |
---|
| 282 | + if (op->error != -EDESTADDRREQ) |
---|
| 283 | + goto iterate_address; |
---|
| 284 | + fallthrough; |
---|
| 285 | + case -ERFKILL: |
---|
| 286 | + case -EADDRNOTAVAIL: |
---|
| 287 | + case -ENETUNREACH: |
---|
| 288 | + case -EHOSTUNREACH: |
---|
| 289 | + case -EHOSTDOWN: |
---|
| 290 | + case -ECONNREFUSED: |
---|
311 | 291 | _debug("no conn"); |
---|
| 292 | + op->error = error; |
---|
312 | 293 | goto iterate_address; |
---|
313 | 294 | |
---|
314 | 295 | case -ECONNRESET: |
---|
315 | 296 | _debug("call reset"); |
---|
| 297 | + op->error = error; |
---|
316 | 298 | goto failed; |
---|
317 | 299 | } |
---|
318 | 300 | |
---|
319 | 301 | restart_from_beginning: |
---|
320 | 302 | _debug("restart"); |
---|
321 | | - afs_end_cursor(&fc->ac); |
---|
322 | | - afs_put_cb_interest(afs_v2net(vnode), fc->cbi); |
---|
323 | | - fc->cbi = NULL; |
---|
324 | | - afs_put_serverlist(afs_v2net(vnode), fc->server_list); |
---|
325 | | - fc->server_list = NULL; |
---|
| 303 | + afs_end_cursor(&op->ac); |
---|
| 304 | + op->server = NULL; |
---|
| 305 | + afs_put_serverlist(op->net, op->server_list); |
---|
| 306 | + op->server_list = NULL; |
---|
326 | 307 | start: |
---|
327 | 308 | _debug("start"); |
---|
328 | 309 | /* See if we need to do an update of the volume record. Note that the |
---|
329 | 310 | * volume may have moved or even have been deleted. |
---|
330 | 311 | */ |
---|
331 | | - fc->ac.error = afs_check_volume_status(vnode->volume, fc->key); |
---|
332 | | - if (fc->ac.error < 0) |
---|
| 312 | + error = afs_check_volume_status(op->volume, op); |
---|
| 313 | + if (error < 0) |
---|
| 314 | + goto failed_set_error; |
---|
| 315 | + |
---|
| 316 | + if (!afs_start_fs_iteration(op, vnode)) |
---|
333 | 317 | goto failed; |
---|
334 | 318 | |
---|
335 | | - if (!afs_start_fs_iteration(fc, vnode)) |
---|
336 | | - goto failed; |
---|
| 319 | + _debug("__ VOL %llx __", op->volume->vid); |
---|
337 | 320 | |
---|
338 | | -use_server: |
---|
339 | | - _debug("use"); |
---|
| 321 | +pick_server: |
---|
| 322 | + _debug("pick [%lx]", op->untried); |
---|
| 323 | + |
---|
| 324 | + error = afs_wait_for_fs_probes(op->server_list, op->untried); |
---|
| 325 | + if (error < 0) |
---|
| 326 | + goto failed_set_error; |
---|
| 327 | + |
---|
| 328 | + /* Pick the untried server with the lowest RTT. If we have outstanding |
---|
| 329 | + * callbacks, we stick with the server we're already using if we can. |
---|
| 330 | + */ |
---|
| 331 | + if (op->server) { |
---|
| 332 | + _debug("server %u", op->index); |
---|
| 333 | + if (test_bit(op->index, &op->untried)) |
---|
| 334 | + goto selected_server; |
---|
| 335 | + op->server = NULL; |
---|
| 336 | + _debug("no server"); |
---|
| 337 | + } |
---|
| 338 | + |
---|
| 339 | + op->index = -1; |
---|
| 340 | + rtt = U32_MAX; |
---|
| 341 | + for (i = 0; i < op->server_list->nr_servers; i++) { |
---|
| 342 | + struct afs_server *s = op->server_list->servers[i].server; |
---|
| 343 | + |
---|
| 344 | + if (!test_bit(i, &op->untried) || |
---|
| 345 | + !test_bit(AFS_SERVER_FL_RESPONDING, &s->flags)) |
---|
| 346 | + continue; |
---|
| 347 | + if (s->probe.rtt < rtt) { |
---|
| 348 | + op->index = i; |
---|
| 349 | + rtt = s->probe.rtt; |
---|
| 350 | + } |
---|
| 351 | + } |
---|
| 352 | + |
---|
| 353 | + if (op->index == -1) |
---|
| 354 | + goto no_more_servers; |
---|
| 355 | + |
---|
| 356 | +selected_server: |
---|
| 357 | + _debug("use %d", op->index); |
---|
| 358 | + __clear_bit(op->index, &op->untried); |
---|
| 359 | + |
---|
340 | 360 | /* We're starting on a different fileserver from the list. We need to |
---|
341 | 361 | * check it, create a callback intercept, find its address list and |
---|
342 | 362 | * probe its capabilities before we use it. |
---|
343 | 363 | */ |
---|
344 | | - ASSERTCMP(fc->ac.alist, ==, NULL); |
---|
345 | | - server = fc->server_list->servers[fc->index].server; |
---|
| 364 | + ASSERTCMP(op->ac.alist, ==, NULL); |
---|
| 365 | + server = op->server_list->servers[op->index].server; |
---|
346 | 366 | |
---|
347 | | - if (!afs_check_server_record(fc, server)) |
---|
| 367 | + if (!afs_check_server_record(op, server)) |
---|
348 | 368 | goto failed; |
---|
349 | 369 | |
---|
350 | 370 | _debug("USING SERVER: %pU", &server->uuid); |
---|
351 | 371 | |
---|
352 | | - /* Make sure we've got a callback interest record for this server. We |
---|
353 | | - * have to link it in before we send the request as we can be sent a |
---|
354 | | - * break request before we've finished decoding the reply and |
---|
355 | | - * installing the vnode. |
---|
356 | | - */ |
---|
357 | | - fc->ac.error = afs_register_server_cb_interest(vnode, fc->server_list, |
---|
358 | | - fc->index); |
---|
359 | | - if (fc->ac.error < 0) |
---|
360 | | - goto failed; |
---|
361 | | - |
---|
362 | | - fc->cbi = afs_get_cb_interest(vnode->cb_interest); |
---|
| 372 | + op->flags |= AFS_OPERATION_RETRY_SERVER; |
---|
| 373 | + op->server = server; |
---|
| 374 | + if (vnode->cb_server != server) { |
---|
| 375 | + vnode->cb_server = server; |
---|
| 376 | + vnode->cb_s_break = server->cb_s_break; |
---|
| 377 | + vnode->cb_v_break = vnode->volume->cb_v_break; |
---|
| 378 | + clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); |
---|
| 379 | + } |
---|
363 | 380 | |
---|
364 | 381 | read_lock(&server->fs_lock); |
---|
365 | 382 | alist = rcu_dereference_protected(server->addresses, |
---|
.. | .. |
---|
367 | 384 | afs_get_addrlist(alist); |
---|
368 | 385 | read_unlock(&server->fs_lock); |
---|
369 | 386 | |
---|
370 | | - memset(&fc->ac, 0, sizeof(fc->ac)); |
---|
| 387 | +retry_server: |
---|
| 388 | + memset(&op->ac, 0, sizeof(op->ac)); |
---|
371 | 389 | |
---|
372 | | - /* Probe the current fileserver if we haven't done so yet. */ |
---|
373 | | - if (!test_bit(AFS_SERVER_FL_PROBED, &server->flags)) { |
---|
374 | | - fc->ac.alist = afs_get_addrlist(alist); |
---|
375 | | - |
---|
376 | | - if (!afs_probe_fileserver(fc)) { |
---|
377 | | - switch (fc->ac.error) { |
---|
378 | | - case -ENOMEM: |
---|
379 | | - case -ERESTARTSYS: |
---|
380 | | - case -EINTR: |
---|
381 | | - goto failed; |
---|
382 | | - default: |
---|
383 | | - goto next_server; |
---|
384 | | - } |
---|
385 | | - } |
---|
386 | | - } |
---|
387 | | - |
---|
388 | | - if (!fc->ac.alist) |
---|
389 | | - fc->ac.alist = alist; |
---|
| 390 | + if (!op->ac.alist) |
---|
| 391 | + op->ac.alist = alist; |
---|
390 | 392 | else |
---|
391 | 393 | afs_put_addrlist(alist); |
---|
392 | 394 | |
---|
393 | | - fc->ac.start = READ_ONCE(alist->index); |
---|
394 | | - fc->ac.index = fc->ac.start; |
---|
| 395 | + op->ac.index = -1; |
---|
395 | 396 | |
---|
396 | 397 | iterate_address: |
---|
397 | | - ASSERT(fc->ac.alist); |
---|
398 | | - _debug("iterate %d/%d", fc->ac.index, fc->ac.alist->nr_addrs); |
---|
| 398 | + ASSERT(op->ac.alist); |
---|
399 | 399 | /* Iterate over the current server's address list to try and find an |
---|
400 | 400 | * address on which it will respond to us. |
---|
401 | 401 | */ |
---|
402 | | - if (!afs_iterate_addresses(&fc->ac)) |
---|
403 | | - goto next_server; |
---|
| 402 | + if (!afs_iterate_addresses(&op->ac)) |
---|
| 403 | + goto out_of_addresses; |
---|
| 404 | + |
---|
| 405 | + _debug("address [%u] %u/%u %pISp", |
---|
| 406 | + op->index, op->ac.index, op->ac.alist->nr_addrs, |
---|
| 407 | + &op->ac.alist->addrs[op->ac.index].transport); |
---|
404 | 408 | |
---|
405 | 409 | _leave(" = t"); |
---|
406 | 410 | return true; |
---|
407 | 411 | |
---|
| 412 | +out_of_addresses: |
---|
| 413 | + /* We've now had a failure to respond on all of a server's addresses - |
---|
| 414 | + * immediately probe them again and consider retrying the server. |
---|
| 415 | + */ |
---|
| 416 | + afs_probe_fileserver(op->net, op->server); |
---|
| 417 | + if (op->flags & AFS_OPERATION_RETRY_SERVER) { |
---|
| 418 | + alist = op->ac.alist; |
---|
| 419 | + error = afs_wait_for_one_fs_probe( |
---|
| 420 | + op->server, !(op->flags & AFS_OPERATION_UNINTR)); |
---|
| 421 | + switch (error) { |
---|
| 422 | + case 0: |
---|
| 423 | + op->flags &= ~AFS_OPERATION_RETRY_SERVER; |
---|
| 424 | + goto retry_server; |
---|
| 425 | + case -ERESTARTSYS: |
---|
| 426 | + goto failed_set_error; |
---|
| 427 | + case -ETIME: |
---|
| 428 | + case -EDESTADDRREQ: |
---|
| 429 | + goto next_server; |
---|
| 430 | + } |
---|
| 431 | + } |
---|
| 432 | + |
---|
408 | 433 | next_server: |
---|
409 | 434 | _debug("next"); |
---|
410 | | - afs_end_cursor(&fc->ac); |
---|
411 | | - afs_put_cb_interest(afs_v2net(vnode), fc->cbi); |
---|
412 | | - fc->cbi = NULL; |
---|
413 | | - fc->index++; |
---|
414 | | - if (fc->index >= fc->server_list->nr_servers) |
---|
415 | | - fc->index = 0; |
---|
416 | | - if (fc->index != fc->start) |
---|
417 | | - goto use_server; |
---|
| 435 | + afs_end_cursor(&op->ac); |
---|
| 436 | + goto pick_server; |
---|
418 | 437 | |
---|
| 438 | +no_more_servers: |
---|
419 | 439 | /* That's all the servers poked to no good effect. Try again if some |
---|
420 | 440 | * of them were busy. |
---|
421 | 441 | */ |
---|
422 | | - if (fc->flags & AFS_FS_CURSOR_VBUSY) |
---|
| 442 | + if (op->flags & AFS_OPERATION_VBUSY) |
---|
423 | 443 | goto restart_from_beginning; |
---|
424 | 444 | |
---|
425 | | - fc->ac.error = -EDESTADDRREQ; |
---|
426 | | - goto failed; |
---|
| 445 | + e.error = -EDESTADDRREQ; |
---|
| 446 | + e.responded = false; |
---|
| 447 | + for (i = 0; i < op->server_list->nr_servers; i++) { |
---|
| 448 | + struct afs_server *s = op->server_list->servers[i].server; |
---|
427 | 449 | |
---|
| 450 | + afs_prioritise_error(&e, READ_ONCE(s->probe.error), |
---|
| 451 | + s->probe.abort_code); |
---|
| 452 | + } |
---|
| 453 | + |
---|
| 454 | + error = e.error; |
---|
| 455 | + |
---|
| 456 | +failed_set_error: |
---|
| 457 | + op->error = error; |
---|
428 | 458 | failed: |
---|
429 | | - fc->flags |= AFS_FS_CURSOR_STOP; |
---|
430 | | - afs_end_cursor(&fc->ac); |
---|
431 | | - _leave(" = f [failed %d]", fc->ac.error); |
---|
| 459 | + op->flags |= AFS_OPERATION_STOP; |
---|
| 460 | + afs_end_cursor(&op->ac); |
---|
| 461 | + _leave(" = f [failed %d]", op->error); |
---|
432 | 462 | return false; |
---|
433 | 463 | } |
---|
434 | 464 | |
---|
435 | 465 | /* |
---|
436 | | - * Select the same fileserver we used for a vnode before and only that |
---|
437 | | - * fileserver. We use this when we have a lock on that file, which is backed |
---|
438 | | - * only by the fileserver we obtained it from. |
---|
| 466 | + * Dump cursor state in the case of the error being EDESTADDRREQ. |
---|
439 | 467 | */ |
---|
440 | | -bool afs_select_current_fileserver(struct afs_fs_cursor *fc) |
---|
| 468 | +void afs_dump_edestaddrreq(const struct afs_operation *op) |
---|
441 | 469 | { |
---|
442 | | - struct afs_vnode *vnode = fc->vnode; |
---|
443 | | - struct afs_cb_interest *cbi = vnode->cb_interest; |
---|
444 | | - struct afs_addr_list *alist; |
---|
| 470 | + static int count; |
---|
| 471 | + int i; |
---|
445 | 472 | |
---|
446 | | - _enter(""); |
---|
| 473 | + if (!IS_ENABLED(CONFIG_AFS_DEBUG_CURSOR) || count > 3) |
---|
| 474 | + return; |
---|
| 475 | + count++; |
---|
447 | 476 | |
---|
448 | | - switch (fc->ac.error) { |
---|
449 | | - case SHRT_MAX: |
---|
450 | | - if (!cbi) { |
---|
451 | | - fc->ac.error = -ESTALE; |
---|
452 | | - fc->flags |= AFS_FS_CURSOR_STOP; |
---|
453 | | - return false; |
---|
| 477 | + rcu_read_lock(); |
---|
| 478 | + |
---|
| 479 | + pr_notice("EDESTADDR occurred\n"); |
---|
| 480 | + pr_notice("FC: cbb=%x cbb2=%x fl=%x err=%hd\n", |
---|
| 481 | + op->file[0].cb_break_before, |
---|
| 482 | + op->file[1].cb_break_before, op->flags, op->error); |
---|
| 483 | + pr_notice("FC: ut=%lx ix=%d ni=%u\n", |
---|
| 484 | + op->untried, op->index, op->nr_iterations); |
---|
| 485 | + |
---|
| 486 | + if (op->server_list) { |
---|
| 487 | + const struct afs_server_list *sl = op->server_list; |
---|
| 488 | + pr_notice("FC: SL nr=%u pr=%u vnov=%hx\n", |
---|
| 489 | + sl->nr_servers, sl->preferred, sl->vnovol_mask); |
---|
| 490 | + for (i = 0; i < sl->nr_servers; i++) { |
---|
| 491 | + const struct afs_server *s = sl->servers[i].server; |
---|
| 492 | + pr_notice("FC: server fl=%lx av=%u %pU\n", |
---|
| 493 | + s->flags, s->addr_version, &s->uuid); |
---|
| 494 | + if (s->addresses) { |
---|
| 495 | + const struct afs_addr_list *a = |
---|
| 496 | + rcu_dereference(s->addresses); |
---|
| 497 | + pr_notice("FC: - av=%u nr=%u/%u/%u pr=%u\n", |
---|
| 498 | + a->version, |
---|
| 499 | + a->nr_ipv4, a->nr_addrs, a->max_addrs, |
---|
| 500 | + a->preferred); |
---|
| 501 | + pr_notice("FC: - R=%lx F=%lx\n", |
---|
| 502 | + a->responded, a->failed); |
---|
| 503 | + if (a == op->ac.alist) |
---|
| 504 | + pr_notice("FC: - current\n"); |
---|
| 505 | + } |
---|
454 | 506 | } |
---|
455 | | - |
---|
456 | | - fc->cbi = afs_get_cb_interest(vnode->cb_interest); |
---|
457 | | - |
---|
458 | | - read_lock(&cbi->server->fs_lock); |
---|
459 | | - alist = rcu_dereference_protected(cbi->server->addresses, |
---|
460 | | - lockdep_is_held(&cbi->server->fs_lock)); |
---|
461 | | - afs_get_addrlist(alist); |
---|
462 | | - read_unlock(&cbi->server->fs_lock); |
---|
463 | | - if (!alist) { |
---|
464 | | - fc->ac.error = -ESTALE; |
---|
465 | | - fc->flags |= AFS_FS_CURSOR_STOP; |
---|
466 | | - return false; |
---|
467 | | - } |
---|
468 | | - |
---|
469 | | - memset(&fc->ac, 0, sizeof(fc->ac)); |
---|
470 | | - fc->ac.alist = alist; |
---|
471 | | - fc->ac.start = READ_ONCE(alist->index); |
---|
472 | | - fc->ac.index = fc->ac.start; |
---|
473 | | - goto iterate_address; |
---|
474 | | - |
---|
475 | | - case 0: |
---|
476 | | - default: |
---|
477 | | - /* Success or local failure. Stop. */ |
---|
478 | | - fc->flags |= AFS_FS_CURSOR_STOP; |
---|
479 | | - _leave(" = f [okay/local %d]", fc->ac.error); |
---|
480 | | - return false; |
---|
481 | | - |
---|
482 | | - case -ECONNABORTED: |
---|
483 | | - fc->flags |= AFS_FS_CURSOR_STOP; |
---|
484 | | - _leave(" = f [abort]"); |
---|
485 | | - return false; |
---|
486 | | - |
---|
487 | | - case -ENETUNREACH: |
---|
488 | | - case -EHOSTUNREACH: |
---|
489 | | - case -ECONNREFUSED: |
---|
490 | | - case -ETIMEDOUT: |
---|
491 | | - case -ETIME: |
---|
492 | | - _debug("no conn"); |
---|
493 | | - goto iterate_address; |
---|
494 | 507 | } |
---|
495 | 508 | |
---|
496 | | -iterate_address: |
---|
497 | | - /* Iterate over the current server's address list to try and find an |
---|
498 | | - * address on which it will respond to us. |
---|
499 | | - */ |
---|
500 | | - if (afs_iterate_addresses(&fc->ac)) { |
---|
501 | | - _leave(" = t"); |
---|
502 | | - return true; |
---|
503 | | - } |
---|
504 | | - |
---|
505 | | - afs_end_cursor(&fc->ac); |
---|
506 | | - return false; |
---|
507 | | -} |
---|
508 | | - |
---|
509 | | -/* |
---|
510 | | - * Tidy up a filesystem cursor and unlock the vnode. |
---|
511 | | - */ |
---|
512 | | -int afs_end_vnode_operation(struct afs_fs_cursor *fc) |
---|
513 | | -{ |
---|
514 | | - struct afs_net *net = afs_v2net(fc->vnode); |
---|
515 | | - int ret; |
---|
516 | | - |
---|
517 | | - mutex_unlock(&fc->vnode->io_lock); |
---|
518 | | - |
---|
519 | | - afs_end_cursor(&fc->ac); |
---|
520 | | - afs_put_cb_interest(net, fc->cbi); |
---|
521 | | - afs_put_serverlist(net, fc->server_list); |
---|
522 | | - |
---|
523 | | - ret = fc->ac.error; |
---|
524 | | - if (ret == -ECONNABORTED) |
---|
525 | | - afs_abort_to_error(fc->ac.abort_code); |
---|
526 | | - |
---|
527 | | - return fc->ac.error; |
---|
| 509 | + pr_notice("AC: t=%lx ax=%u ac=%d er=%d r=%u ni=%u\n", |
---|
| 510 | + op->ac.tried, op->ac.index, op->ac.abort_code, op->ac.error, |
---|
| 511 | + op->ac.responded, op->ac.nr_iterations); |
---|
| 512 | + rcu_read_unlock(); |
---|
528 | 513 | } |
---|