aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs/volume.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2017-11-02 11:27:50 -0400
committerDavid Howells <dhowells@redhat.com>2017-11-13 10:38:18 -0500
commit8b2a464ced77fe35be72ab7d38152a9439daf8d3 (patch)
treeec478c8adebb6344513581b60935c0cf2b0ff937 /fs/afs/volume.c
parent989782dcdc91a5e6d5999c7a52a84a60a0811e56 (diff)
afs: Add an address list concept
Add an RCU replaceable address list structure to hold a list of server addresses. The list also holds the To this end: (1) A cell's VL server address list can be loaded directly via insmod or echo to /proc/fs/afs/cells or dynamically from a DNS query for AFSDB or SRV records. (2) Anyone wanting to use a cell's VL server address must wait until the cell record comes online and has tried to obtain some addresses. (3) An FS server's address list, for the moment, has a single entry that is the key to the server list. This will change in the future when a server is instead keyed on its UUID and the VL.GetAddrsU operation is used. (4) An 'address cursor' concept is introduced to handle iteration through the address list. This is passed to the afs_make_call() as, in the future, stuff (such as abort code) that doesn't outlast the call will be returned in it. In the future, we might want to annotate the list with information about how each address fares. We might then want to propagate such annotations over address list replacement. Whilst we're at it, we allow IPv6 addresses to be specified in colon-delimited lists by enclosing them in square brackets. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs/volume.c')
-rw-r--r--fs/afs/volume.c115
1 files changed, 83 insertions, 32 deletions
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
index 4f6fd10094c6..d282cd0ff268 100644
--- a/fs/afs/volume.c
+++ b/fs/afs/volume.c
@@ -210,10 +210,44 @@ void afs_put_volume(struct afs_cell *cell, struct afs_volume *volume)
210} 210}
211 211
212/* 212/*
213 * Initialise a filesystem server cursor for iterating over FS servers.
214 */
215void 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 */
228int 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/*
213 * pick a server to use to try accessing this volume 247 * pick a server to use to try accessing this volume
214 * - returns with an elevated usage count on the server chosen 248 * - returns with an elevated usage count on the server chosen
215 */ 249 */
216struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode) 250bool afs_volume_pick_fileserver(struct afs_fs_cursor *fc, struct afs_vnode *vnode)
217{ 251{
218 struct afs_volume *volume = vnode->volume; 252 struct afs_volume *volume = vnode->volume;
219 struct afs_server *server; 253 struct afs_server *server;
@@ -223,19 +257,18 @@ struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode)
223 257
224 /* stick with the server we're already using if we can */ 258 /* stick with the server we're already using if we can */
225 if (vnode->cb_interest && vnode->cb_interest->server->fs_state == 0) { 259 if (vnode->cb_interest && vnode->cb_interest->server->fs_state == 0) {
226 afs_get_server(vnode->cb_interest->server); 260 fc->server = afs_get_server(vnode->cb_interest->server);
227 _leave(" = %p [current]", vnode->cb_interest->server); 261 goto set_server;
228 return vnode->cb_interest->server;
229 } 262 }
230 263
231 down_read(&volume->server_sem); 264 down_read(&volume->server_sem);
232 265
233 /* handle the no-server case */ 266 /* handle the no-server case */
234 if (volume->nservers == 0) { 267 if (volume->nservers == 0) {
235 ret = volume->rjservers ? -ENOMEDIUM : -ESTALE; 268 fc->ac.error = volume->rjservers ? -ENOMEDIUM : -ESTALE;
236 up_read(&volume->server_sem); 269 up_read(&volume->server_sem);
237 _leave(" = %d [no servers]", ret); 270 _leave(" = f [no servers %d]", fc->ac.error);
238 return ERR_PTR(ret); 271 return false;
239 } 272 }
240 273
241 /* basically, just search the list for the first live server and use 274 /* basically, just search the list for the first live server and use
@@ -280,13 +313,15 @@ struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *vnode)
280 } 313 }
281 } 314 }
282 315
316error:
317 fc->ac.error = ret;
318
283 /* no available servers 319 /* no available servers
284 * - TODO: handle the no active servers case better 320 * - TODO: handle the no active servers case better
285 */ 321 */
286error:
287 up_read(&volume->server_sem); 322 up_read(&volume->server_sem);
288 _leave(" = %d", ret); 323 _leave(" = f [%d]", fc->ac.error);
289 return ERR_PTR(ret); 324 return false;
290 325
291picked_server: 326picked_server:
292 /* Found an apparently healthy server. We need to register an interest 327 /* Found an apparently healthy server. We need to register an interest
@@ -296,37 +331,41 @@ picked_server:
296 &volume->cb_interests[loop], server); 331 &volume->cb_interests[loop], server);
297 if (ret < 0) 332 if (ret < 0)
298 goto error; 333 goto error;
299 334
300 afs_get_server(server); 335 fc->server = afs_get_server(server);
301 up_read(&volume->server_sem); 336 up_read(&volume->server_sem);
302 _leave(" = %p (picked %pIS)", 337set_server:
303 server, &server->addr.transport); 338 fc->ac.alist = afs_get_addrlist(fc->server->addrs);
304 return server; 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;
305} 343}
306 344
307/* 345/*
308 * release a server after use 346 * release a server after use
309 * - releases the ref on the server struct that was acquired by picking 347 * - releases the ref on the server struct that was acquired by picking
310 * - records result of using a particular server to access a volume 348 * - records result of using a particular server to access a volume
311 * - return 0 to try again, 1 if okay or to issue error 349 * - return true to try again, false if okay or to issue error
312 * - the caller must release the server struct if result was 0 350 * - the caller must release the server struct if result was false
313 */ 351 */
314int afs_volume_release_fileserver(struct afs_vnode *vnode, 352bool afs_iterate_fs_cursor(struct afs_fs_cursor *fc,
315 struct afs_server *server, 353 struct afs_vnode *vnode)
316 int result)
317{ 354{
318 struct afs_volume *volume = vnode->volume; 355 struct afs_volume *volume = vnode->volume;
356 struct afs_server *server = fc->server;
319 unsigned loop; 357 unsigned loop;
320 358
321 _enter("%s,%pIS,%d", 359 _enter("%s,%pIS,%d",
322 volume->vlocation->vldb.name, &server->addr.transport, result); 360 volume->vlocation->vldb.name, &fc->ac.addr->transport,
361 fc->ac.error);
323 362
324 switch (result) { 363 switch (fc->ac.error) {
325 /* success */ 364 /* success */
326 case 0: 365 case 0:
327 server->fs_state = 0; 366 server->fs_state = 0;
328 _leave(""); 367 _leave(" = f");
329 return 1; 368 return false;
330 369
331 /* the fileserver denied all knowledge of the volume */ 370 /* the fileserver denied all knowledge of the volume */
332 case -ENOMEDIUM: 371 case -ENOMEDIUM:
@@ -363,8 +402,9 @@ int afs_volume_release_fileserver(struct afs_vnode *vnode,
363 */ 402 */
364 up_write(&volume->server_sem); 403 up_write(&volume->server_sem);
365 afs_put_server(afs_v2net(vnode), server); 404 afs_put_server(afs_v2net(vnode), server);
366 _leave(" [completely rejected]"); 405 fc->server = NULL;
367 return 1; 406 _leave(" = f [completely rejected]");
407 return false;
368 408
369 /* problem reaching the server */ 409 /* problem reaching the server */
370 case -ENETUNREACH: 410 case -ENETUNREACH:
@@ -378,8 +418,8 @@ int afs_volume_release_fileserver(struct afs_vnode *vnode,
378 */ 418 */
379 spin_lock(&server->fs_lock); 419 spin_lock(&server->fs_lock);
380 if (!server->fs_state) { 420 if (!server->fs_state) {
381 server->fs_state = result; 421 server->fs_state = fc->ac.error;
382 printk("kAFS: SERVER DEAD state=%d\n", result); 422 printk("kAFS: SERVER DEAD state=%d\n", fc->ac.error);
383 } 423 }
384 spin_unlock(&server->fs_lock); 424 spin_unlock(&server->fs_lock);
385 goto try_next_server; 425 goto try_next_server;
@@ -390,8 +430,9 @@ int afs_volume_release_fileserver(struct afs_vnode *vnode,
390 case -ENONET: 430 case -ENONET:
391 /* tell the caller to accept the result */ 431 /* tell the caller to accept the result */
392 afs_put_server(afs_v2net(vnode), server); 432 afs_put_server(afs_v2net(vnode), server);
393 _leave(" [local failure]"); 433 fc->server = NULL;
394 return 1; 434 _leave(" = f [local failure]");
435 return false;
395 } 436 }
396 437
397 /* tell the caller to loop around and try the next server */ 438 /* tell the caller to loop around and try the next server */
@@ -399,6 +440,16 @@ try_next_server_upw:
399 up_write(&volume->server_sem); 440 up_write(&volume->server_sem);
400try_next_server: 441try_next_server:
401 afs_put_server(afs_v2net(vnode), server); 442 afs_put_server(afs_v2net(vnode), server);
402 _leave(" [try next server]"); 443 _leave(" = t [try next server]");
403 return 0; 444 return true;
445}
446
447/*
448 * Clean up a fileserver cursor.
449 */
450int 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;
404} 455}