afs: Clarify vcache->mvid accesses
[openafs.git] / src / afs / afs_volume.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Implements:
12  * afs_vtoi (local)
13  * afs_UFSGetVolSlot
14  * afs_MemGetVolSlot
15  * afs_CheckVolumeNames
16  * afs_FindVolume
17  */
18 #include <afsconfig.h>
19 #include "afs/param.h"
20
21
22 #include "afs/stds.h"
23 #include "afs/sysincludes.h"    /* Standard vendor system headers */
24
25 #if !defined(UKERNEL)
26 #if !defined(AFS_LINUX20_ENV)
27 #include <net/if.h>
28 #endif
29 #include <netinet/in.h>
30
31 #ifdef AFS_SGI62_ENV
32 #include "h/hashing.h"
33 #endif
34 #if !defined(AFS_HPUX110_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV)
35 #include <netinet/in_var.h>
36 #endif /* ! AFS_HPUX110_ENV */
37 #endif /* !defined(UKERNEL) */
38
39 #include "afsincludes.h"        /* Afs-based standard headers */
40 #include "afs/afs_stats.h"      /* afs statistics */
41 #include "afs/afs_dynroot.h"
42
43 #if     defined(AFS_SUN5_ENV)
44 #include <inet/led.h>
45 #include <inet/common.h>
46 #include <netinet/ip6.h>
47 #include <inet/ip.h>
48 #endif
49
50 /* In case we don't have the vl error table yet. */
51 #ifndef ERROR_TABLE_BASE_VL
52 #define ERROR_TABLE_BASE_VL     (363520L)
53 #define VL_NOENT                (363524L)
54 #endif /* vlserver error base define */
55
56 /* Exported variables */
57 afs_dcache_id_t volumeInode;    /* Inode for VolumeItems file */
58 afs_rwlock_t afs_xvolume;       /** allocation lock for volumes */
59 struct volume *afs_freeVolList;
60 struct volume *afs_volumes[NVOLS];
61 afs_int32 afs_volCounter = 1;   /** for allocating volume indices */
62 afs_int32 fvTable[NFENTRIES];
63
64 /* Forward declarations */
65 static struct volume *afs_NewVolumeByName(char *aname, afs_int32 acell,
66                                           int agood, struct vrequest *areq,
67                                           afs_int32 locktype);
68 static struct volume *afs_NewDynrootVolume(struct VenusFid *fid);
69 static int inVolList(struct VenusFid *fid, afs_int32 nvols, afs_int32 * vID,
70                      afs_int32 * cID);
71
72
73
74 /**
75  * Convert a volume name to a number;
76  * @param aname Volume name.
77  * @return return 0 if can't parse as a number.
78  */
79 static int
80 afs_vtoi(char *aname)
81 {
82     afs_int32 temp;
83     int tc;
84     temp = 0;
85     AFS_STATCNT(afs_vtoi);
86     while ((tc = *aname++)) {
87         if (tc > '9' || tc < '0')
88             return 0;           /* invalid name */
89         temp *= 10;
90         temp += tc - '0';
91     }
92     return temp;
93
94 }                               /*afs_vtoi */
95
96
97 /**
98  * All of the vol cache routines must be called with the afs_xvolume
99  * lock held in exclusive mode, since they use static variables.
100  * In addition, we don't want two people adding the same volume
101  * at the same time.
102  */
103
104 static struct fvolume staticFVolume;
105 afs_int32 afs_FVIndex = -1;
106
107 /*!
108  * Initialize a newly gotten volume slot.
109  *
110  * \param tv volume slot to be initialized
111  * \param tf volume item data; null if none
112  * \param volid volume id for this volume slot
113  * \param cell cell for this volume slot
114  * \return none
115  */
116 static void
117 afs_InitVolSlot(struct volume *tv, struct fvolume *tf, afs_int32 volid,
118                 struct cell *tcell)
119 {
120     AFS_STATCNT(afs_InitVolSlot);
121     memset(tv, 0, sizeof(struct volume));
122     tv->cell = tcell->cellNum;
123     AFS_RWLOCK_INIT(&tv->lock, "volume lock");
124     tv->volume = volid;
125     if (tf) {
126         tv->vtix = afs_FVIndex;
127         tv->mtpoint = tf->mtpoint;
128         tv->dotdot = tf->dotdot;
129         tv->rootVnode = tf->rootVnode;
130         tv->rootUnique = tf->rootUnique;
131     } else {
132         tv->vtix = -1;
133         tv->rootVnode = tv->rootUnique = 0;
134         afs_GetDynrootMountFid(&tv->dotdot);
135         afs_GetDynrootMountFid(&tv->mtpoint);
136         tv->mtpoint.Fid.Vnode =
137             VNUM_FROM_TYPEID(VN_TYPE_MOUNT, tcell->cellIndex << 2);
138         tv->mtpoint.Fid.Unique = volid;
139     }
140 }
141
142 /**
143  * UFS specific version of afs_GetVolSlot
144  * @return
145  */
146 struct volume *
147 afs_UFSGetVolSlot(afs_int32 volid, struct cell *tcell)
148 {
149     struct volume *tv = NULL, **lv;
150     struct osi_file *tfile;
151     afs_int32 i = -1, code;
152     afs_int32 bestTime;
153     struct volume *bestVp, *oldLp = NULL, **bestLp = NULL;
154     char *oldname = NULL;
155     afs_int32 oldvtix = -2; /* Initialize to a value that doesn't occur */
156     struct fvolume *tf = NULL;
157     int j = 0;
158
159     AFS_STATCNT(afs_UFSGetVolSlot);
160     if (!afs_freeVolList) {
161         /* get free slot */
162         bestTime = 0x7fffffff;
163         bestVp = 0;
164         bestLp = 0;
165         for (i = 0; i < NVOLS; i++) {
166             lv = &afs_volumes[i];
167             for (tv = *lv; tv; lv = &tv->next, tv = *lv) {
168                 if (tv->refCount == 0) {        /* is this one available? */
169                     if (tv->accessTime < bestTime) {    /* best one available? */
170                         bestTime = tv->accessTime;
171                         bestLp = lv;
172                         bestVp = tv;
173                     }
174                 }
175             }
176         }
177         if (!bestVp) {
178             afs_warn("afs_UFSGetVolSlot: no vol slots available\n");
179             goto error;
180         }
181         tv = bestVp;
182
183         oldLp = *bestLp;
184         *bestLp = tv->next;
185
186         oldname = tv->name;
187         tv->name = NULL;
188
189         oldvtix = tv->vtix;
190         /* now write out volume structure to file */
191         if (tv->vtix < 0) {
192             tv->vtix = afs_volCounter++;
193             /* now put on hash chain */
194             i = FVHash(tv->cell, tv->volume);
195             staticFVolume.next = fvTable[i];
196             fvTable[i] = tv->vtix;
197         } else {
198             /*
199              * Haul the guy in from disk so we don't overwrite hash table
200              * next chain
201              */
202             if (afs_FVIndex != tv->vtix) {
203                 tfile = osi_UFSOpen(&volumeInode);
204                 if (!tfile) {
205                     afs_warn("afs_UFSGetVolSlot: unable to open volumeinfo\n");
206                     goto error;
207                 }
208                 code =
209                     afs_osi_Read(tfile, sizeof(struct fvolume) * tv->vtix,
210                                  &staticFVolume, sizeof(struct fvolume));
211                 osi_UFSClose(tfile);
212                 if (code != sizeof(struct fvolume)) {
213                     afs_warn("afs_UFSGetVolSlot: error %d reading volumeinfo\n",
214                              (int)code);
215                     goto error;
216                 }
217             }
218         }
219         afs_FVIndex = tv->vtix;
220         staticFVolume.volume = tv->volume;
221         staticFVolume.cell = tv->cell;
222         staticFVolume.mtpoint = tv->mtpoint;
223         staticFVolume.dotdot = tv->dotdot;
224         staticFVolume.rootVnode = tv->rootVnode;
225         staticFVolume.rootUnique = tv->rootUnique;
226         tfile = osi_UFSOpen(&volumeInode);
227         if (!tfile) {
228             afs_warn("afs_UFSGetVolSlot: unable to open volumeinfo\n");
229             goto error;
230         }
231         code =
232             afs_osi_Write(tfile, sizeof(struct fvolume) * afs_FVIndex,
233                           &staticFVolume, sizeof(struct fvolume));
234         osi_UFSClose(tfile);
235         if (code != sizeof(struct fvolume)) {
236             afs_warn("afs_UFSGetVolSlot: error %d writing volumeinfo\n",
237                      (int)code);
238             goto error;
239         }
240         if (oldname) {
241             afs_osi_Free(oldname, strlen(oldname) + 1);
242             oldname = NULL;
243         }
244     } else {
245         tv = afs_freeVolList;
246         afs_freeVolList = tv->next;
247     }
248
249     /* read volume item data from disk for the gotten slot */
250     for (j = fvTable[FVHash(tcell->cellNum, volid)]; j != 0; j = tf->next) {
251         if (afs_FVIndex != j) {
252             tfile = osi_UFSOpen(&volumeInode);
253             if (!tfile) {
254                 afs_warn("afs_UFSGetVolSlot: unable to open volumeinfo\n");
255                 code = -1;   /* indicate error */
256             } else {
257                 code =
258                     afs_osi_Read(tfile, sizeof(struct fvolume) * j,
259                                  &staticFVolume, sizeof(struct fvolume));
260                 osi_UFSClose(tfile);
261                 if (code != sizeof(struct fvolume)) {
262                     afs_warn("afs_UFSGetVolSlot: error %d reading volumeinfo\n",
263                              (int)code);
264                 }
265             }
266             if (code != sizeof(struct fvolume)) {
267                 /* put tv back on the free list; the data in it is not valid */
268                 tv->next = afs_freeVolList;
269                 afs_freeVolList = tv;
270                 /* staticFVolume contents are not valid */
271                 afs_FVIndex = -1;
272                 return NULL;
273             }
274             afs_FVIndex = j;
275         }
276         if (j != 0) {           /* volume items record 0 is not used */
277             tf = &staticFVolume;
278             if (tf->cell == tcell->cellNum && tf->volume == volid) {
279                 break;
280             }
281         }
282     }
283
284     afs_InitVolSlot(tv, tf, volid, tcell);
285     return tv;
286
287  error:
288     if (tv) {
289         if (oldvtix == -2) {
290             afs_warn("afs_UFSGetVolSlot: oldvtix is uninitialized\n");
291             return NULL;
292         }
293         if (oldname) {
294             tv->name = oldname;
295             oldname = NULL;
296         }
297         if (oldvtix < 0) {
298             afs_volCounter--;
299             fvTable[i] = staticFVolume.next;
300         }
301         if (bestLp) {
302             *bestLp = oldLp;
303         }
304         tv->vtix = oldvtix;
305         /* we messed with staticFVolume, so make sure someone else
306          * doesn't think it's fine to use */
307         afs_FVIndex = -1;
308     }
309     return NULL;
310 }                               /*afs_UFSGetVolSlot */
311
312
313 /**
314  *   Get an available volume list slot. If the list does not exist,
315  * create one containing a single element.
316  * @return
317  */
318 struct volume *
319 afs_MemGetVolSlot(afs_int32 volid, struct cell *tcell)
320 {
321     struct volume *tv;
322
323     AFS_STATCNT(afs_MemGetVolSlot);
324     if (!afs_freeVolList) {
325         struct volume *newVp;
326
327         newVp = afs_osi_Alloc(sizeof(struct volume));
328         osi_Assert(newVp != NULL);
329
330         newVp->next = NULL;
331         afs_freeVolList = newVp;
332     }
333     tv = afs_freeVolList;
334     afs_freeVolList = tv->next;
335
336     afs_InitVolSlot(tv, NULL, volid, tcell);
337     return tv;
338
339 }                               /*afs_MemGetVolSlot */
340
341 /*!
342  * Setup a volume slot for cell:volume.
343  *
344  * Find the volume slot for the cell:volume, otherwise get
345  * and initialize a new slot.
346  *
347  * \param volid volume id
348  * \param cell  cell
349  * \return volume
350  */
351 static struct volume *
352 afs_SetupVolSlot(afs_int32 volid, struct cell *tcell)
353 {
354     struct volume *tv;
355     int i;
356
357     AFS_STATCNT(afs_SetupVolSlot);
358     ObtainWriteLock(&afs_xvolume, 108);
359     i = VHash(volid);
360     for (tv = afs_volumes[i]; tv; tv = tv->next) {
361         if (tv->volume == volid && tv->cell == tcell->cellNum) {
362             break;
363         }
364     }
365     if (!tv) {
366         tv = afs_GetVolSlot(volid, tcell);
367         if (!tv) {
368             ReleaseWriteLock(&afs_xvolume);
369             return NULL;
370         }
371         tv->next = afs_volumes[i];      /* thread into list */
372         afs_volumes[i] = tv;
373     }
374     tv->refCount++;
375     tv->states &= ~VRecheck;    /* just checked it */
376     tv->accessTime = osi_Time();
377     ReleaseWriteLock(&afs_xvolume);
378     return tv;
379 }
380
381 /*!
382  * Reset volume information for all volume structs that
383  * point to a speicific server, skipping a given volume if provided.
384  *
385  * @param[in] srvp
386  *      The server to reset volume info about
387  * @param[in] tv
388  *      The volume to skip resetting info about
389  */
390 void
391 afs_ResetVolumes(struct server *srvp, struct volume *tv)
392 {
393     int j, k;
394     struct volume *vp;
395
396     /* Find any volumes residing on this server and flush their state */
397     for (j = 0; j < NVOLS; j++) {
398         for (vp = afs_volumes[j]; vp; vp = vp->next) {
399             for (k = 0; k < AFS_MAXHOSTS; k++) {
400                 if (!srvp || (vp->serverHost[k] == srvp)) {
401                     if (tv && tv != vp) {
402                         vp->serverHost[k] = 0;
403                         afs_ResetVolumeInfo(vp);
404                     }
405                     break;
406                 }
407             }
408         }
409     }
410 }
411
412 /**
413  *   Reset volume name to volume id mapping cache.
414  * @param flags
415  */
416 void
417 afs_CheckVolumeNames(int flags)
418 {
419     afs_int32 i, j;
420     struct volume *tv;
421     unsigned int now;
422     struct vcache *tvc;
423     afs_int32 *volumeID, *cellID, vsize, nvols;
424 #ifdef AFS_DARWIN80_ENV
425     vnode_t tvp;
426 #endif
427     AFS_STATCNT(afs_CheckVolumeNames);
428
429     nvols = 0;
430     volumeID = cellID = NULL;
431     vsize = 0;
432     ObtainReadLock(&afs_xvolume);
433     if (flags & AFS_VOLCHECK_EXPIRED) {
434         /*
435          * allocate space to hold the volumeIDs and cellIDs, only if
436          * we will be invalidating the mountpoints later on
437          */
438         for (i = 0; i < NVOLS; i++)
439             for (tv = afs_volumes[i]; tv; tv = tv->next)
440                 ++vsize;
441
442         volumeID = afs_osi_Alloc(2 * vsize * sizeof(*volumeID));
443         cellID = (volumeID) ? volumeID + vsize : 0;
444     }
445
446     now = osi_Time();
447     for (i = 0; i < NVOLS; i++) {
448         for (tv = afs_volumes[i]; tv; tv = tv->next) {
449             if (flags & AFS_VOLCHECK_EXPIRED) {
450                 if (((tv->expireTime < (now + 10)) && (tv->states & VRO))
451                     || (flags & AFS_VOLCHECK_FORCE)) {
452                     afs_ResetVolumeInfo(tv);    /* also resets status */
453                     if (volumeID) {
454                         volumeID[nvols] = tv->volume;
455                         cellID[nvols] = tv->cell;
456                     }
457                     ++nvols;
458                     continue;
459                 }
460             }
461             /* ??? */
462             if (flags & (AFS_VOLCHECK_BUSY | AFS_VOLCHECK_FORCE)) {
463                 for (j = 0; j < AFS_MAXHOSTS; j++)
464                     tv->status[j] = not_busy;
465             }
466
467         }
468     }
469     ReleaseReadLock(&afs_xvolume);
470
471
472     /* next ensure all mt points are re-evaluated */
473     if (nvols || (flags & (AFS_VOLCHECK_FORCE | AFS_VOLCHECK_MTPTS))) {
474 loop:
475         ObtainReadLock(&afs_xvcache);
476         for (i = 0; i < VCSIZE; i++) {
477             for (tvc = afs_vhashT[i]; tvc; tvc = tvc->hnext) {
478
479                 /* if the volume of "mvid.target_root" of the vcache entry is
480                  * among the ones we found earlier, then we re-evaluate it.
481                  * Also, if the force bit is set or we explicitly asked to
482                  * reevaluate the mt-pts, we clean the cmvalid bit */
483
484                 if ((flags & (AFS_VOLCHECK_FORCE | AFS_VOLCHECK_MTPTS))
485                     || (tvc->mvid.target_root
486                         && inVolList(tvc->mvid.target_root, nvols, volumeID, cellID)))
487                     tvc->f.states &= ~CMValid;
488
489                 /* If the volume that this file belongs to was reset earlier,
490                  * then we should remove its callback.
491                  * Again, if forced, always do it.
492                  */
493                 if ((tvc->f.states & CRO)
494                     && (inVolList(&tvc->f.fid, nvols, volumeID, cellID)
495                         || (flags & AFS_VOLCHECK_FORCE))) {
496
497                     if (tvc->f.states & CVInit) {
498                         ReleaseReadLock(&afs_xvcache);
499                         afs_osi_Sleep(&tvc->f.states);
500                         goto loop;
501                     }
502 #ifdef AFS_DARWIN80_ENV
503                     if (tvc->f.states & CDeadVnode) {
504                         ReleaseReadLock(&afs_xvcache);
505                         afs_osi_Sleep(&tvc->f.states);
506                         goto loop;
507                     }
508                     tvp = AFSTOV(tvc);
509                     if (vnode_get(tvp))
510                         continue;
511                     if (vnode_ref(tvp)) {
512                         AFS_GUNLOCK();
513                         /* AFSTOV(tvc) may be NULL */
514                         vnode_put(tvp);
515                         AFS_GLOCK();
516                         continue;
517                     }
518 #else
519                     AFS_FAST_HOLD(tvc);
520 #endif
521                     ReleaseReadLock(&afs_xvcache);
522
523                     ObtainWriteLock(&afs_xcbhash, 485);
524                     /* LOCKXXX: We aren't holding tvc write lock? */
525                     afs_DequeueCallback(tvc);
526                     tvc->f.states &= ~CStatd;
527                     ReleaseWriteLock(&afs_xcbhash);
528                     if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
529                         osi_dnlc_purgedp(tvc);
530
531 #ifdef AFS_DARWIN80_ENV
532                     vnode_put(AFSTOV(tvc));
533                     /* our tvc ptr is still good until now */
534                     AFS_FAST_RELE(tvc);
535                     ObtainReadLock(&afs_xvcache);
536 #else
537                     ObtainReadLock(&afs_xvcache);
538
539                     /* our tvc ptr is still good until now */
540                     AFS_FAST_RELE(tvc);
541 #endif
542                 }
543             }
544         }
545         osi_dnlc_purge();       /* definitely overkill, but it's safer this way. */
546         ReleaseReadLock(&afs_xvcache);
547     }
548
549     if (volumeID)
550         afs_osi_Free(volumeID, 2 * vsize * sizeof(*volumeID));
551
552 }                               /*afs_CheckVolumeNames */
553
554
555 /**
556  * Check if volume is in the specified list.
557  * @param fid File FID.
558  * @param nvols Nomber of volumes???
559  * @param vID Array of volume IDs.
560  * @param cID Array of cache IDs.
561  * @return 1 - true, 0 - false.
562  */
563 static int
564 inVolList(struct VenusFid *fid, afs_int32 nvols, afs_int32 * vID,
565           afs_int32 * cID)
566 {
567     afs_int32 i;
568
569     /* if no arrays present, be conservative and return true */
570     if (nvols && (!vID || !cID))
571         return 1;
572
573     for (i = 0; i < nvols; ++i) {
574         if (fid->Fid.Volume == vID[i] && fid->Cell == cID[i])
575             return 1;
576     }
577     return 0;
578 }
579
580
581 /* afs_PutVolume is now a macro in afs.h */
582
583
584 /**
585  *    Return volume struct if we have it cached and it's up-to-date.
586  *  Environment: Must be called with afs_xvolume unlocked.
587  *  @param afid Volume FID.
588  *  @param locktype
589  *  @return Volume or NULL if no result.
590  */
591 struct volume *
592 afs_FindVolume(struct VenusFid *afid, afs_int32 locktype)
593 {
594     struct volume *tv;
595     afs_int32 i;
596
597     if (afid == NULL)
598         return NULL;
599
600     i = VHash(afid->Fid.Volume);
601     ObtainWriteLock(&afs_xvolume, 106);
602     for (tv = afs_volumes[i]; tv; tv = tv->next) {
603         if (tv->volume == afid->Fid.Volume && tv->cell == afid->Cell
604             && (tv->states & VRecheck) == 0) {
605             tv->refCount++;
606             break;
607         }
608     }
609     ReleaseWriteLock(&afs_xvolume);
610     return tv;                  /* NULL if we didn't find it */
611 }                               /*afs_FindVolume */
612
613
614
615 /**
616  *   Note that areq may be null, in which case we don't bother to set any
617  * request status information.
618  * @param afid Volume FID.
619  * @param areq Request type.
620  * @param locktype Lock to be used.
621  * @return Volume or NULL if no result.
622  */
623 struct volume *
624 afs_GetVolume(struct VenusFid *afid, struct vrequest *areq,
625               afs_int32 locktype)
626 {
627     struct volume *tv;
628     char *bp, tbuf[CVBS];
629     AFS_STATCNT(afs_GetVolume);
630
631     tv = afs_FindVolume(afid, locktype);
632     if (!tv) {
633         /* Do a dynroot check and add dynroot volume if found. */
634         if (afs_IsDynrootAnyFid(afid)) {
635             tv = afs_NewDynrootVolume(afid);
636         } else {
637             bp = afs_cv2string(&tbuf[CVBS], afid->Fid.Volume);
638             tv = afs_NewVolumeByName(bp, afid->Cell, 0, areq, locktype);
639         }
640     }
641     return tv;
642 }                               /*afs_GetVolume */
643
644
645
646 /**
647  *
648  * @param volid Volume ID. If it's 0, get it from the name.
649  * @param aname Volume name.
650  * @param ve Volume entry.
651  * @param tcell The cell containing this volume.
652  * @param agood
653  * @param type Type of volume.
654  * @param areq Request.
655  * @return Volume or NULL if failure.
656  */
657 static struct volume *
658 afs_SetupVolume(afs_int32 volid, char *aname, void *ve, struct cell *tcell,
659                 afs_int32 agood, afs_int32 type, struct vrequest *areq)
660 {
661     struct volume *tv;
662     struct vldbentry *ove = (struct vldbentry *)ve;
663     struct nvldbentry *nve = (struct nvldbentry *)ve;
664     struct uvldbentry *uve = (struct uvldbentry *)ve;
665
666     int whichType;              /* which type of volume to look for */
667     int i;
668
669     if (!volid) {
670         int len;
671         /* special hint from file server to use vlserver */
672         len = strlen(aname);
673         if (len >= 8 && strcmp(aname + len - 7, ".backup") == 0)
674             whichType = BACKVOL;
675         else if (len >= 10 && strcmp(aname + len - 9, ".readonly") == 0)
676             whichType = ROVOL;
677         else
678             whichType = RWVOL;
679
680         /* figure out which one we're really interested in (a set is returned) */
681         volid = afs_vtoi(aname);
682         if (volid == 0) {
683             if (type == 2) {
684                 volid = uve->volumeId[whichType];
685             } else if (type == 1) {
686                 volid = nve->volumeId[whichType];
687             } else {
688                 volid = ove->volumeId[whichType];
689             }
690         } /* end of if (volid == 0) */
691     } /* end of if (!volid) */
692
693     tv = afs_SetupVolSlot(volid, tcell);
694     if (!tv) {
695         return NULL;
696     }
697
698     if (type == 2) {
699         LockAndInstallUVolumeEntry(tv, uve, tcell->cellNum, tcell, areq);
700     } else if (type == 1)
701         LockAndInstallNVolumeEntry(tv, nve, tcell->cellNum);
702     else
703         LockAndInstallVolumeEntry(tv, ove, tcell->cellNum);
704     if (agood) {
705         if (!tv->name) {
706             tv->name = afs_osi_Alloc(strlen(aname) + 1);
707             osi_Assert(tv->name != NULL);
708             strcpy(tv->name, aname);
709         }
710     }
711     for (i = 0; i < NMAXNSERVERS; i++) {
712         tv->status[i] = not_busy;
713     }
714     ReleaseWriteLock(&tv->lock);
715     return tv;
716 }
717
718
719 /**
720  * Seek volume by it's name and attributes.
721  * If volume not found, try to add one.
722  * @param aname Volume name.
723  * @param acell Cell
724  * @param agood
725  * @param areq
726  * @param locktype Type of lock to be used.
727  * @return
728  */
729 struct volume *
730 afs_GetVolumeByName(char *aname, afs_int32 acell, int agood,
731                     struct vrequest *areq, afs_int32 locktype)
732 {
733     afs_int32 i;
734     struct volume *tv;
735
736     AFS_STATCNT(afs_GetVolumeByName);
737     ObtainWriteLock(&afs_xvolume, 112);
738     for (i = 0; i < NVOLS; i++) {
739         for (tv = afs_volumes[i]; tv; tv = tv->next) {
740             if (tv->name && !strcmp(aname, tv->name) && tv->cell == acell
741                 && (tv->states & VRecheck) == 0) {
742                 tv->refCount++;
743                 ReleaseWriteLock(&afs_xvolume);
744                 return tv;
745             }
746         }
747     }
748
749     ReleaseWriteLock(&afs_xvolume);
750
751     if (AFS_IS_DISCONNECTED)
752         return NULL;
753
754     tv = afs_NewVolumeByName(aname, acell, agood, areq, locktype);
755     return (tv);
756 }
757
758 /**
759  *   Init a new dynroot volume.
760  * @param Volume FID.
761  * @return Volume or NULL if not found.
762  */
763 static struct volume *
764 afs_NewDynrootVolume(struct VenusFid *fid)
765 {
766     struct cell *tcell;
767     struct volume *tv;
768     struct vldbentry *tve;
769     char *bp, tbuf[CVBS];
770
771     tcell = afs_GetCell(fid->Cell, READ_LOCK);
772     if (!tcell)
773         return NULL;
774     tve = afs_osi_Alloc(sizeof(*tve));
775     osi_Assert(tve != NULL);
776     if (!(tcell->states & CHasVolRef))
777         tcell->states |= CHasVolRef;
778
779     bp = afs_cv2string(&tbuf[CVBS], fid->Fid.Volume);
780     memset(tve, 0, sizeof(*tve));
781     strcpy(tve->name, "local-dynroot");
782     tve->volumeId[ROVOL] = fid->Fid.Volume;
783     tve->flags = VLF_ROEXISTS;
784
785     tv = afs_SetupVolume(0, bp, tve, tcell, 0, 0, 0);
786     afs_PutCell(tcell, READ_LOCK);
787     afs_osi_Free(tve, sizeof(*tve));
788     return tv;
789 }
790
791 int lastnvcode;
792
793 /**
794  * @param aname Volume name.
795  * @param acell Cell id.
796  * @param agood
797  * @param areq Request type.
798  * @param locktype Type of lock to be used.
799  * @return Volume or NULL if failure.
800  */
801 static struct volume *
802 afs_NewVolumeByName(char *aname, afs_int32 acell, int agood,
803                     struct vrequest *areq, afs_int32 locktype)
804 {
805     afs_int32 code, type = 0;
806     struct volume *tv, *tv1;
807     struct vldbentry *tve;
808     struct nvldbentry *ntve;
809     struct uvldbentry *utve;
810     struct cell *tcell;
811     char *tbuffer, *ve;
812     struct afs_conn *tconn;
813     struct vrequest *treq = NULL;
814     struct rx_connection *rxconn;
815
816     if (strlen(aname) > VL_MAXNAMELEN)  /* Invalid volume name */
817         return NULL;
818
819     tcell = afs_GetCell(acell, READ_LOCK);
820     if (!tcell) {
821         return NULL;
822     }
823
824     code = afs_CreateReq(&treq, afs_osi_credp); /* *must* be unauth for vldb */
825     if (code) {
826         return NULL;
827     }
828
829     /* allow null request if we don't care about ENODEV/ETIMEDOUT distinction */
830     if (!areq)
831         areq = treq;
832
833
834     afs_Trace2(afs_iclSetp, CM_TRACE_GETVOL, ICL_TYPE_STRING, aname,
835                ICL_TYPE_POINTER, aname);
836     tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
837     tve = (struct vldbentry *)(tbuffer + 1024);
838     ntve = (struct nvldbentry *)tve;
839     utve = (struct uvldbentry *)tve;
840
841     do {
842         tconn =
843             afs_ConnByMHosts(tcell->cellHosts, tcell->vlport, tcell->cellNum,
844                              treq, SHARED_LOCK, 0, &rxconn);
845         if (tconn) {
846             if (tconn->parent->srvr->server->flags & SNO_LHOSTS) {
847                 type = 0;
848                 RX_AFS_GUNLOCK();
849                 code = VL_GetEntryByNameO(rxconn, aname, tve);
850                 RX_AFS_GLOCK();
851             } else if (tconn->parent->srvr->server->flags & SYES_LHOSTS) {
852                 type = 1;
853                 RX_AFS_GUNLOCK();
854                 code = VL_GetEntryByNameN(rxconn, aname, ntve);
855                 RX_AFS_GLOCK();
856             } else {
857                 type = 2;
858                 RX_AFS_GUNLOCK();
859                 code = VL_GetEntryByNameU(rxconn, aname, utve);
860                 RX_AFS_GLOCK();
861                 if (!(tconn->parent->srvr->server->flags & SVLSRV_UUID)) {
862                     if (code == RXGEN_OPCODE) {
863                         type = 1;
864                         RX_AFS_GUNLOCK();
865                         code = VL_GetEntryByNameN(rxconn, aname, ntve);
866                         RX_AFS_GLOCK();
867                         if (code == RXGEN_OPCODE) {
868                             type = 0;
869                             tconn->parent->srvr->server->flags |= SNO_LHOSTS;
870                             RX_AFS_GUNLOCK();
871                             code = VL_GetEntryByNameO(rxconn, aname, tve);
872                             RX_AFS_GLOCK();
873                         } else if (!code)
874                             tconn->parent->srvr->server->flags |= SYES_LHOSTS;
875                     } else if (!code)
876                         tconn->parent->srvr->server->flags |= SVLSRV_UUID;
877                 }
878                 lastnvcode = code;
879             }
880         } else
881             code = -1;
882     } while (afs_Analyze(tconn, rxconn, code, NULL, treq, -1,   /* no op code for this */
883                          SHARED_LOCK, tcell));
884
885     if (code) {
886         /* If the client has yet to contact this cell and contact failed due
887          * to network errors, mark the VLDB servers as back up.
888          * That the client tried and failed can be determined from the
889          * fact that there was a downtime incident, but CHasVolRef is not set.
890          */
891     /* RT 48959 - unclear if this should really go */
892 #if 0
893         if (areq->networkError && !(tcell->states & CHasVolRef)) {
894             int i;
895             struct server *sp;
896             struct srvAddr *sap;
897             for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
898                 if ((sp = tcell->cellHosts[i]) == NULL)
899                     break;
900                 for (sap = sp->addr; sap; sap = sap->next_sa)
901                     afs_MarkServerUpOrDown(sap, 0);
902             }
903         }
904 #endif
905         afs_CopyError(treq, areq);
906         osi_FreeLargeSpace(tbuffer);
907         afs_PutCell(tcell, READ_LOCK);
908         afs_DestroyReq(treq);
909         return NULL;
910     }
911     /*
912      * Check to see if this cell has not yet referenced a volume.  If
913      * it hasn't, it's just about to change its status, and we need to mark
914      * this fact down. Note that it is remotely possible that afs_SetupVolume
915      * could fail and we would still not have a volume reference.
916      */
917     if (!(tcell->states & CHasVolRef)) {
918         tcell->states |= CHasVolRef;
919         afs_stats_cmperf.numCellsContacted++;
920     }
921     /*First time a volume in this cell has been referenced */
922     if (type == 2)
923         ve = (char *)utve;
924     else if (type == 1)
925         ve = (char *)ntve;
926     else
927         ve = (char *)tve;
928     tv = afs_SetupVolume(0, aname, ve, tcell, agood, type, treq);
929     if ((agood == 3) && tv && tv->backVol) {
930         /*
931          * This means that very soon we'll ask for the BK volume so
932          * we'll prefetch it (well we did already.)
933          */
934         tv1 =
935             afs_SetupVolume(tv->backVol, (char *)0, ve, tcell, 0, type, treq);
936         if (tv1) {
937             tv1->refCount--;
938         }
939     }
940     if ((agood >= 2) && tv && tv->roVol) {
941         /*
942          * This means that very soon we'll ask for the RO volume so
943          * we'll prefetch it (well we did already.)
944          */
945         tv1 = afs_SetupVolume(tv->roVol, NULL, ve, tcell, 0, type, treq);
946         if (tv1) {
947             tv1->refCount--;
948         }
949     }
950     osi_FreeLargeSpace(tbuffer);
951     afs_PutCell(tcell, READ_LOCK);
952     afs_DestroyReq(treq);
953     return tv;
954
955 }                               /*afs_NewVolumeByName */
956
957
958
959 /**
960  *   Call this with the volume structure locked; used for new-style vldb requests.
961  * @param av Volume
962  * @param ve
963  * @param acell
964  */
965 void
966 LockAndInstallVolumeEntry(struct volume *av, struct vldbentry *ve, int acell)
967 {
968     struct server *ts;
969     struct cell *cellp;
970     int i, j;
971     afs_int32 mask;
972     afs_uint32 temp;
973     char types = 0;
974     struct server *serverHost[AFS_MAXHOSTS];
975
976     AFS_STATCNT(InstallVolumeEntry);
977
978     memset(serverHost, 0, sizeof(serverHost));
979
980     /* Determine the type of volume we want */
981     if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) {
982         mask = VLSF_RWVOL;
983     } else if ((ve->flags & VLF_ROEXISTS)
984                && (av->volume == ve->volumeId[ROVOL])) {
985         mask = VLSF_ROVOL;
986         types |= VRO;
987     } else if ((ve->flags & VLF_BACKEXISTS)
988                && (av->volume == ve->volumeId[BACKVOL])) {
989         /* backup always is on the same volume as parent */
990         mask = VLSF_RWVOL;
991         types |= (VRO | VBackup);
992     } else {
993         mask = 0;               /* Can't find volume in vldb entry */
994     }
995
996     cellp = afs_GetCell(acell, 0);
997
998     /* Step through the VLDB entry making sure each server listed is there */
999     for (i = 0, j = 0; i < ve->nServers; i++) {
1000         if (((ve->serverFlags[i] & mask) == 0)
1001             || (ve->serverFlags[i] & VLSF_DONTUSE)) {
1002             continue;           /* wrong volume or  don't use this volume */
1003         }
1004
1005         temp = htonl(ve->serverNumber[i]);
1006         ts = afs_GetServer(&temp, 1, acell, cellp->fsport, WRITE_LOCK,
1007                            (afsUUID *) 0, 0, av);
1008         serverHost[j] = ts;
1009
1010         /*
1011          * The cell field could be 0 if the server entry was created
1012          * first with the 'fs setserverprefs' call which doesn't set
1013          * the cell field. Thus if the afs_GetServer call above
1014          * follows later on it will find the server entry thus it will
1015          * simply return without setting any fields, so we set the
1016          * field ourselves below.
1017          */
1018         if (!ts->cell)
1019             ts->cell = cellp;
1020         afs_PutServer(ts, WRITE_LOCK);
1021         j++;
1022     }
1023
1024     ObtainWriteLock(&av->lock, 109);
1025
1026     memcpy(av->serverHost, serverHost, sizeof(serverHost));
1027
1028     /* from above */
1029     av->states |= types;
1030
1031     /* fill in volume types */
1032     av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
1033     av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
1034     av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
1035
1036     if (ve->flags & VLF_DFSFILESET)
1037         av->states |= VForeign;
1038
1039     afs_SortServers(av->serverHost, AFS_MAXHOSTS);
1040 }                               /*InstallVolumeEntry */
1041
1042
1043 void
1044 LockAndInstallNVolumeEntry(struct volume *av, struct nvldbentry *ve, int acell)
1045 {
1046     struct server *ts;
1047     struct cell *cellp;
1048     int i, j;
1049     afs_int32 mask;
1050     afs_uint32 temp;
1051     char types = 0;
1052     struct server *serverHost[AFS_MAXHOSTS];
1053
1054     AFS_STATCNT(InstallVolumeEntry);
1055
1056     memset(serverHost, 0, sizeof(serverHost));
1057
1058     /* Determine type of volume we want */
1059     if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) {
1060         mask = VLSF_RWVOL;
1061     } else if ((ve->flags & VLF_ROEXISTS)
1062                && (av->volume == ve->volumeId[ROVOL])) {
1063         mask = VLSF_ROVOL;
1064         types |= VRO;
1065     } else if ((ve->flags & VLF_BACKEXISTS)
1066                && (av->volume == ve->volumeId[BACKVOL])) {
1067         /* backup always is on the same volume as parent */
1068         mask = VLSF_RWVOL;
1069         types |= (VRO | VBackup);
1070     } else {
1071         mask = 0;               /* Can't find volume in vldb entry */
1072     }
1073
1074     cellp = afs_GetCell(acell, 0);
1075
1076     /* Step through the VLDB entry making sure each server listed is there */
1077     for (i = 0, j = 0; i < ve->nServers; i++) {
1078         if (((ve->serverFlags[i] & mask) == 0)
1079             || (ve->serverFlags[i] & VLSF_DONTUSE)) {
1080             continue;           /* wrong volume or don't use this volume */
1081         }
1082
1083         temp = htonl(ve->serverNumber[i]);
1084         ts = afs_GetServer(&temp, 1, acell, cellp->fsport, WRITE_LOCK,
1085                            (afsUUID *) 0, 0, av);
1086         serverHost[j] = ts;
1087         /*
1088          * The cell field could be 0 if the server entry was created
1089          * first with the 'fs setserverprefs' call which doesn't set
1090          * the cell field. Thus if the afs_GetServer call above
1091          * follows later on it will find the server entry thus it will
1092          * simply return without setting any fields, so we set the
1093          * field ourselves below.
1094          */
1095         if (!ts->cell)
1096             ts->cell = cellp;
1097         afs_PutServer(ts, WRITE_LOCK);
1098         j++;
1099     }
1100
1101     ObtainWriteLock(&av->lock, 110);
1102
1103     memcpy(av->serverHost, serverHost, sizeof(serverHost));
1104
1105     /* from above */
1106     av->states |= types;
1107
1108     /* fill in volume types */
1109     av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
1110     av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
1111     av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
1112
1113     if (ve->flags & VLF_DFSFILESET)
1114         av->states |= VForeign;
1115
1116     afs_SortServers(av->serverHost, AFS_MAXHOSTS);
1117 }                               /*InstallNVolumeEntry */
1118
1119
1120 void
1121 LockAndInstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell,
1122                            struct cell *tcell, struct vrequest *areq)
1123 {
1124     struct server *ts;
1125     struct afs_conn *tconn;
1126     struct cell *cellp;
1127     int i, j;
1128     afs_uint32 serverid;
1129     afs_int32 mask;
1130     int k;
1131     char type = 0;
1132     struct server *serverHost[AFS_MAXHOSTS];
1133
1134     AFS_STATCNT(InstallVolumeEntry);
1135
1136     memset(serverHost, 0, sizeof(serverHost));
1137
1138     /* Determine type of volume we want */
1139     if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) {
1140         mask = VLSF_RWVOL;
1141     } else if ((ve->flags & VLF_ROEXISTS)
1142                && av->volume == ve->volumeId[ROVOL]) {
1143         mask = VLSF_ROVOL;
1144         type |= VRO;
1145     } else if ((ve->flags & VLF_BACKEXISTS)
1146                && (av->volume == ve->volumeId[BACKVOL])) {
1147         /* backup always is on the same volume as parent */
1148         mask = VLSF_RWVOL;
1149         type |= (VRO | VBackup);
1150     } else {
1151         mask = 0;               /* Can't find volume in vldb entry */
1152     }
1153
1154     cellp = afs_GetCell(acell, 0);
1155
1156     /* Gather the list of servers the VLDB says the volume is on
1157      * and initialize the ve->serverHost[] array. If a server struct
1158      * is not found, then get the list of addresses for the
1159      * server, VL_GetAddrsU(), and create a server struct, afs_GetServer().
1160      */
1161     for (i = 0, j = 0; i < ve->nServers; i++) {
1162         if (((ve->serverFlags[i] & mask) == 0)
1163             || (ve->serverFlags[i] & VLSF_DONTUSE)) {
1164             continue;           /* wrong volume don't use this volume */
1165         }
1166
1167         if (!(ve->serverFlags[i] & VLSF_UUID)) {
1168             /* The server has no uuid */
1169             serverid = htonl(ve->serverNumber[i].time_low);
1170             ts = afs_GetServer(&serverid, 1, acell, cellp->fsport,
1171                                WRITE_LOCK, (afsUUID *) 0, 0, av);
1172         } else {
1173             ts = afs_FindServer(0, cellp->fsport, &ve->serverNumber[i], 0);
1174             if (ts && (ts->sr_addr_uniquifier == ve->serverUnique[i])
1175                 && ts->addr) {
1176                 /* uuid, uniquifier, and portal are the same */
1177             } else {
1178                 afs_uint32 *addrp, code;
1179                 afs_int32 nentries, unique;
1180                 bulkaddrs addrs;
1181                 ListAddrByAttributes attrs;
1182                 afsUUID uuid;
1183                 struct rx_connection *rxconn;
1184
1185                 memset(&attrs, 0, sizeof(attrs));
1186                 attrs.Mask = VLADDR_UUID;
1187                 attrs.uuid = ve->serverNumber[i];
1188                 memset(&uuid, 0, sizeof(uuid));
1189                 memset(&addrs, 0, sizeof(addrs));
1190                 do {
1191                     tconn =
1192                         afs_ConnByMHosts(tcell->cellHosts, tcell->vlport,
1193                                          tcell->cellNum, areq, SHARED_LOCK,
1194                                          0, &rxconn);
1195                     if (tconn) {
1196                         RX_AFS_GUNLOCK();
1197                         code =
1198                             VL_GetAddrsU(rxconn, &attrs, &uuid, &unique,
1199                                          &nentries, &addrs);
1200                         RX_AFS_GLOCK();
1201                     } else {
1202                         code = -1;
1203                     }
1204
1205                     /* Handle corrupt VLDB (defect 7393) */
1206                     if (code == 0 && nentries == 0)
1207                         code = VL_NOENT;
1208
1209                 } while (afs_Analyze
1210                          (tconn, rxconn, code, NULL, areq, -1, SHARED_LOCK, tcell));
1211                 if (code) {
1212                     /* Better handing of such failures; for now we'll simply retry this call */
1213                     areq->volumeError = 1;
1214                     return;
1215                 }
1216
1217                 addrp = addrs.bulkaddrs_val;
1218                 for (k = 0; k < nentries; k++) {
1219                     addrp[k] = htonl(addrp[k]);
1220                 }
1221                 ts = afs_GetServer(addrp, nentries, acell,
1222                                    cellp->fsport, WRITE_LOCK,
1223                                    &ve->serverNumber[i],
1224                                    ve->serverUnique[i], av);
1225                 xdr_free((xdrproc_t) xdr_bulkaddrs, &addrs);
1226             }
1227         }
1228         serverHost[j] = ts;
1229
1230         /* The cell field could be 0 if the server entry was created
1231          * first with the 'fs setserverprefs' call which doesn't set
1232          * the cell field. Thus if the afs_GetServer call above
1233          * follows later on it will find the server entry thus it will
1234          * simply return without setting any fields, so we set the
1235          * field ourselves below.
1236          */
1237         if (!ts->cell)
1238             ts->cell = cellp;
1239         afs_PutServer(ts, WRITE_LOCK);
1240         j++;
1241     }
1242
1243     ObtainWriteLock(&av->lock, 111);
1244
1245     memcpy(av->serverHost, serverHost, sizeof(serverHost));
1246
1247     /* from above */
1248     av->states |= type;
1249
1250     /* fill in volume types */
1251     av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
1252     av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
1253     av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
1254
1255     if (ve->flags & VLF_DFSFILESET)
1256         av->states |= VForeign;
1257
1258     afs_SortServers(av->serverHost, AFS_MAXHOSTS);
1259 }                               /*InstallVolumeEntry */
1260
1261
1262 /**
1263  *   Reset volume info for the specified volume strecture. Mark volume
1264  * to be rechecked next time.
1265  * @param tv
1266  */
1267 void
1268 afs_ResetVolumeInfo(struct volume *tv)
1269 {
1270     int i;
1271
1272     AFS_STATCNT(afs_ResetVolumeInfo);
1273     ObtainWriteLock(&tv->lock, 117);
1274     tv->states |= VRecheck;
1275
1276     /* the hard-mount code in afs_Analyze may not be able to reset this flag
1277      * when VRecheck is set, so clear it here to ensure it gets cleared. */
1278     tv->states &= ~VHardMount;
1279
1280     for (i = 0; i < AFS_MAXHOSTS; i++)
1281         tv->status[i] = not_busy;
1282     if (tv->name) {
1283         afs_osi_Free(tv->name, strlen(tv->name) + 1);
1284         tv->name = NULL;
1285     }
1286     ReleaseWriteLock(&tv->lock);
1287 }