fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / afs / vlocation.c
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
29 static void afs_vlocation_update_timer(struct afs_timer *timer);
30 static void afs_vlocation_update_attend(struct afs_async_op *op);
31 static void afs_vlocation_update_discard(struct afs_async_op *op);
32 static void __afs_put_vlocation(struct afs_vlocation *vlocation);
33
34 static 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
45 static const struct afs_timer_ops afs_vlocation_timer_ops = {
46         .timed_out      = __afs_vlocation_timeout,
47 };
48
49 static const struct afs_timer_ops afs_vlocation_update_timer_ops = {
50         .timed_out      = afs_vlocation_update_timer,
51 };
52
53 static 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
58 static LIST_HEAD(afs_vlocation_update_pendq);   /* queue of VLs awaiting update */
59 static struct afs_vlocation *afs_vlocation_update;      /* VL currently being updated */
60 static DEFINE_SPINLOCK(afs_vlocation_update_lock); /* lock guarding update queue */
61
62 #ifdef AFS_CACHING_SUPPORT
63 static cachefs_match_val_t afs_vlocation_cache_match(void *target,
64                                                      const void *entry);
65 static void afs_vlocation_cache_update(void *source, void *entry);
66
67 struct 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  */
82 static 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  */
161 static 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  */
243 int 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 = kzalloc(sizeof(struct afs_vlocation), GFP_KERNEL);
285         if (!vlocation)
286                 return -ENOMEM;
287
288         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);
328         list_move_tail(&vlocation->link, &cell->vl_list);
329         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  */
457 static 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 */
479         list_move_tail(&vlocation->link,&cell->vl_graveyard);
480
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  */
498 void 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  */
514 void 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  */
552 static 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  */
614 static 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  */
644 static 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  */
723 static 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  */
873 static 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
894 static 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
941 static 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