]>
git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - fs/afs/rotate.c
c7975b3ba59afd2f0a87ccb0314c446f303b9912
1 /* Handle fileserver selection and rotation.
3 * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/kernel.h>
13 #include <linux/slab.h>
17 * Initialise a filesystem server cursor for iterating over FS servers.
19 void afs_init_fs_cursor(struct afs_fs_cursor
*fc
, struct afs_vnode
*vnode
)
21 memset(fc
, 0, sizeof(*fc
));
25 * Set a filesystem server cursor for using a specific FS server.
27 int afs_set_fs_cursor(struct afs_fs_cursor
*fc
, struct afs_vnode
*vnode
)
29 afs_init_fs_cursor(fc
, vnode
);
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
);
36 fc
->ac
.error
= vnode
->cb_interest
->server
->fs_state
;
38 fc
->ac
.error
= -ESTALE
;
40 read_sequnlock_excl(&vnode
->cb_lock
);
46 * pick a server to use to try accessing this volume
47 * - returns with an elevated usage count on the server chosen
49 bool afs_volume_pick_fileserver(struct afs_fs_cursor
*fc
, struct afs_vnode
*vnode
)
51 struct afs_volume
*volume
= vnode
->volume
;
52 struct afs_server
*server
;
55 _enter("%s", volume
->vlocation
->vldb
.name
);
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
);
63 down_read(&volume
->server_sem
);
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
);
73 /* basically, just search the list for the first live server and use
76 for (loop
= 0; loop
< volume
->nservers
; loop
++) {
77 server
= volume
->servers
[loop
];
78 state
= server
->fs_state
;
80 _debug("consider %d [%d]", loop
, state
);
99 ret
== -ENETUNREACH
||
100 ret
== -EHOSTUNREACH
)
107 ret
== -ENETUNREACH
||
108 ret
== -EHOSTUNREACH
||
109 ret
== -ECONNREFUSED
)
118 /* no available servers
119 * - TODO: handle the no active servers case better
121 up_read(&volume
->server_sem
);
122 _leave(" = f [%d]", fc
->ac
.error
);
126 /* Found an apparently healthy server. We need to register an interest
127 * in receiving callbacks before we talk to it.
129 ret
= afs_register_server_cb_interest(vnode
,
130 &volume
->cb_interests
[loop
], server
);
134 fc
->server
= afs_get_server(server
);
135 up_read(&volume
->server_sem
);
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
);
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
151 bool afs_iterate_fs_cursor(struct afs_fs_cursor
*fc
,
152 struct afs_vnode
*vnode
)
154 struct afs_volume
*volume
= vnode
->volume
;
155 struct afs_server
*server
= fc
->server
;
159 volume
->vlocation
->vldb
.name
, &fc
->ac
.addr
->transport
,
162 switch (fc
->ac
.error
) {
165 server
->fs_state
= 0;
169 /* the fileserver denied all knowledge of the volume */
171 down_write(&volume
->server_sem
);
173 /* firstly, find where the server is in the active list (if it
175 for (loop
= 0; loop
< volume
->nservers
; loop
++)
176 if (volume
->servers
[loop
] == server
)
179 /* no longer there - may have been discarded by another op */
180 goto try_next_server_upw
;
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
);
192 if (volume
->nservers
> 0)
193 /* another server might acknowledge its existence */
194 goto try_next_server_upw
;
196 /* handle the case where all the fileservers have rejected the
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
202 up_write(&volume
->server_sem
);
203 afs_put_server(afs_v2net(vnode
), server
);
205 _leave(" = f [completely rejected]");
208 /* problem reaching the server */
215 /* mark the server as dead
216 * TODO: vary dead timeout depending on error
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
);
223 spin_unlock(&server
->fs_lock
);
224 goto try_next_server
;
226 /* miscellaneous error */
230 /* tell the caller to accept the result */
231 afs_put_server(afs_v2net(vnode
), server
);
233 _leave(" = f [local failure]");
237 /* tell the caller to loop around and try the next server */
239 up_write(&volume
->server_sem
);
241 afs_put_server(afs_v2net(vnode
), server
);
242 _leave(" = t [try next server]");
247 * Clean up a fileserver cursor.
249 int afs_end_fs_cursor(struct afs_fs_cursor
*fc
, struct afs_net
*net
)
251 afs_end_cursor(&fc
->ac
);
252 afs_put_server(net
, fc
->server
);