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