diff options
author | David Howells <dhowells@redhat.com> | 2017-11-02 11:27:50 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2017-11-13 10:38:19 -0500 |
commit | 9cc6fc50f7bc69ac28bee45eed13cbc65a86210f (patch) | |
tree | 81f5ea54ddb8e9df3bf1fa768f9421d6aeec98e5 | |
parent | 8b2a464ced77fe35be72ab7d38152a9439daf8d3 (diff) |
afs: Move server rotation code into its own file
Move server rotation code into its own file.
Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r-- | fs/afs/Makefile | 1 | ||||
-rw-r--r-- | fs/afs/rotate.c | 254 | ||||
-rw-r--r-- | fs/afs/volume.c | 250 |
3 files changed, 255 insertions, 250 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile index 849383986d3b..192d476d7c76 100644 --- a/fs/afs/Makefile +++ b/fs/afs/Makefile | |||
@@ -20,6 +20,7 @@ kafs-objs := \ | |||
20 | misc.o \ | 20 | misc.o \ |
21 | mntpt.o \ | 21 | mntpt.o \ |
22 | proc.o \ | 22 | proc.o \ |
23 | rotate.o \ | ||
23 | rxrpc.o \ | 24 | rxrpc.o \ |
24 | security.o \ | 25 | security.o \ |
25 | server.o \ | 26 | server.o \ |
diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c new file mode 100644 index 000000000000..c7975b3ba59a --- /dev/null +++ b/fs/afs/rotate.c | |||
@@ -0,0 +1,254 @@ | |||
1 | /* Handle fileserver selection and rotation. | ||
2 | * | ||
3 | * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. | ||
4 | * 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 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include "internal.h" | ||
15 | |||
16 | /* | ||
17 | * Initialise a filesystem server cursor for iterating over FS servers. | ||
18 | */ | ||
19 | void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode) | ||
20 | { | ||
21 | memset(fc, 0, sizeof(*fc)); | ||
22 | } | ||
23 | |||
24 | /* | ||
25 | * Set a filesystem server cursor for using a specific FS server. | ||
26 | */ | ||
27 | int afs_set_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode) | ||
28 | { | ||
29 | afs_init_fs_cursor(fc, vnode); | ||
30 | |||
31 | read_seqlock_excl(&vnode->cb_lock); | ||
32 | if (vnode->cb_interest) { | ||
33 | if (vnode->cb_interest->server->fs_state == 0) | ||
34 | fc->server = afs_get_server(vnode->cb_interest->server); | ||
35 | else | ||
36 | fc->ac.error = vnode->cb_interest->server->fs_state; | ||
37 | } else { | ||
38 | fc->ac.error = -ESTALE; | ||
39 | } | ||
40 | read_sequnlock_excl(&vnode->cb_lock); | ||
41 | |||
42 | return fc->ac.error; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * pick a server to use to try accessing this volume | ||
47 | * - returns with an elevated usage count on the server chosen | ||
48 | */ | ||
49 | bool afs_volume_pick_fileserver(struct afs_fs_cursor *fc, struct afs_vnode *vnode) | ||
50 | { | ||
51 | struct afs_volume *volume = vnode->volume; | ||
52 | struct afs_server *server; | ||
53 | int ret, state, loop; | ||
54 | |||
55 | _enter("%s", volume->vlocation->vldb.name); | ||
56 | |||
57 | /* stick with the server we're already using if we can */ | ||
58 | if (vnode->cb_interest && vnode->cb_interest->server->fs_state == 0) { | ||
59 | fc->server = afs_get_server(vnode->cb_interest->server); | ||
60 | goto set_server; | ||
61 | } | ||
62 | |||
63 | down_read(&volume->server_sem); | ||
64 | |||
65 | /* handle the no-server case */ | ||
66 | if (volume->nservers == 0) { | ||
67 | fc->ac.error = volume->rjservers ? -ENOMEDIUM : -ESTALE; | ||
68 | up_read(&volume->server_sem); | ||
69 | _leave(" = f [no servers %d]", fc->ac.error); | ||
70 | return false; | ||
71 | } | ||
72 | |||
73 | /* basically, just search the list for the first live server and use | ||
74 | * that */ | ||
75 | ret = 0; | ||
76 | for (loop = 0; loop < volume->nservers; loop++) { | ||
77 | server = volume->servers[loop]; | ||
78 | state = server->fs_state; | ||
79 | |||
80 | _debug("consider %d [%d]", loop, state); | ||
81 | |||
82 | switch (state) { | ||
83 | case 0: | ||
84 | goto picked_server; | ||
85 | |||
86 | case -ENETUNREACH: | ||
87 | if (ret == 0) | ||
88 | ret = state; | ||
89 | break; | ||
90 | |||
91 | case -EHOSTUNREACH: | ||
92 | if (ret == 0 || | ||
93 | ret == -ENETUNREACH) | ||
94 | ret = state; | ||
95 | break; | ||
96 | |||
97 | case -ECONNREFUSED: | ||
98 | if (ret == 0 || | ||
99 | ret == -ENETUNREACH || | ||
100 | ret == -EHOSTUNREACH) | ||
101 | ret = state; | ||
102 | break; | ||
103 | |||
104 | default: | ||
105 | case -EREMOTEIO: | ||
106 | if (ret == 0 || | ||
107 | ret == -ENETUNREACH || | ||
108 | ret == -EHOSTUNREACH || | ||
109 | ret == -ECONNREFUSED) | ||
110 | ret = state; | ||
111 | break; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | error: | ||
116 | fc->ac.error = ret; | ||
117 | |||
118 | /* no available servers | ||
119 | * - TODO: handle the no active servers case better | ||
120 | */ | ||
121 | up_read(&volume->server_sem); | ||
122 | _leave(" = f [%d]", fc->ac.error); | ||
123 | return false; | ||
124 | |||
125 | picked_server: | ||
126 | /* Found an apparently healthy server. We need to register an interest | ||
127 | * in receiving callbacks before we talk to it. | ||
128 | */ | ||
129 | ret = afs_register_server_cb_interest(vnode, | ||
130 | &volume->cb_interests[loop], server); | ||
131 | if (ret < 0) | ||
132 | goto error; | ||
133 | |||
134 | fc->server = afs_get_server(server); | ||
135 | up_read(&volume->server_sem); | ||
136 | set_server: | ||
137 | fc->ac.alist = afs_get_addrlist(fc->server->addrs); | ||
138 | fc->ac.addr = &fc->ac.alist->addrs[0]; | ||
139 | _debug("USING SERVER: %pIS\n", &fc->ac.addr->transport); | ||
140 | _leave(" = t (picked %pIS)", &fc->ac.addr->transport); | ||
141 | return true; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * release a server after use | ||
146 | * - releases the ref on the server struct that was acquired by picking | ||
147 | * - records result of using a particular server to access a volume | ||
148 | * - return true to try again, false if okay or to issue error | ||
149 | * - the caller must release the server struct if result was false | ||
150 | */ | ||
151 | bool afs_iterate_fs_cursor(struct afs_fs_cursor *fc, | ||
152 | struct afs_vnode *vnode) | ||
153 | { | ||
154 | struct afs_volume *volume = vnode->volume; | ||
155 | struct afs_server *server = fc->server; | ||
156 | unsigned loop; | ||
157 | |||
158 | _enter("%s,%pIS,%d", | ||
159 | volume->vlocation->vldb.name, &fc->ac.addr->transport, | ||
160 | fc->ac.error); | ||
161 | |||
162 | switch (fc->ac.error) { | ||
163 | /* success */ | ||
164 | case 0: | ||
165 | server->fs_state = 0; | ||
166 | _leave(" = f"); | ||
167 | return false; | ||
168 | |||
169 | /* the fileserver denied all knowledge of the volume */ | ||
170 | case -ENOMEDIUM: | ||
171 | down_write(&volume->server_sem); | ||
172 | |||
173 | /* firstly, find where the server is in the active list (if it | ||
174 | * is) */ | ||
175 | for (loop = 0; loop < volume->nservers; loop++) | ||
176 | if (volume->servers[loop] == server) | ||
177 | goto present; | ||
178 | |||
179 | /* no longer there - may have been discarded by another op */ | ||
180 | goto try_next_server_upw; | ||
181 | |||
182 | present: | ||
183 | volume->nservers--; | ||
184 | memmove(&volume->servers[loop], | ||
185 | &volume->servers[loop + 1], | ||
186 | sizeof(volume->servers[loop]) * | ||
187 | (volume->nservers - loop)); | ||
188 | volume->servers[volume->nservers] = NULL; | ||
189 | afs_put_server(afs_v2net(vnode), server); | ||
190 | volume->rjservers++; | ||
191 | |||
192 | if (volume->nservers > 0) | ||
193 | /* another server might acknowledge its existence */ | ||
194 | goto try_next_server_upw; | ||
195 | |||
196 | /* handle the case where all the fileservers have rejected the | ||
197 | * volume | ||
198 | * - TODO: try asking the fileservers for volume information | ||
199 | * - TODO: contact the VL server again to see if the volume is | ||
200 | * no longer registered | ||
201 | */ | ||
202 | up_write(&volume->server_sem); | ||
203 | afs_put_server(afs_v2net(vnode), server); | ||
204 | fc->server = NULL; | ||
205 | _leave(" = f [completely rejected]"); | ||
206 | return false; | ||
207 | |||
208 | /* problem reaching the server */ | ||
209 | case -ENETUNREACH: | ||
210 | case -EHOSTUNREACH: | ||
211 | case -ECONNREFUSED: | ||
212 | case -ETIME: | ||
213 | case -ETIMEDOUT: | ||
214 | case -EREMOTEIO: | ||
215 | /* mark the server as dead | ||
216 | * TODO: vary dead timeout depending on error | ||
217 | */ | ||
218 | spin_lock(&server->fs_lock); | ||
219 | if (!server->fs_state) { | ||
220 | server->fs_state = fc->ac.error; | ||
221 | printk("kAFS: SERVER DEAD state=%d\n", fc->ac.error); | ||
222 | } | ||
223 | spin_unlock(&server->fs_lock); | ||
224 | goto try_next_server; | ||
225 | |||
226 | /* miscellaneous error */ | ||
227 | default: | ||
228 | case -ENOMEM: | ||
229 | case -ENONET: | ||
230 | /* tell the caller to accept the result */ | ||
231 | afs_put_server(afs_v2net(vnode), server); | ||
232 | fc->server = NULL; | ||
233 | _leave(" = f [local failure]"); | ||
234 | return false; | ||
235 | } | ||
236 | |||
237 | /* tell the caller to loop around and try the next server */ | ||
238 | try_next_server_upw: | ||
239 | up_write(&volume->server_sem); | ||
240 | try_next_server: | ||
241 | afs_put_server(afs_v2net(vnode), server); | ||
242 | _leave(" = t [try next server]"); | ||
243 | return true; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Clean up a fileserver cursor. | ||
248 | */ | ||
249 | int afs_end_fs_cursor(struct afs_fs_cursor *fc, struct afs_net *net) | ||
250 | { | ||
251 | afs_end_cursor(&fc->ac); | ||
252 | afs_put_server(net, fc->server); | ||
253 | return fc->ac.error; | ||
254 | } | ||
diff --git a/fs/afs/volume.c b/fs/afs/volume.c index d282cd0ff268..3c5ad1cc50f3 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c | |||
@@ -10,12 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
16 | #include <linux/fs.h> | ||
17 | #include <linux/pagemap.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include "internal.h" | 14 | #include "internal.h" |
20 | 15 | ||
21 | static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; | 16 | static const char *afs_voltypes[] = { "R/W", "R/O", "BAK" }; |
@@ -208,248 +203,3 @@ void afs_put_volume(struct afs_cell *cell, struct afs_volume *volume) | |||
208 | 203 | ||
209 | _leave(" [destroyed]"); | 204 | _leave(" [destroyed]"); |
210 | } | 205 | } |
211 | |||
212 | /* | ||
213 | * Initialise a filesystem server cursor for iterating over FS servers. | ||
214 | */ | ||
215 | void afs_init_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode) | ||
216 | { | ||
217 | fc->ac.alist = NULL; | ||
218 | fc->ac.addr = NULL; | ||
219 | fc->ac.start = 0; | ||
220 | fc->ac.index = 0; | ||
221 | fc->ac.error = 0; | ||
222 | fc->server = NULL; | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | * Set a filesystem server cursor for using a specific FS server. | ||
227 | */ | ||
228 | int afs_set_fs_cursor(struct afs_fs_cursor *fc, struct afs_vnode *vnode) | ||
229 | { | ||
230 | afs_init_fs_cursor(fc, vnode); | ||
231 | |||
232 | read_seqlock_excl(&vnode->cb_lock); | ||
233 | if (vnode->cb_interest) { | ||
234 | if (vnode->cb_interest->server->fs_state == 0) | ||
235 | fc->server = afs_get_server(vnode->cb_interest->server); | ||
236 | else | ||
237 | fc->ac.error = vnode->cb_interest->server->fs_state; | ||
238 | } else { | ||
239 | fc->ac.error = -ESTALE; | ||
240 | } | ||
241 | read_sequnlock_excl(&vnode->cb_lock); | ||
242 | |||
243 | return fc->ac.error; | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * pick a server to use to try accessing this volume | ||
248 | * - returns with an elevated usage count on the server chosen | ||
249 | */ | ||
250 | bool afs_volume_pick_fileserver(struct afs_fs_cursor *fc, struct afs_vnode *vnode) | ||
251 | { | ||
252 | struct afs_volume *volume = vnode->volume; | ||
253 | struct afs_server *server; | ||
254 | int ret, state, loop; | ||
255 | |||
256 | _enter("%s", volume->vlocation->vldb.name); | ||
257 | |||
258 | /* stick with the server we're already using if we can */ | ||
259 | if (vnode->cb_interest && vnode->cb_interest->server->fs_state == 0) { | ||
260 | fc->server = afs_get_server(vnode->cb_interest->server); | ||
261 | goto set_server; | ||
262 | } | ||
263 | |||
264 | down_read(&volume->server_sem); | ||
265 | |||
266 | /* handle the no-server case */ | ||
267 | if (volume->nservers == 0) { | ||
268 | fc->ac.error = volume->rjservers ? -ENOMEDIUM : -ESTALE; | ||
269 | up_read(&volume->server_sem); | ||
270 | _leave(" = f [no servers %d]", fc->ac.error); | ||
271 | return false; | ||
272 | } | ||
273 | |||
274 | /* basically, just search the list for the first live server and use | ||
275 | * that */ | ||
276 | ret = 0; | ||
277 | for (loop = 0; loop < volume->nservers; loop++) { | ||
278 | server = volume->servers[loop]; | ||
279 | state = server->fs_state; | ||
280 | |||
281 | _debug("consider %d [%d]", loop, state); | ||
282 | |||
283 | switch (state) { | ||
284 | case 0: | ||
285 | goto picked_server; | ||
286 | |||
287 | case -ENETUNREACH: | ||
288 | if (ret == 0) | ||
289 | ret = state; | ||
290 | break; | ||
291 | |||
292 | case -EHOSTUNREACH: | ||
293 | if (ret == 0 || | ||
294 | ret == -ENETUNREACH) | ||
295 | ret = state; | ||
296 | break; | ||
297 | |||
298 | case -ECONNREFUSED: | ||
299 | if (ret == 0 || | ||
300 | ret == -ENETUNREACH || | ||
301 | ret == -EHOSTUNREACH) | ||
302 | ret = state; | ||
303 | break; | ||
304 | |||
305 | default: | ||
306 | case -EREMOTEIO: | ||
307 | if (ret == 0 || | ||
308 | ret == -ENETUNREACH || | ||
309 | ret == -EHOSTUNREACH || | ||
310 | ret == -ECONNREFUSED) | ||
311 | ret = state; | ||
312 | break; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | error: | ||
317 | fc->ac.error = ret; | ||
318 | |||
319 | /* no available servers | ||
320 | * - TODO: handle the no active servers case better | ||
321 | */ | ||
322 | up_read(&volume->server_sem); | ||
323 | _leave(" = f [%d]", fc->ac.error); | ||
324 | return false; | ||
325 | |||
326 | picked_server: | ||
327 | /* Found an apparently healthy server. We need to register an interest | ||
328 | * in receiving callbacks before we talk to it. | ||
329 | */ | ||
330 | ret = afs_register_server_cb_interest(vnode, | ||
331 | &volume->cb_interests[loop], server); | ||
332 | if (ret < 0) | ||
333 | goto error; | ||
334 | |||
335 | fc->server = afs_get_server(server); | ||
336 | up_read(&volume->server_sem); | ||
337 | set_server: | ||
338 | fc->ac.alist = afs_get_addrlist(fc->server->addrs); | ||
339 | fc->ac.addr = &fc->ac.alist->addrs[0]; | ||
340 | _debug("USING SERVER: %pIS\n", &fc->ac.addr->transport); | ||
341 | _leave(" = t (picked %pIS)", &fc->ac.addr->transport); | ||
342 | return true; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * release a server after use | ||
347 | * - releases the ref on the server struct that was acquired by picking | ||
348 | * - records result of using a particular server to access a volume | ||
349 | * - return true to try again, false if okay or to issue error | ||
350 | * - the caller must release the server struct if result was false | ||
351 | */ | ||
352 | bool afs_iterate_fs_cursor(struct afs_fs_cursor *fc, | ||
353 | struct afs_vnode *vnode) | ||
354 | { | ||
355 | struct afs_volume *volume = vnode->volume; | ||
356 | struct afs_server *server = fc->server; | ||
357 | unsigned loop; | ||
358 | |||
359 | _enter("%s,%pIS,%d", | ||
360 | volume->vlocation->vldb.name, &fc->ac.addr->transport, | ||
361 | fc->ac.error); | ||
362 | |||
363 | switch (fc->ac.error) { | ||
364 | /* success */ | ||
365 | case 0: | ||
366 | server->fs_state = 0; | ||
367 | _leave(" = f"); | ||
368 | return false; | ||
369 | |||
370 | /* the fileserver denied all knowledge of the volume */ | ||
371 | case -ENOMEDIUM: | ||
372 | down_write(&volume->server_sem); | ||
373 | |||
374 | /* firstly, find where the server is in the active list (if it | ||
375 | * is) */ | ||
376 | for (loop = 0; loop < volume->nservers; loop++) | ||
377 | if (volume->servers[loop] == server) | ||
378 | goto present; | ||
379 | |||
380 | /* no longer there - may have been discarded by another op */ | ||
381 | goto try_next_server_upw; | ||
382 | |||
383 | present: | ||
384 | volume->nservers--; | ||
385 | memmove(&volume->servers[loop], | ||
386 | &volume->servers[loop + 1], | ||
387 | sizeof(volume->servers[loop]) * | ||
388 | (volume->nservers - loop)); | ||
389 | volume->servers[volume->nservers] = NULL; | ||
390 | afs_put_server(afs_v2net(vnode), server); | ||
391 | volume->rjservers++; | ||
392 | |||
393 | if (volume->nservers > 0) | ||
394 | /* another server might acknowledge its existence */ | ||
395 | goto try_next_server_upw; | ||
396 | |||
397 | /* handle the case where all the fileservers have rejected the | ||
398 | * volume | ||
399 | * - TODO: try asking the fileservers for volume information | ||
400 | * - TODO: contact the VL server again to see if the volume is | ||
401 | * no longer registered | ||
402 | */ | ||
403 | up_write(&volume->server_sem); | ||
404 | afs_put_server(afs_v2net(vnode), server); | ||
405 | fc->server = NULL; | ||
406 | _leave(" = f [completely rejected]"); | ||
407 | return false; | ||
408 | |||
409 | /* problem reaching the server */ | ||
410 | case -ENETUNREACH: | ||
411 | case -EHOSTUNREACH: | ||
412 | case -ECONNREFUSED: | ||
413 | case -ETIME: | ||
414 | case -ETIMEDOUT: | ||
415 | case -EREMOTEIO: | ||
416 | /* mark the server as dead | ||
417 | * TODO: vary dead timeout depending on error | ||
418 | */ | ||
419 | spin_lock(&server->fs_lock); | ||
420 | if (!server->fs_state) { | ||
421 | server->fs_state = fc->ac.error; | ||
422 | printk("kAFS: SERVER DEAD state=%d\n", fc->ac.error); | ||
423 | } | ||
424 | spin_unlock(&server->fs_lock); | ||
425 | goto try_next_server; | ||
426 | |||
427 | /* miscellaneous error */ | ||
428 | default: | ||
429 | case -ENOMEM: | ||
430 | case -ENONET: | ||
431 | /* tell the caller to accept the result */ | ||
432 | afs_put_server(afs_v2net(vnode), server); | ||
433 | fc->server = NULL; | ||
434 | _leave(" = f [local failure]"); | ||
435 | return false; | ||
436 | } | ||
437 | |||
438 | /* tell the caller to loop around and try the next server */ | ||
439 | try_next_server_upw: | ||
440 | up_write(&volume->server_sem); | ||
441 | try_next_server: | ||
442 | afs_put_server(afs_v2net(vnode), server); | ||
443 | _leave(" = t [try next server]"); | ||
444 | return true; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * Clean up a fileserver cursor. | ||
449 | */ | ||
450 | int afs_end_fs_cursor(struct afs_fs_cursor *fc, struct afs_net *net) | ||
451 | { | ||
452 | afs_end_cursor(&fc->ac); | ||
453 | afs_put_server(net, fc->server); | ||
454 | return fc->ac.error; | ||
455 | } | ||