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