Skip to content

Commit 9cc6fc5

Browse files
committed
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>
1 parent 8b2a464 commit 9cc6fc5

File tree

3 files changed

+255
-250
lines changed

3 files changed

+255
-250
lines changed

fs/afs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ kafs-objs := \
2020
misc.o \
2121
mntpt.o \
2222
proc.o \
23+
rotate.o \
2324
rxrpc.o \
2425
security.o \
2526
server.o \

fs/afs/rotate.c

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)