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