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