blob: 782ee7c600caf0ec80c43f9c91407d1d93d6d506 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* 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 */
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700284 vlocation = kzalloc(sizeof(struct afs_vlocation), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 if (!vlocation)
286 return -ENOMEM;
287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 atomic_set(&vlocation->usage, 1);
289 INIT_LIST_HEAD(&vlocation->link);
290 rwlock_init(&vlocation->lock);
291 memcpy(vlocation->vldb.name, name, namesz);
292
293 afs_timer_init(&vlocation->timeout, &afs_vlocation_timer_ops);
294 afs_timer_init(&vlocation->upd_timer, &afs_vlocation_update_timer_ops);
295 afs_async_op_init(&vlocation->upd_op, &afs_vlocation_update_op_ops);
296
297 afs_get_cell(cell);
298 vlocation->cell = cell;
299
300 list_add_tail(&vlocation->link, &cell->vl_list);
301
302#ifdef AFS_CACHING_SUPPORT
303 /* we want to store it in the cache, plus it might already be
304 * encached */
305 cachefs_acquire_cookie(cell->cache,
306 &afs_volume_cache_index_def,
307 vlocation,
308 &vlocation->cache);
309
310 if (vlocation->valid)
311 goto found_in_cache;
312#endif
313
314 /* try to look up an unknown volume in the cell VL databases by name */
315 ret = afs_vlocation_access_vl_by_name(vlocation, name, namesz, &vldb);
316 if (ret < 0) {
317 printk("kAFS: failed to locate '%*.*s' in cell '%s'\n",
318 namesz, namesz, name, cell->name);
319 goto error;
320 }
321
322 goto found_on_vlserver;
323
324 found_in_graveyard:
325 /* found in the graveyard - resurrect */
326 _debug("found in graveyard");
327 atomic_inc(&vlocation->usage);
Akinobu Mitaf1166292006-06-26 00:24:46 -0700328 list_move_tail(&vlocation->link, &cell->vl_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 spin_unlock(&cell->vl_gylock);
330
331 afs_kafstimod_del_timer(&vlocation->timeout);
332 goto active;
333
334 found_in_memory:
335 /* found in memory - check to see if it's active */
336 _debug("found in memory");
337 atomic_inc(&vlocation->usage);
338
339 active:
340 active = 1;
341
342#ifdef AFS_CACHING_SUPPORT
343 found_in_cache:
344#endif
345 /* try to look up a cached volume in the cell VL databases by ID */
346 _debug("found in cache");
347
348 _debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",
349 vlocation->vldb.name,
350 vlocation->vldb.vidmask,
351 ntohl(vlocation->vldb.servers[0].s_addr),
352 vlocation->vldb.srvtmask[0],
353 ntohl(vlocation->vldb.servers[1].s_addr),
354 vlocation->vldb.srvtmask[1],
355 ntohl(vlocation->vldb.servers[2].s_addr),
356 vlocation->vldb.srvtmask[2]
357 );
358
359 _debug("Vids: %08x %08x %08x",
360 vlocation->vldb.vid[0],
361 vlocation->vldb.vid[1],
362 vlocation->vldb.vid[2]);
363
364 if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) {
365 vid = vlocation->vldb.vid[0];
366 voltype = AFSVL_RWVOL;
367 }
368 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) {
369 vid = vlocation->vldb.vid[1];
370 voltype = AFSVL_ROVOL;
371 }
372 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) {
373 vid = vlocation->vldb.vid[2];
374 voltype = AFSVL_BACKVOL;
375 }
376 else {
377 BUG();
378 vid = 0;
379 voltype = 0;
380 }
381
382 ret = afs_vlocation_access_vl_by_id(vlocation, vid, voltype, &vldb);
383 switch (ret) {
384 /* net error */
385 default:
386 printk("kAFS: failed to volume '%*.*s' (%x) up in '%s': %d\n",
387 namesz, namesz, name, vid, cell->name, ret);
388 goto error;
389
390 /* pulled from local cache into memory */
391 case 0:
392 goto found_on_vlserver;
393
394 /* uh oh... looks like the volume got deleted */
395 case -ENOMEDIUM:
396 printk("kAFS: volume '%*.*s' (%x) does not exist '%s'\n",
397 namesz, namesz, name, vid, cell->name);
398
399 /* TODO: make existing record unavailable */
400 goto error;
401 }
402
403 found_on_vlserver:
404 _debug("Done VL Lookup: %*.*s %02x { %08x(%x) %08x(%x) %08x(%x) }",
405 namesz, namesz, name,
406 vldb.vidmask,
407 ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0],
408 ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1],
409 ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2]
410 );
411
412 _debug("Vids: %08x %08x %08x", vldb.vid[0], vldb.vid[1], vldb.vid[2]);
413
414 if ((namesz < sizeof(vlocation->vldb.name) &&
415 vlocation->vldb.name[namesz] != '\0') ||
416 memcmp(vldb.name, name, namesz) != 0)
417 printk("kAFS: name of volume '%*.*s' changed to '%s' on server\n",
418 namesz, namesz, name, vldb.name);
419
420 memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb));
421
422 afs_kafstimod_add_timer(&vlocation->upd_timer, 10 * HZ);
423
424#ifdef AFS_CACHING_SUPPORT
425 /* update volume entry in local cache */
426 cachefs_update_cookie(vlocation->cache);
427#endif
428
429 *_vlocation = vlocation;
430 _leave(" = 0 (%p)",vlocation);
431 return 0;
432
433 error:
434 if (vlocation) {
435 if (active) {
436 __afs_put_vlocation(vlocation);
437 }
438 else {
439 list_del(&vlocation->link);
440#ifdef AFS_CACHING_SUPPORT
441 cachefs_relinquish_cookie(vlocation->cache, 0);
442#endif
443 afs_put_cell(vlocation->cell);
444 kfree(vlocation);
445 }
446 }
447
448 _leave(" = %d", ret);
449 return ret;
450} /* end afs_vlocation_lookup() */
451
452/*****************************************************************************/
453/*
454 * finish using a volume location record
455 * - caller must have cell->vol_sem write-locked
456 */
457static void __afs_put_vlocation(struct afs_vlocation *vlocation)
458{
459 struct afs_cell *cell;
460
461 if (!vlocation)
462 return;
463
464 _enter("%s", vlocation->vldb.name);
465
466 cell = vlocation->cell;
467
468 /* sanity check */
469 BUG_ON(atomic_read(&vlocation->usage) <= 0);
470
471 spin_lock(&cell->vl_gylock);
472 if (likely(!atomic_dec_and_test(&vlocation->usage))) {
473 spin_unlock(&cell->vl_gylock);
474 _leave("");
475 return;
476 }
477
478 /* move to graveyard queue */
Akinobu Mitaf1166292006-06-26 00:24:46 -0700479 list_move_tail(&vlocation->link,&cell->vl_graveyard);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
481 /* remove from pending timeout queue (refcounted if actually being
482 * updated) */
483 list_del_init(&vlocation->upd_op.link);
484
485 /* time out in 10 secs */
486 afs_kafstimod_del_timer(&vlocation->upd_timer);
487 afs_kafstimod_add_timer(&vlocation->timeout, 10 * HZ);
488
489 spin_unlock(&cell->vl_gylock);
490
491 _leave(" [killed]");
492} /* end __afs_put_vlocation() */
493
494/*****************************************************************************/
495/*
496 * finish using a volume location record
497 */
498void afs_put_vlocation(struct afs_vlocation *vlocation)
499{
500 if (vlocation) {
501 struct afs_cell *cell = vlocation->cell;
502
503 down_write(&cell->vl_sem);
504 __afs_put_vlocation(vlocation);
505 up_write(&cell->vl_sem);
506 }
507} /* end afs_put_vlocation() */
508
509/*****************************************************************************/
510/*
511 * timeout vlocation record
512 * - removes from the cell's graveyard if the usage count is zero
513 */
514void afs_vlocation_do_timeout(struct afs_vlocation *vlocation)
515{
516 struct afs_cell *cell;
517
518 _enter("%s", vlocation->vldb.name);
519
520 cell = vlocation->cell;
521
522 BUG_ON(atomic_read(&vlocation->usage) < 0);
523
524 /* remove from graveyard if still dead */
525 spin_lock(&cell->vl_gylock);
526 if (atomic_read(&vlocation->usage) == 0)
527 list_del_init(&vlocation->link);
528 else
529 vlocation = NULL;
530 spin_unlock(&cell->vl_gylock);
531
532 if (!vlocation) {
533 _leave("");
534 return; /* resurrected */
535 }
536
537 /* we can now destroy it properly */
538#ifdef AFS_CACHING_SUPPORT
539 cachefs_relinquish_cookie(vlocation->cache, 0);
540#endif
541 afs_put_cell(cell);
542
543 kfree(vlocation);
544
545 _leave(" [destroyed]");
546} /* end afs_vlocation_do_timeout() */
547
548/*****************************************************************************/
549/*
550 * send an update operation to the currently selected server
551 */
552static int afs_vlocation_update_begin(struct afs_vlocation *vlocation)
553{
554 afs_voltype_t voltype;
555 afs_volid_t vid;
556 int ret;
557
558 _enter("%s{ufs=%u ucs=%u}",
559 vlocation->vldb.name,
560 vlocation->upd_first_svix,
561 vlocation->upd_curr_svix);
562
563 /* try to look up a cached volume in the cell VL databases by ID */
564 if (vlocation->vldb.vidmask & AFS_VOL_VTM_RW) {
565 vid = vlocation->vldb.vid[0];
566 voltype = AFSVL_RWVOL;
567 }
568 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_RO) {
569 vid = vlocation->vldb.vid[1];
570 voltype = AFSVL_ROVOL;
571 }
572 else if (vlocation->vldb.vidmask & AFS_VOL_VTM_BAK) {
573 vid = vlocation->vldb.vid[2];
574 voltype = AFSVL_BACKVOL;
575 }
576 else {
577 BUG();
578 vid = 0;
579 voltype = 0;
580 }
581
582 /* contact the chosen server */
583 ret = afs_server_lookup(
584 vlocation->cell,
585 &vlocation->cell->vl_addrs[vlocation->upd_curr_svix],
586 &vlocation->upd_op.server);
587
588 switch (ret) {
589 case 0:
590 break;
591 case -ENOMEM:
592 case -ENONET:
593 default:
594 _leave(" = %d", ret);
595 return ret;
596 }
597
598 /* initiate the update operation */
599 ret = afs_rxvl_get_entry_by_id_async(&vlocation->upd_op, vid, voltype);
600 if (ret < 0) {
601 _leave(" = %d", ret);
602 return ret;
603 }
604
605 _leave(" = %d", ret);
606 return ret;
607} /* end afs_vlocation_update_begin() */
608
609/*****************************************************************************/
610/*
611 * abandon updating a VL record
612 * - does not restart the update timer
613 */
614static void afs_vlocation_update_abandon(struct afs_vlocation *vlocation,
615 afs_vlocation_upd_t state,
616 int ret)
617{
618 _enter("%s,%u", vlocation->vldb.name, state);
619
620 if (ret < 0)
621 printk("kAFS: Abandoning VL update '%s': %d\n",
622 vlocation->vldb.name, ret);
623
624 /* discard the server record */
625 afs_put_server(vlocation->upd_op.server);
626 vlocation->upd_op.server = NULL;
627
628 spin_lock(&afs_vlocation_update_lock);
629 afs_vlocation_update = NULL;
630 vlocation->upd_state = state;
631
632 /* TODO: start updating next VL record on pending list */
633
634 spin_unlock(&afs_vlocation_update_lock);
635
636 _leave("");
637} /* end afs_vlocation_update_abandon() */
638
639/*****************************************************************************/
640/*
641 * handle periodic update timeouts and busy retry timeouts
642 * - called from kafstimod
643 */
644static void afs_vlocation_update_timer(struct afs_timer *timer)
645{
646 struct afs_vlocation *vlocation =
647 list_entry(timer, struct afs_vlocation, upd_timer);
648 int ret;
649
650 _enter("%s", vlocation->vldb.name);
651
652 /* only update if not in the graveyard (defend against putting too) */
653 spin_lock(&vlocation->cell->vl_gylock);
654
655 if (!atomic_read(&vlocation->usage))
656 goto out_unlock1;
657
658 spin_lock(&afs_vlocation_update_lock);
659
660 /* if we were woken up due to EBUSY sleep then restart immediately if
661 * possible or else jump to front of pending queue */
662 if (vlocation->upd_state == AFS_VLUPD_BUSYSLEEP) {
663 if (afs_vlocation_update) {
664 list_add(&vlocation->upd_op.link,
665 &afs_vlocation_update_pendq);
666 }
667 else {
668 afs_get_vlocation(vlocation);
669 afs_vlocation_update = vlocation;
670 vlocation->upd_state = AFS_VLUPD_INPROGRESS;
671 }
672 goto out_unlock2;
673 }
674
675 /* put on pending queue if there's already another update in progress */
676 if (afs_vlocation_update) {
677 vlocation->upd_state = AFS_VLUPD_PENDING;
678 list_add_tail(&vlocation->upd_op.link,
679 &afs_vlocation_update_pendq);
680 goto out_unlock2;
681 }
682
683 /* hold a ref on it while actually updating */
684 afs_get_vlocation(vlocation);
685 afs_vlocation_update = vlocation;
686 vlocation->upd_state = AFS_VLUPD_INPROGRESS;
687
688 spin_unlock(&afs_vlocation_update_lock);
689 spin_unlock(&vlocation->cell->vl_gylock);
690
691 /* okay... we can start the update */
692 _debug("BEGIN VL UPDATE [%s]", vlocation->vldb.name);
693 vlocation->upd_first_svix = vlocation->cell->vl_curr_svix;
694 vlocation->upd_curr_svix = vlocation->upd_first_svix;
695 vlocation->upd_rej_cnt = 0;
696 vlocation->upd_busy_cnt = 0;
697
698 ret = afs_vlocation_update_begin(vlocation);
699 if (ret < 0) {
700 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret);
701 afs_kafstimod_add_timer(&vlocation->upd_timer,
702 AFS_VLDB_TIMEOUT);
703 afs_put_vlocation(vlocation);
704 }
705
706 _leave("");
707 return;
708
709 out_unlock2:
710 spin_unlock(&afs_vlocation_update_lock);
711 out_unlock1:
712 spin_unlock(&vlocation->cell->vl_gylock);
713 _leave("");
714 return;
715
716} /* end afs_vlocation_update_timer() */
717
718/*****************************************************************************/
719/*
720 * attend to an update operation upon which an event happened
721 * - called in kafsasyncd context
722 */
723static void afs_vlocation_update_attend(struct afs_async_op *op)
724{
725 struct afs_cache_vlocation vldb;
726 struct afs_vlocation *vlocation =
727 list_entry(op, struct afs_vlocation, upd_op);
728 unsigned tmp;
729 int ret;
730
731 _enter("%s", vlocation->vldb.name);
732
733 ret = afs_rxvl_get_entry_by_id_async2(op, &vldb);
734 switch (ret) {
735 case -EAGAIN:
736 _leave(" [unfinished]");
737 return;
738
739 case 0:
740 _debug("END VL UPDATE: %d\n", ret);
741 vlocation->valid = 1;
742
743 _debug("Done VL Lookup: %02x { %08x(%x) %08x(%x) %08x(%x) }",
744 vldb.vidmask,
745 ntohl(vldb.servers[0].s_addr), vldb.srvtmask[0],
746 ntohl(vldb.servers[1].s_addr), vldb.srvtmask[1],
747 ntohl(vldb.servers[2].s_addr), vldb.srvtmask[2]
748 );
749
750 _debug("Vids: %08x %08x %08x",
751 vldb.vid[0], vldb.vid[1], vldb.vid[2]);
752
753 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0);
754
755 down_write(&vlocation->cell->vl_sem);
756
757 /* actually update the cache */
758 if (strncmp(vldb.name, vlocation->vldb.name,
759 sizeof(vlocation->vldb.name)) != 0)
760 printk("kAFS: name of volume '%s'"
761 " changed to '%s' on server\n",
762 vlocation->vldb.name, vldb.name);
763
764 memcpy(&vlocation->vldb, &vldb, sizeof(vlocation->vldb));
765
766#if 0
767 /* TODO update volume entry in local cache */
768#endif
769
770 up_write(&vlocation->cell->vl_sem);
771
772 if (ret < 0)
773 printk("kAFS: failed to update local cache: %d\n", ret);
774
775 afs_kafstimod_add_timer(&vlocation->upd_timer,
776 AFS_VLDB_TIMEOUT);
777 afs_put_vlocation(vlocation);
778 _leave(" [found]");
779 return;
780
781 case -ENOMEDIUM:
782 vlocation->upd_rej_cnt++;
783 goto try_next;
784
785 /* the server is locked - retry in a very short while */
786 case -EBUSY:
787 vlocation->upd_busy_cnt++;
788 if (vlocation->upd_busy_cnt > 3)
789 goto try_next; /* too many retries */
790
791 afs_vlocation_update_abandon(vlocation,
792 AFS_VLUPD_BUSYSLEEP, 0);
793 afs_kafstimod_add_timer(&vlocation->upd_timer, HZ / 2);
794 afs_put_vlocation(vlocation);
795 _leave(" [busy]");
796 return;
797
798 case -ENETUNREACH:
799 case -EHOSTUNREACH:
800 case -ECONNREFUSED:
801 case -EREMOTEIO:
802 /* record bad vlserver info in the cell too
803 * - TODO: use down_write_trylock() if available
804 */
805 if (vlocation->upd_curr_svix == vlocation->cell->vl_curr_svix)
806 vlocation->cell->vl_curr_svix =
807 vlocation->cell->vl_curr_svix %
808 vlocation->cell->vl_naddrs;
809
810 case -EBADRQC:
811 case -EINVAL:
812 case -EACCES:
813 case -EBADMSG:
814 goto try_next;
815
816 default:
817 goto abandon;
818 }
819
820 /* try contacting the next server */
821 try_next:
822 vlocation->upd_busy_cnt = 0;
823
824 /* discard the server record */
825 afs_put_server(vlocation->upd_op.server);
826 vlocation->upd_op.server = NULL;
827
828 tmp = vlocation->cell->vl_naddrs;
829 if (tmp == 0)
830 goto abandon;
831
832 vlocation->upd_curr_svix++;
833 if (vlocation->upd_curr_svix >= tmp)
834 vlocation->upd_curr_svix = 0;
835 if (vlocation->upd_first_svix >= tmp)
836 vlocation->upd_first_svix = tmp - 1;
837
838 /* move to the next server */
839 if (vlocation->upd_curr_svix != vlocation->upd_first_svix) {
840 afs_vlocation_update_begin(vlocation);
841 _leave(" [next]");
842 return;
843 }
844
845 /* run out of servers to try - was the volume rejected? */
846 if (vlocation->upd_rej_cnt > 0) {
847 printk("kAFS: Active volume no longer valid '%s'\n",
848 vlocation->vldb.name);
849 vlocation->valid = 0;
850 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, 0);
851 afs_kafstimod_add_timer(&vlocation->upd_timer,
852 AFS_VLDB_TIMEOUT);
853 afs_put_vlocation(vlocation);
854 _leave(" [invalidated]");
855 return;
856 }
857
858 /* abandon the update */
859 abandon:
860 afs_vlocation_update_abandon(vlocation, AFS_VLUPD_SLEEP, ret);
861 afs_kafstimod_add_timer(&vlocation->upd_timer, HZ * 10);
862 afs_put_vlocation(vlocation);
863 _leave(" [abandoned]");
864
865} /* end afs_vlocation_update_attend() */
866
867/*****************************************************************************/
868/*
869 * deal with an update operation being discarded
870 * - called in kafsasyncd context when it's dying due to rmmod
871 * - the call has already been aborted and put()'d
872 */
873static void afs_vlocation_update_discard(struct afs_async_op *op)
874{
875 struct afs_vlocation *vlocation =
876 list_entry(op, struct afs_vlocation, upd_op);
877
878 _enter("%s", vlocation->vldb.name);
879
880 afs_put_server(op->server);
881 op->server = NULL;
882
883 afs_put_vlocation(vlocation);
884
885 _leave("");
886} /* end afs_vlocation_update_discard() */
887
888/*****************************************************************************/
889/*
890 * match a VLDB record stored in the cache
891 * - may also load target from entry
892 */
893#ifdef AFS_CACHING_SUPPORT
894static cachefs_match_val_t afs_vlocation_cache_match(void *target,
895 const void *entry)
896{
897 const struct afs_cache_vlocation *vldb = entry;
898 struct afs_vlocation *vlocation = target;
899
900 _enter("{%s},{%s}", vlocation->vldb.name, vldb->name);
901
902 if (strncmp(vlocation->vldb.name, vldb->name, sizeof(vldb->name)) == 0
903 ) {
904 if (!vlocation->valid ||
905 vlocation->vldb.rtime == vldb->rtime
906 ) {
907 vlocation->vldb = *vldb;
908 vlocation->valid = 1;
909 _leave(" = SUCCESS [c->m]");
910 return CACHEFS_MATCH_SUCCESS;
911 }
912 /* need to update cache if cached info differs */
913 else if (memcmp(&vlocation->vldb, vldb, sizeof(*vldb)) != 0) {
914 /* delete if VIDs for this name differ */
915 if (memcmp(&vlocation->vldb.vid,
916 &vldb->vid,
917 sizeof(vldb->vid)) != 0) {
918 _leave(" = DELETE");
919 return CACHEFS_MATCH_SUCCESS_DELETE;
920 }
921
922 _leave(" = UPDATE");
923 return CACHEFS_MATCH_SUCCESS_UPDATE;
924 }
925 else {
926 _leave(" = SUCCESS");
927 return CACHEFS_MATCH_SUCCESS;
928 }
929 }
930
931 _leave(" = FAILED");
932 return CACHEFS_MATCH_FAILED;
933} /* end afs_vlocation_cache_match() */
934#endif
935
936/*****************************************************************************/
937/*
938 * update a VLDB record stored in the cache
939 */
940#ifdef AFS_CACHING_SUPPORT
941static void afs_vlocation_cache_update(void *source, void *entry)
942{
943 struct afs_cache_vlocation *vldb = entry;
944 struct afs_vlocation *vlocation = source;
945
946 _enter("");
947
948 *vldb = vlocation->vldb;
949
950} /* end afs_vlocation_cache_update() */
951#endif