aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs/vlocation.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs/vlocation.c')
-rw-r--r--fs/afs/vlocation.c954
1 files changed, 954 insertions, 0 deletions
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
new file mode 100644
index 000000000000..eced20618ecc
--- /dev/null
+++ b/fs/afs/vlocation.c
@@ -0,0 +1,954 @@
1/* vlocation.c: volume location management
2 *
3 * Copyright (C) 2002 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 License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/slab.h>
16#include <linux/fs.h>
17#include <linux/pagemap.h>
18#include "volume.h"
19#include "cell.h"
20#include "cmservice.h"
21#include "fsclient.h"
22#include "vlclient.h"
23#include "kafstimod.h"
24#include <rxrpc/connection.h>
25#include "internal.h"
26
27#define AFS_VLDB_TIMEOUT HZ*1000
28
29static void afs_vlocation_update_timer(struct afs_timer *timer);
30static void afs_vlocation_update_attend(struct afs_async_op *op);
31static void afs_vlocation_update_discard(struct afs_async_op *op);
32static void __afs_put_vlocation(struct afs_vlocation *vlocation);
33
34static void __afs_vlocation_timeout(struct afs_timer *timer)
35{
36 struct afs_vlocation *vlocation =
37 list_entry(timer, struct afs_vlocation, timeout);
38
39 _debug("VL TIMEOUT [%s{u=%d}]",
40 vlocation->vldb.name, atomic_read(&vlocation->usage));
41
42 afs_vlocation_do_timeout(vlocation);
43}
44
45static const struct afs_timer_ops afs_vlocation_timer_ops = {
46 .timed_out = __afs_vlocation_timeout,
47};
48
49static const struct afs_timer_ops afs_vlocation_update_timer_ops = {
50 .timed_out = afs_vlocation_update_timer,
51};
52
53static const struct afs_async_op_ops afs_vlocation_update_op_ops = {
54 .attend = afs_vlocation_update_attend,
55 .discard = afs_vlocation_update_discard,
56};
57
58static LIST_HEAD(afs_vlocation_update_pendq); /* queue of VLs awaiting update */
59static struct afs_vlocation *afs_vlocation_update; /* VL currently being updated */
60static DEFINE_SPINLOCK(afs_vlocation_update_lock); /* lock guarding update queue */
61
62#ifdef AFS_CACHING_SUPPORT
63static cachefs_match_val_t afs_vlocation_cache_match(void *target,
64 const void *entry);
65static void afs_vlocation_cache_update(void *source, void *entry);
66
67struct cachefs_index_def afs_vlocation_cache_index_def = {
68 .name = "vldb",
69 .data_size = sizeof(struct afs_cache_vlocation),
70 .keys[0] = { CACHEFS_INDEX_KEYS_ASCIIZ, 64 },
71 .match = afs_vlocation_cache_match,
72 .update = afs_vlocation_cache_update,
73};
74#endif
75
76/*****************************************************************************/
77/*
78 * iterate through the VL servers in a cell until one of them admits knowing
79 * about the volume in question
80 * - caller must have cell->vl_sem write-locked
81 */
82static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vlocation,
83 const char *name,
84 unsigned namesz,
85 struct afs_cache_vlocation *vldb)
86{
87 struct afs_server *server = NULL;
88 struct afs_cell *cell = vlocation->cell;
89 int count, ret;
90
91 _enter("%s,%*.*s,%u", cell->name, namesz, namesz, name, namesz);
92
93 ret = -ENOMEDIUM;
94 for (count = cell->vl_naddrs; count > 0; count--) {
95 _debug("CellServ[%hu]: %08x",
96 cell->vl_curr_svix,
97 cell->vl_addrs[cell->vl_curr_svix].s_addr);
98
99 /* try and create a server */
100 ret = afs_server_lookup(cell,
101 &cell->vl_addrs[cell->vl_curr_svix],
102 &server);
103 switch (ret) {
104 case 0:
105 break;
106 case -ENOMEM:
107 case -ENONET:
108 goto out;
109 default:
110 goto rotate;
111 }
112
113 /* attempt to access the VL server */
114 ret = afs_rxvl_get_entry_by_name(server, name, namesz, vldb);
115 switch (ret) {
116 case 0:
117 afs_put_server(server);
118 goto out;
119 case -ENOMEM:
120 case -ENONET:
121 case -ENETUNREACH:
122 case -EHOSTUNREACH:
123 case -ECONNREFUSED:
124 down_write(&server->sem);
125 if (server->vlserver) {
126 rxrpc_put_connection(server->vlserver);
127 server->vlserver = NULL;
128 }
129 up_write(&server->sem);
130 afs_put_server(server);
131 if (ret == -ENOMEM || ret == -ENONET)
132 goto out;
133 goto rotate;
134 case -ENOMEDIUM:
135 afs_put_server(server);
136 goto out;
137 default:
138 afs_put_server(server);
139 ret = -ENOMEDIUM;
140 goto rotate;
141 }
142
143 /* rotate the server records upon lookup failure */
144 rotate:
145 cell->vl_curr_svix++;
146 cell->vl_curr_svix %= cell->vl_naddrs;
147 }
148
149 out:
150 _leave(" = %d", ret);
151 return ret;
152
153} /* end afs_vlocation_access_vl_by_name() */
154
155/*****************************************************************************/
156/*
157 * iterate through the VL servers in a cell until one of them admits knowing
158 * about the volume in question
159 * - caller must have cell->vl_sem write-locked
160 */
161static int afs_vlocation_access_vl_by_id(struct afs_vlocation *vlocation,
162 afs_volid_t volid,
163 afs_voltype_t voltype,
164 struct afs_cache_vlocation *vldb)
165{
166 struct afs_server *server = NULL;
167 struct afs_cell *cell = vlocation->cell;
168 int count, ret;
169
170 _enter("%s,%x,%d,", cell->name, volid, voltype);
171
172 ret = -ENOMEDIUM;
173 for (count = cell->vl_naddrs; count > 0; count--) {
174 _debug("CellServ[%hu]: %08x",
175 cell->vl_curr_svix,
176 cell->vl_addrs[cell->vl_curr_svix].s_addr);
177
178 /* try and create a server */
179 ret = afs_server_lookup(cell,
180 &cell->vl_addrs[cell->vl_curr_svix],
181 &server);
182 switch (ret) {
183 case 0:
184 break;
185 case -ENOMEM:
186 case -ENONET:
187 goto out;
188 default:
189 goto rotate;
190 }
191
192 /* attempt to access the VL server */
193 ret = afs_rxvl_get_entry_by_id(server, volid, voltype, vldb);
194 switch (ret) {
195 case 0:
196 afs_put_server(server);
197 goto out;
198 case -ENOMEM:
199 case -ENONET:
200 case -ENETUNREACH:
201 case -EHOSTUNREACH:
202 case -ECONNREFUSED:
203 down_write(&server->sem);
204 if (server->vlserver) {
205 rxrpc_put_connection(server->vlserver);
206 server->vlserver = NULL;
207 }
208 up_write(&server->sem);
209 afs_put_server(server);
210 if (ret == -ENOMEM || ret == -ENONET)
211 goto out;
212 goto rotate;
213 case -ENOMEDIUM:
214 afs_put_server(server);
215 goto out;
216 default:
217 afs_put_server(server);
218 ret = -ENOMEDIUM;
219 goto rotate;
220 }
221
222 /* rotate the server records upon lookup failure */
223 rotate:
224 cell->vl_curr_svix++;
225 cell->vl_curr_svix %= cell->vl_naddrs;
226 }
227
228 out:
229 _leave(" = %d", ret);
230 return ret;
231
232} /* end afs_vlocation_access_vl_by_id() */
233
234/*****************************************************************************/
235/*
236 * lookup volume location
237 * - caller must have cell->vol_sem write-locked
238 * - iterate through the VL servers in a cell until one of them admits knowing
239 * about the volume in question
240 * - lookup in the local cache if not able to find on the VL server
241 * - insert/update in the local cache if did get a VL response
242 */
243int afs_vlocation_lookup(struct afs_cell *cell,
244 const char *name,
245 unsigned namesz,
246 struct afs_vlocation **_vlocation)
247{
248 struct afs_cache_vlocation vldb;
249 struct afs_vlocation *vlocation;
250 afs_voltype_t voltype;
251 afs_volid_t vid;
252 int active = 0, ret;
253
254 _enter("{%s},%*.*s,%u,", cell->name, namesz, namesz, name, namesz);
255
256 if (namesz > sizeof(vlocation->vldb.name)) {
257 _leave(" = -ENAMETOOLONG");
258 return -ENAMETOOLONG;
259 }
260
261 /* search the cell's active list first */
262 list_for_each_entry(vlocation, &cell->vl_list, link) {
263 if (namesz < sizeof(vlocation->vldb.name) &&
264 vlocation->vldb.name[namesz] != '\0')
265 continue;
266
267 if (memcmp(vlocation->vldb.name, name, namesz) == 0)
268 goto found_in_memory;
269 }
270
271 /* search the cell's graveyard list second */
272 spin_lock(&cell->vl_gylock);
273 list_for_each_entry(vlocation, &cell->vl_graveyard, link) {
274 if (namesz < sizeof(vlocation->vldb.name) &&
275 vlocation->vldb.name[namesz] != '\0')
276 continue;
277
278 if (memcmp(vlocation->vldb.name, name, namesz) == 0)
279 goto found_in_graveyard;
280 }
281 spin_unlock(&cell->vl_gylock);
282
283 /* not in the cell's in-memory lists - create a new record */
284 vlocation = kmalloc(sizeof(struct afs_vlocation), GFP_KERNEL);
285 if (!vlocation)
286 return -ENOMEM;
287
288 memset(vlocation, 0, sizeof(struct afs_vlocation));
289 atomic_set(&vlocation->usage, 1);
290 INIT_LIST_HEAD(&vlocation->link);
291 rwlock_init(&vlocation->lock);
292 memcpy(vlocation->vldb.name, name, namesz);
293
294 afs_timer_init(&vlocation->timeout, &afs_vlocation_timer_ops);
295 afs_timer_init(&vlocation->upd_timer, &afs_vlocation_update_timer_ops);
296 afs_async_op_init(&vlocation->upd_op, &afs_vlocation_update_op_ops);
297
298 afs_get_cell(cell);
299 vlocation->cell = cell;
300
301 list_add_tail(&vlocation->link, &cell->vl_list);
302
303#ifdef AFS_CACHING_SUPPORT
304 /* we want to store it in the cache, plus it might already be
305 * encached */
306 cachefs_acquire_cookie(cell->cache,
307 &afs_volume_cache_index_def,
308 vlocation,
309 &vlocation->cache);
310
311 if (vlocation->valid)
312 goto found_in_cache;
313#endif
314
315 /* try to look up an unknown volume in the cell VL databases by name */
316 ret = afs_vlocation_access_vl_by_name(vlocation, name, namesz, &vldb);
317 if (ret < 0) {
318 printk("kAFS: failed to locate '%*.*s' in cell '%s'\n",
319 namesz, namesz, name, cell->name);
320 goto error;
321 }
322
323 goto found_on_vlserver;
324
325 found_in_graveyard:
326 /* found in the graveyard - resurrect */
327 _debug("found in graveyard");
328 atomic_inc(&vlocation->usage);
329 list_del(&vlocation->link);
330 list_add_tail(&vlocation->link, &cell->vl_list);
331 spin_unlock(&cell->vl_gylock);
332
333 afs_kafstimod_del_timer(&vlocation->timeout);
334 goto active;
335
336 found_in_memory:
337 /* found in memory - check to see if it's active */
338 _debug("found in memory");
339 atomic_inc(&vlocation->usage);
340
341 active:
342 active = 1;
343
344#ifdef AFS_CACHING_SUPPORT
345 found_in_cache:
346#endif
347 /* try to look up a cached volume in the cell VL databases by ID */
348 _debug("found in cache");
349
350 _debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",
351 vlocation->vldb.name,
352 vlocation->vldb.vidmask,
353 ntohl(vlocation->vldb.servers[0].s_addr),
354 vlocation->vldb.srvtmask[0],
355 ntohl(vlocation->vldb.servers[1].s_addr),
356 vlocation->vldb.srvtmask[1],
357 ntohl(vlocation->vldb.servers[2].s_addr),
358 vlocation->vldb.srvtmask[2]
359 );
360
361 _debug("Vids: %08x %08x %08x",
362 vlocation->vldb.vid[0],
363 vlocation->vldb.vid[1],
364 vlocation->vldb.vid[2]);
365
366 if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) {
367 vid = vlocation->vldb.vid[0];
368 voltype = AFSVL_RWVOL;
369 }
370 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) {
371 vid = vlocation->vldb.vid[1];
372 voltype = AFSVL_ROVOL;
373 }
374 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) {
375 vid = vlocation->vldb.vid[2];
376 voltype = AFSVL_BACKVOL;
377 }
378 else {
379 BUG();
380 vid = 0;
381 voltype = 0;
382 }
383
384 ret = afs_vlocation_access_vl_by_id(vlocation, vid, voltype, &vldb);
385 switch (ret) {
386 /* net error */
387 default:
388 printk("kAFS: failed to volume '%*.*s' (%x) up in '%s': %d\n",
389 namesz, namesz, name, vid, cell->name, ret);
390 goto error;
391
392 /* pulled from local cache into memory */
393 case 0:
394 goto found_on_vlserver;
395
396 /* uh oh... looks like the volume got deleted */
397 case -ENOMEDIUM:
398 printk("kAFS: volume '%*.*s' (%x) does not exist '%s'\n",
399 namesz, namesz, name, vid, cell->name);
400
401 /* TODO: make existing record unavailable */
402 goto error;
403 }
404
405 found_on_vlserver:
406 _debug("Done VL Lookup: %*.*s %02x { %08x(%x) %08x(%x) %08x(%x) }",
407 namesz, namesz, name,
408 vldb.vidmask,
409 ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0],
410 ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1],
411 ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2]
412 );
413
414 _debug("Vids: %08x %08x %08x", vldb.vid[0], vldb.vid[1], vldb.vid[2]);
415
416 if ((namesz < sizeof(vlocation->vldb.name) &&
417 vlocation->vldb.name[namesz] != '\0') ||
418 memcmp(vldb.name, name, namesz) != 0)
419 printk("kAFS: name of volume '%*.*s' changed to '%s' on server\n",
420 namesz, namesz, name, vldb.name);
421
422 memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb));
423
424 afs_kafstimod_add_timer(&vlocation->upd_timer, 10 * HZ);
425
426#ifdef AFS_CACHING_SUPPORT
427 /* update volume entry in local cache */
428 cachefs_update_cookie(vlocation->cache);
429#endif
430
431 *_vlocation = vlocation;
432 _leave(" = 0 (%p)",vlocation);
433 return 0;
434
435 error:
436 if (vlocation) {
437 if (active) {
438 __afs_put_vlocation(vlocation);
439 }
440 else {
441 list_del(&vlocation->link);
442#ifdef AFS_CACHING_SUPPORT
443 cachefs_relinquish_cookie(vlocation->cache, 0);
444#endif
445 afs_put_cell(vlocation->cell);
446 kfree(vlocation);
447 }
448 }
449
450 _leave(" = %d", ret);
451 return ret;
452} /* end afs_vlocation_lookup() */
453
454/*****************************************************************************/
455/*
456 * finish using a volume location record
457 * - caller must have cell->vol_sem write-locked
458 */
459static void __afs_put_vlocation(struct afs_vlocation *vlocation)
460{
461 struct afs_cell *cell;
462
463 if (!vlocation)
464 return;
465
466 _enter("%s", vlocation->vldb.name);
467
468 cell = vlocation->cell;
469
470 /* sanity check */
471 BUG_ON(atomic_read(&vlocation->usage) <= 0);
472
473 spin_lock(&cell->vl_gylock);
474 if (likely(!atomic_dec_and_test(&vlocation->usage))) {
475 spin_unlock(&cell->vl_gylock);
476 _leave("");
477 return;
478 }
479
480 /* move to graveyard queue */
481 list_del(&vlocation->link);
482 list_add_tail(&vlocation->link,&cell->vl_graveyard);
483
484 /* remove from pending timeout queue (refcounted if actually being
485 * updated) */
486 list_del_init(&vlocation->upd_op.link);
487
488 /* time out in 10 secs */
489 afs_kafstimod_del_timer(&vlocation->upd_timer);
490 afs_kafstimod_add_timer(&vlocation->timeout, 10 * HZ);
491
492 spin_unlock(&cell->vl_gylock);
493
494 _leave(" [killed]");
495} /* end __afs_put_vlocation() */
496
497/*****************************************************************************/
498/*
499 * finish using a volume location record
500 */
501void afs_put_vlocation(struct afs_vlocation *vlocation)
502{
503 if (vlocation) {
504 struct afs_cell *cell = vlocation->cell;
505
506 down_write(&cell->vl_sem);
507 __afs_put_vlocation(vlocation);
508 up_write(&cell->vl_sem);
509 }
510} /* end afs_put_vlocation() */
511
512/*****************************************************************************/
513/*
514 * timeout vlocation record
515 * - removes from the cell's graveyard if the usage count is zero
516 */
517void afs_vlocation_do_timeout(struct afs_vlocation *vlocation)
518{
519 struct afs_cell *cell;
520
521 _enter("%s", vlocation->vldb.name);
522
523 cell = vlocation->cell;
524
525 BUG_ON(atomic_read(&vlocation->usage) < 0);
526
527 /* remove from graveyard if still dead */
528 spin_lock(&cell->vl_gylock);
529 if (atomic_read(&vlocation->usage) == 0)
530 list_del_init(&vlocation->link);
531 else
532 vlocation = NULL;
533 spin_unlock(&cell->vl_gylock);
534
535 if (!vlocation) {
536 _leave("");
537 return; /* resurrected */
538 }
539
540 /* we can now destroy it properly */
541#ifdef AFS_CACHING_SUPPORT
542 cachefs_relinquish_cookie(vlocation->cache, 0);
543#endif
544 afs_put_cell(cell);
545
546 kfree(vlocation);
547
548 _leave(" [destroyed]");
549} /* end afs_vlocation_do_timeout() */
550
551/*****************************************************************************/
552/*
553 * send an update operation to the currently selected server
554 */
555static int afs_vlocation_update_begin(struct afs_vlocation *vlocation)
556{
557 afs_voltype_t voltype;
558 afs_volid_t vid;
559 int ret;
560
561 _enter("%s{ufs=%u ucs=%u}",
562 vlocation->vldb.name,
563 vlocation->upd_first_svix,
564 vlocation->upd_curr_svix);
565
566 /* try to look up a cached volume in the cell VL databases by ID */
567 if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) {
568 vid = vlocation->vldb.vid[0];
569 voltype = AFSVL_RWVOL;
570 }
571 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) {
572 vid = vlocation->vldb.vid[1];
573 voltype = AFSVL_ROVOL;
574 }
575 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) {
576 vid = vlocation->vldb.vid[2];
577 voltype = AFSVL_BACKVOL;
578 }
579 else {
580 BUG();
581 vid = 0;
582 voltype = 0;
583 }
584
585 /* contact the chosen server */
586 ret = afs_server_lookup(
587 vlocation->cell,
588 &vlocation->cell->vl_addrs[vlocation->upd_curr_svix],
589 &vlocation->upd_op.server);
590
591 switch (ret) {
592 case 0:
593 break;
594 case -ENOMEM:
595 case -ENONET:
596 default:
597 _leave(" = %d", ret);
598 return ret;
599 }
600
601 /* initiate the update operation */
602 ret = afs_rxvl_get_entry_by_id_async(&vlocation->upd_op, vid, voltype);
603 if (ret < 0) {
604 _leave(" = %d", ret);
605 return ret;
606 }
607
608 _leave(" = %d", ret);
609 return ret;
610} /* end afs_vlocation_update_begin() */
611
612/*****************************************************************************/
613/*
614 * abandon updating a VL record
615 * - does not restart the update timer
616 */
617static void afs_vlocation_update_abandon(struct afs_vlocation *vlocation,
618 afs_vlocation_upd_t state,
619 int ret)
620{
621 _enter("%s,%u", vlocation->vldb.name, state);
622
623 if (ret < 0)
624 printk("kAFS: Abandoning VL update '%s': %d\n",
625 vlocation->vldb.name, ret);
626
627 /* discard the server record */
628 afs_put_server(vlocation->upd_op.server);
629 vlocation->upd_op.server = NULL;
630
631 spin_lock(&afs_vlocation_update_lock);
632 afs_vlocation_update = NULL;
633 vlocation->upd_state = state;
634
635 /* TODO: start updating next VL record on pending list */
636
637 spin_unlock(&afs_vlocation_update_lock);
638
639 _leave("");
640} /* end afs_vlocation_update_abandon() */
641
642/*****************************************************************************/
643/*
644 * handle periodic update timeouts and busy retry timeouts
645 * - called from kafstimod
646 */
647static void afs_vlocation_update_timer(struct afs_timer *timer)
648{
649 struct afs_vlocation *vlocation =
650 list_entry(timer, struct afs_vlocation, upd_timer);
651 int ret;
652
653 _enter("%s", vlocation->vldb.name);
654
655 /* only update if not in the graveyard (defend against putting too) */
656 spin_lock(&vlocation->cell->vl_gylock);
657
658 if (!atomic_read(&vlocation->usage))
659 goto out_unlock1;
660
661 spin_lock(&afs_vlocation_update_lock);
662
663 /* if we were woken up due to EBUSY sleep then restart immediately if
664 * possible or else jump to front of pending queue */
665 if (vlocation->upd_state == AFS_VLUPD_BUSYSLEEP) {
666 if (afs_vlocation_update) {
667 list_add(&vlocation->upd_op.link,
668 &afs_vlocation_update_pendq);
669 }
670 else {
671 afs_get_vlocation(vlocation);
672 afs_vlocation_update = vlocation;
673 vlocation->upd_state = AFS_VLUPD_INPROGRESS;
674 }
675 goto out_unlock2;
676 }
677
678 /* put on pending queue if there's already another update in progress */
679 if (afs_vlocation_update) {
680 vlocation->upd_state = AFS_VLUPD_PENDING;
681 list_add_tail(&vlocation->upd_op.link,
682 &afs_vlocation_update_pendq);
683 goto out_unlock2;
684 }
685
686 /* hold a ref on it while actually updating */
687 afs_get_vlocation(vlocation);
688 afs_vlocation_update = vlocation;
689 vlocation->upd_state = AFS_VLUPD_INPROGRESS;
690
691 spin_unlock(&afs_vlocation_update_lock);
692 spin_unlock(&vlocation->cell->vl_gylock);
693
694 /* okay... we can start the update */
695 _debug("BEGIN VL UPDATE [%s]", vlocation->vldb.name);
696 vlocation->upd_first_svix = vlocation->cell->vl_curr_svix;
697 vlocation->upd_curr_svix = vlocation->upd_first_svix;
698 vlocation->upd_rej_cnt = 0;
699 vlocation->upd_busy_cnt = 0;
700
701 ret = afs_vlocation_update_begin(vlocation);
702 if (ret < 0) {
703 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret);
704 afs_kafstimod_add_timer(&vlocation->upd_timer,
705 AFS_VLDB_TIMEOUT);
706 afs_put_vlocation(vlocation);
707 }
708
709 _leave("");
710 return;
711
712 out_unlock2:
713 spin_unlock(&afs_vlocation_update_lock);
714 out_unlock1:
715 spin_unlock(&vlocation->cell->vl_gylock);
716 _leave("");
717 return;
718
719} /* end afs_vlocation_update_timer() */
720
721/*****************************************************************************/
722/*
723 * attend to an update operation upon which an event happened
724 * - called in kafsasyncd context
725 */
726static void afs_vlocation_update_attend(struct afs_async_op *op)
727{
728 struct afs_cache_vlocation vldb;
729 struct afs_vlocation *vlocation =
730 list_entry(op, struct afs_vlocation, upd_op);
731 unsigned tmp;
732 int ret;
733
734 _enter("%s", vlocation->vldb.name);
735
736 ret = afs_rxvl_get_entry_by_id_async2(op, &vldb);
737 switch (ret) {
738 case -EAGAIN:
739 _leave(" [unfinished]");
740 return;
741
742 case 0:
743 _debug("END VL UPDATE: %d\n", ret);
744 vlocation->valid = 1;
745
746 _debug("Done VL Lookup: %02x { %08x(%x) %08x(%x) %08x(%x) }",
747 vldb.vidmask,
748 ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0],
749 ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1],
750 ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2]
751 );
752
753 _debug("Vids: %08x %08x %08x",
754 vldb.vid[0], vldb.vid[1], vldb.vid[2]);
755
756 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0);
757
758 down_write(&vlocation->cell->vl_sem);
759
760 /* actually update the cache */
761 if (strncmp(vldb.name, vlocation->vldb.name,
762 sizeof(vlocation->vldb.name)) != 0)
763 printk("kAFS: name of volume '%s'"
764 " changed to '%s' on server\n",
765 vlocation->vldb.name, vldb.name);
766
767 memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb));
768
769#if 0
770 /* TODO update volume entry in local cache */
771#endif
772
773 up_write(&vlocation->cell->vl_sem);
774
775 if (ret < 0)
776 printk("kAFS: failed to update local cache: %d\n", ret);
777
778 afs_kafstimod_add_timer(&vlocation->upd_timer,
779 AFS_VLDB_TIMEOUT);
780 afs_put_vlocation(vlocation);
781 _leave(" [found]");
782 return;
783
784 case -ENOMEDIUM:
785 vlocation->upd_rej_cnt++;
786 goto try_next;
787
788 /* the server is locked - retry in a very short while */
789 case -EBUSY:
790 vlocation->upd_busy_cnt++;
791 if (vlocation->upd_busy_cnt > 3)
792 goto try_next; /* too many retries */
793
794 afs_vlocation_update_abandon(vlocation,
795 AFS_VLUPD_BUSYSLEEP, 0);
796 afs_kafstimod_add_timer(&vlocation->upd_timer, HZ / 2);
797 afs_put_vlocation(vlocation);
798 _leave(" [busy]");
799 return;
800
801 case -ENETUNREACH:
802 case -EHOSTUNREACH:
803 case -ECONNREFUSED:
804 case -EREMOTEIO:
805 /* record bad vlserver info in the cell too
806 * - TODO: use down_write_trylock() if available
807 */
808 if (vlocation->upd_curr_svix == vlocation->cell->vl_curr_svix)
809 vlocation->cell->vl_curr_svix =
810 vlocation->cell->vl_curr_svix %
811 vlocation->cell->vl_naddrs;
812
813 case -EBADRQC:
814 case -EINVAL:
815 case -EACCES:
816 case -EBADMSG:
817 goto try_next;
818
819 default:
820 goto abandon;
821 }
822
823 /* try contacting the next server */
824 try_next:
825 vlocation->upd_busy_cnt = 0;
826
827 /* discard the server record */
828 afs_put_server(vlocation->upd_op.server);
829 vlocation->upd_op.server = NULL;
830
831 tmp = vlocation->cell->vl_naddrs;
832 if (tmp == 0)
833 goto abandon;
834
835 vlocation->upd_curr_svix++;
836 if (vlocation->upd_curr_svix >= tmp)
837 vlocation->upd_curr_svix = 0;
838 if (vlocation->upd_first_svix >= tmp)
839 vlocation->upd_first_svix = tmp - 1;
840
841 /* move to the next server */
842 if (vlocation->upd_curr_svix != vlocation->upd_first_svix) {
843 afs_vlocation_update_begin(vlocation);
844 _leave(" [next]");
845 return;
846 }
847
848 /* run out of servers to try - was the volume rejected? */
849 if (vlocation->upd_rej_cnt > 0) {
850 printk("kAFS: Active volume no longer valid '%s'\n",
851 vlocation->vldb.name);
852 vlocation->valid = 0;
853 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0);
854 afs_kafstimod_add_timer(&vlocation->upd_timer,
855 AFS_VLDB_TIMEOUT);
856 afs_put_vlocation(vlocation);
857 _leave(" [invalidated]");
858 return;
859 }
860
861 /* abandon the update */
862 abandon:
863 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret);
864 afs_kafstimod_add_timer(&vlocation->upd_timer, HZ * 10);
865 afs_put_vlocation(vlocation);
866 _leave(" [abandoned]");
867
868} /* end afs_vlocation_update_attend() */
869
870/*****************************************************************************/
871/*
872 * deal with an update operation being discarded
873 * - called in kafsasyncd context when it's dying due to rmmod
874 * - the call has already been aborted and put()'d
875 */
876static void afs_vlocation_update_discard(struct afs_async_op *op)
877{
878 struct afs_vlocation *vlocation =
879 list_entry(op, struct afs_vlocation, upd_op);
880
881 _enter("%s", vlocation->vldb.name);
882
883 afs_put_server(op->server);
884 op->server = NULL;
885
886 afs_put_vlocation(vlocation);
887
888 _leave("");
889} /* end afs_vlocation_update_discard() */
890
891/*****************************************************************************/
892/*
893 * match a VLDB record stored in the cache
894 * - may also load target from entry
895 */
896#ifdef AFS_CACHING_SUPPORT
897static cachefs_match_val_t afs_vlocation_cache_match(void *target,
898 const void *entry)
899{
900 const struct afs_cache_vlocation *vldb = entry;
901 struct afs_vlocation *vlocation = target;
902
903 _enter("{%s},{%s}", vlocation->vldb.name, vldb->name);
904
905 if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0
906 ) {
907 if (!vlocation->valid ||
908 vlocation->vldb.rtime == vldb->rtime
909 ) {
910 vlocation->vldb = *vldb;
911 vlocation->valid = 1;
912 _leave(" = SUCCESS [c->m]");
913 return CACHEFS_MATCH_SUCCESS;
914 }
915 /* need to update cache if cached info differs */
916 else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) {
917 /* delete if VIDs for this name differ */
918 if (memcmp(&vlocation->vldb.vid,
919 &vldb->vid,
920 sizeof(vldb->vid)) != 0) {
921 _leave(" = DELETE");
922 return CACHEFS_MATCH_SUCCESS_DELETE;
923 }
924
925 _leave(" = UPDATE");
926 return CACHEFS_MATCH_SUCCESS_UPDATE;
927 }
928 else {
929 _leave(" = SUCCESS");
930 return CACHEFS_MATCH_SUCCESS;
931 }
932 }
933
934 _leave(" = FAILED");
935 return CACHEFS_MATCH_FAILED;
936} /* end afs_vlocation_cache_match() */
937#endif
938
939/*****************************************************************************/
940/*
941 * update a VLDB record stored in the cache
942 */
943#ifdef AFS_CACHING_SUPPORT
944static void afs_vlocation_cache_update(void *source, void *entry)
945{
946 struct afs_cache_vlocation *vldb = entry;
947 struct afs_vlocation *vlocation = source;
948
949 _enter("");
950
951 *vldb = vlocation->vldb;
952
953} /* end afs_vlocation_cache_update() */
954#endif