libafs: do not allow NULL creds for afs_CreateReq
[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 = NULL;
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     code = afs_CreateReq(&treq, afs_osi_credp); /* *must* be unauth for vldb */
811     if (code) {
812         return NULL;
813     }
814
815     /* allow null request if we don't care about ENODEV/ETIMEDOUT distinction */
816     if (!areq)
817         areq = treq;
818
819
820     afs_Trace2(afs_iclSetp, CM_TRACE_GETVOL, ICL_TYPE_STRING, aname,
821                ICL_TYPE_POINTER, aname);
822     tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
823     tve = (struct vldbentry *)(tbuffer + 1024);
824     ntve = (struct nvldbentry *)tve;
825     utve = (struct uvldbentry *)tve;
826
827     do {
828         tconn =
829             afs_ConnByMHosts(tcell->cellHosts, tcell->vlport, tcell->cellNum,
830                              treq, SHARED_LOCK, 0, &rxconn);
831         if (tconn) {
832             if (tconn->parent->srvr->server->flags & SNO_LHOSTS) {
833                 type = 0;
834                 RX_AFS_GUNLOCK();
835                 code = VL_GetEntryByNameO(rxconn, aname, tve);
836                 RX_AFS_GLOCK();
837             } else if (tconn->parent->srvr->server->flags & SYES_LHOSTS) {
838                 type = 1;
839                 RX_AFS_GUNLOCK();
840                 code = VL_GetEntryByNameN(rxconn, aname, ntve);
841                 RX_AFS_GLOCK();
842             } else {
843                 type = 2;
844                 RX_AFS_GUNLOCK();
845                 code = VL_GetEntryByNameU(rxconn, aname, utve);
846                 RX_AFS_GLOCK();
847                 if (!(tconn->parent->srvr->server->flags & SVLSRV_UUID)) {
848                     if (code == RXGEN_OPCODE) {
849                         type = 1;
850                         RX_AFS_GUNLOCK();
851                         code = VL_GetEntryByNameN(rxconn, aname, ntve);
852                         RX_AFS_GLOCK();
853                         if (code == RXGEN_OPCODE) {
854                             type = 0;
855                             tconn->parent->srvr->server->flags |= SNO_LHOSTS;
856                             RX_AFS_GUNLOCK();
857                             code = VL_GetEntryByNameO(rxconn, aname, tve);
858                             RX_AFS_GLOCK();
859                         } else if (!code)
860                             tconn->parent->srvr->server->flags |= SYES_LHOSTS;
861                     } else if (!code)
862                         tconn->parent->srvr->server->flags |= SVLSRV_UUID;
863                 }
864                 lastnvcode = code;
865             }
866         } else
867             code = -1;
868     } while (afs_Analyze(tconn, rxconn, code, NULL, treq, -1,   /* no op code for this */
869                          SHARED_LOCK, tcell));
870
871     if (code) {
872         /* If the client has yet to contact this cell and contact failed due
873          * to network errors, mark the VLDB servers as back up.
874          * That the client tried and failed can be determined from the
875          * fact that there was a downtime incident, but CHasVolRef is not set.
876          */
877     /* RT 48959 - unclear if this should really go */
878 #if 0
879         if (areq->networkError && !(tcell->states & CHasVolRef)) {
880             int i;
881             struct server *sp;
882             struct srvAddr *sap;
883             for (i = 0; i < AFS_MAXCELLHOSTS; i++) {
884                 if ((sp = tcell->cellHosts[i]) == NULL)
885                     break;
886                 for (sap = sp->addr; sap; sap = sap->next_sa)
887                     afs_MarkServerUpOrDown(sap, 0);
888             }
889         }
890 #endif
891         afs_CopyError(treq, areq);
892         osi_FreeLargeSpace(tbuffer);
893         afs_PutCell(tcell, READ_LOCK);
894         afs_DestroyReq(treq);
895         return NULL;
896     }
897     /*
898      * Check to see if this cell has not yet referenced a volume.  If
899      * it hasn't, it's just about to change its status, and we need to mark
900      * this fact down. Note that it is remotely possible that afs_SetupVolume
901      * could fail and we would still not have a volume reference.
902      */
903     if (!(tcell->states & CHasVolRef)) {
904         tcell->states |= CHasVolRef;
905         afs_stats_cmperf.numCellsContacted++;
906     }
907     /*First time a volume in this cell has been referenced */
908     if (type == 2)
909         ve = (char *)utve;
910     else if (type == 1)
911         ve = (char *)ntve;
912     else
913         ve = (char *)tve;
914     tv = afs_SetupVolume(0, aname, ve, tcell, agood, type, treq);
915     if ((agood == 3) && tv && tv->backVol) {
916         /*
917          * This means that very soon we'll ask for the BK volume so
918          * we'll prefetch it (well we did already.)
919          */
920         tv1 =
921             afs_SetupVolume(tv->backVol, (char *)0, ve, tcell, 0, type, treq);
922         if (tv1) {
923             tv1->refCount--;
924         }
925     }
926     if ((agood >= 2) && tv && tv->roVol) {
927         /*
928          * This means that very soon we'll ask for the RO volume so
929          * we'll prefetch it (well we did already.)
930          */
931         tv1 = afs_SetupVolume(tv->roVol, NULL, ve, tcell, 0, type, treq);
932         if (tv1) {
933             tv1->refCount--;
934         }
935     }
936     osi_FreeLargeSpace(tbuffer);
937     afs_PutCell(tcell, READ_LOCK);
938     afs_DestroyReq(treq);
939     return tv;
940
941 }                               /*afs_NewVolumeByName */
942
943
944
945 /**
946  *   Call this with the volume structure locked; used for new-style vldb requests.
947  * @param av Volume
948  * @param ve
949  * @param acell
950  */
951 void
952 LockAndInstallVolumeEntry(struct volume *av, struct vldbentry *ve, int acell)
953 {
954     struct server *ts;
955     struct cell *cellp;
956     int i, j;
957     afs_int32 mask;
958     afs_uint32 temp;
959     char types = 0;
960     struct server *serverHost[AFS_MAXHOSTS];
961
962     AFS_STATCNT(InstallVolumeEntry);
963
964     memset(serverHost, 0, sizeof(serverHost));
965
966     /* Determine the type of volume we want */
967     if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) {
968         mask = VLSF_RWVOL;
969     } else if ((ve->flags & VLF_ROEXISTS)
970                && (av->volume == ve->volumeId[ROVOL])) {
971         mask = VLSF_ROVOL;
972         types |= VRO;
973     } else if ((ve->flags & VLF_BACKEXISTS)
974                && (av->volume == ve->volumeId[BACKVOL])) {
975         /* backup always is on the same volume as parent */
976         mask = VLSF_RWVOL;
977         types |= (VRO | VBackup);
978     } else {
979         mask = 0;               /* Can't find volume in vldb entry */
980     }
981
982     cellp = afs_GetCell(acell, 0);
983
984     /* Step through the VLDB entry making sure each server listed is there */
985     for (i = 0, j = 0; i < ve->nServers; i++) {
986         if (((ve->serverFlags[i] & mask) == 0)
987             || (ve->serverFlags[i] & VLSF_DONTUSE)) {
988             continue;           /* wrong volume or  don't use this volume */
989         }
990
991         temp = htonl(ve->serverNumber[i]);
992         ts = afs_GetServer(&temp, 1, acell, cellp->fsport, WRITE_LOCK,
993                            (afsUUID *) 0, 0, av);
994         serverHost[j] = ts;
995
996         /*
997          * The cell field could be 0 if the server entry was created
998          * first with the 'fs setserverprefs' call which doesn't set
999          * the cell field. Thus if the afs_GetServer call above
1000          * follows later on it will find the server entry thus it will
1001          * simply return without setting any fields, so we set the
1002          * field ourselves below.
1003          */
1004         if (!ts->cell)
1005             ts->cell = cellp;
1006         afs_PutServer(ts, WRITE_LOCK);
1007         j++;
1008     }
1009
1010     ObtainWriteLock(&av->lock, 109);
1011
1012     memcpy(av->serverHost, serverHost, sizeof(serverHost));
1013
1014     /* from above */
1015     av->states |= types;
1016
1017     /* fill in volume types */
1018     av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
1019     av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
1020     av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
1021
1022     if (ve->flags & VLF_DFSFILESET)
1023         av->states |= VForeign;
1024
1025     afs_SortServers(av->serverHost, AFS_MAXHOSTS);
1026 }                               /*InstallVolumeEntry */
1027
1028
1029 void
1030 LockAndInstallNVolumeEntry(struct volume *av, struct nvldbentry *ve, int acell)
1031 {
1032     struct server *ts;
1033     struct cell *cellp;
1034     int i, j;
1035     afs_int32 mask;
1036     afs_uint32 temp;
1037     char types = 0;
1038     struct server *serverHost[AFS_MAXHOSTS];
1039
1040     AFS_STATCNT(InstallVolumeEntry);
1041
1042     memset(serverHost, 0, sizeof(serverHost));
1043
1044     /* Determine type of volume we want */
1045     if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) {
1046         mask = VLSF_RWVOL;
1047     } else if ((ve->flags & VLF_ROEXISTS)
1048                && (av->volume == ve->volumeId[ROVOL])) {
1049         mask = VLSF_ROVOL;
1050         types |= VRO;
1051     } else if ((ve->flags & VLF_BACKEXISTS)
1052                && (av->volume == ve->volumeId[BACKVOL])) {
1053         /* backup always is on the same volume as parent */
1054         mask = VLSF_RWVOL;
1055         types |= (VRO | VBackup);
1056     } else {
1057         mask = 0;               /* Can't find volume in vldb entry */
1058     }
1059
1060     cellp = afs_GetCell(acell, 0);
1061
1062     /* Step through the VLDB entry making sure each server listed is there */
1063     for (i = 0, j = 0; i < ve->nServers; i++) {
1064         if (((ve->serverFlags[i] & mask) == 0)
1065             || (ve->serverFlags[i] & VLSF_DONTUSE)) {
1066             continue;           /* wrong volume or don't use this volume */
1067         }
1068
1069         temp = htonl(ve->serverNumber[i]);
1070         ts = afs_GetServer(&temp, 1, acell, cellp->fsport, WRITE_LOCK,
1071                            (afsUUID *) 0, 0, av);
1072         serverHost[j] = ts;
1073         /*
1074          * The cell field could be 0 if the server entry was created
1075          * first with the 'fs setserverprefs' call which doesn't set
1076          * the cell field. Thus if the afs_GetServer call above
1077          * follows later on it will find the server entry thus it will
1078          * simply return without setting any fields, so we set the
1079          * field ourselves below.
1080          */
1081         if (!ts->cell)
1082             ts->cell = cellp;
1083         afs_PutServer(ts, WRITE_LOCK);
1084         j++;
1085     }
1086
1087     ObtainWriteLock(&av->lock, 110);
1088
1089     memcpy(av->serverHost, serverHost, sizeof(serverHost));
1090
1091     /* from above */
1092     av->states |= types;
1093
1094     /* fill in volume types */
1095     av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
1096     av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
1097     av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
1098
1099     if (ve->flags & VLF_DFSFILESET)
1100         av->states |= VForeign;
1101
1102     afs_SortServers(av->serverHost, AFS_MAXHOSTS);
1103 }                               /*InstallNVolumeEntry */
1104
1105
1106 void
1107 LockAndInstallUVolumeEntry(struct volume *av, struct uvldbentry *ve, int acell,
1108                            struct cell *tcell, struct vrequest *areq)
1109 {
1110     struct server *ts;
1111     struct afs_conn *tconn;
1112     struct cell *cellp;
1113     int i, j;
1114     afs_uint32 serverid;
1115     afs_int32 mask;
1116     int k;
1117     char type = 0;
1118     struct server *serverHost[AFS_MAXHOSTS];
1119
1120     AFS_STATCNT(InstallVolumeEntry);
1121
1122     memset(serverHost, 0, sizeof(serverHost));
1123
1124     /* Determine type of volume we want */
1125     if ((ve->flags & VLF_RWEXISTS) && (av->volume == ve->volumeId[RWVOL])) {
1126         mask = VLSF_RWVOL;
1127     } else if ((ve->flags & VLF_ROEXISTS)
1128                && av->volume == ve->volumeId[ROVOL]) {
1129         mask = VLSF_ROVOL;
1130         type |= VRO;
1131     } else if ((ve->flags & VLF_BACKEXISTS)
1132                && (av->volume == ve->volumeId[BACKVOL])) {
1133         /* backup always is on the same volume as parent */
1134         mask = VLSF_RWVOL;
1135         type |= (VRO | VBackup);
1136     } else {
1137         mask = 0;               /* Can't find volume in vldb entry */
1138     }
1139
1140     cellp = afs_GetCell(acell, 0);
1141
1142     /* Gather the list of servers the VLDB says the volume is on
1143      * and initialize the ve->serverHost[] array. If a server struct
1144      * is not found, then get the list of addresses for the
1145      * server, VL_GetAddrsU(), and create a server struct, afs_GetServer().
1146      */
1147     for (i = 0, j = 0; i < ve->nServers; i++) {
1148         if (((ve->serverFlags[i] & mask) == 0)
1149             || (ve->serverFlags[i] & VLSF_DONTUSE)) {
1150             continue;           /* wrong volume don't use this volume */
1151         }
1152
1153         if (!(ve->serverFlags[i] & VLSF_UUID)) {
1154             /* The server has no uuid */
1155             serverid = htonl(ve->serverNumber[i].time_low);
1156             ts = afs_GetServer(&serverid, 1, acell, cellp->fsport,
1157                                WRITE_LOCK, (afsUUID *) 0, 0, av);
1158         } else {
1159             ts = afs_FindServer(0, cellp->fsport, &ve->serverNumber[i], 0);
1160             if (ts && (ts->sr_addr_uniquifier == ve->serverUnique[i])
1161                 && ts->addr) {
1162                 /* uuid, uniquifier, and portal are the same */
1163             } else {
1164                 afs_uint32 *addrp, code;
1165                 afs_int32 nentries, unique;
1166                 bulkaddrs addrs;
1167                 ListAddrByAttributes attrs;
1168                 afsUUID uuid;
1169                 struct rx_connection *rxconn;
1170
1171                 memset(&attrs, 0, sizeof(attrs));
1172                 attrs.Mask = VLADDR_UUID;
1173                 attrs.uuid = ve->serverNumber[i];
1174                 memset(&uuid, 0, sizeof(uuid));
1175                 memset(&addrs, 0, sizeof(addrs));
1176                 do {
1177                     tconn =
1178                         afs_ConnByMHosts(tcell->cellHosts, tcell->vlport,
1179                                          tcell->cellNum, areq, SHARED_LOCK,
1180                                          0, &rxconn);
1181                     if (tconn) {
1182                         RX_AFS_GUNLOCK();
1183                         code =
1184                             VL_GetAddrsU(rxconn, &attrs, &uuid, &unique,
1185                                          &nentries, &addrs);
1186                         RX_AFS_GLOCK();
1187                     } else {
1188                         code = -1;
1189                     }
1190
1191                     /* Handle corrupt VLDB (defect 7393) */
1192                     if (code == 0 && nentries == 0)
1193                         code = VL_NOENT;
1194
1195                 } while (afs_Analyze
1196                          (tconn, rxconn, code, NULL, areq, -1, SHARED_LOCK, tcell));
1197                 if (code) {
1198                     /* Better handing of such failures; for now we'll simply retry this call */
1199                     areq->volumeError = 1;
1200                     return;
1201                 }
1202
1203                 addrp = addrs.bulkaddrs_val;
1204                 for (k = 0; k < nentries; k++) {
1205                     addrp[k] = htonl(addrp[k]);
1206                 }
1207                 ts = afs_GetServer(addrp, nentries, acell,
1208                                    cellp->fsport, WRITE_LOCK,
1209                                    &ve->serverNumber[i],
1210                                    ve->serverUnique[i], av);
1211                 xdr_free((xdrproc_t) xdr_bulkaddrs, &addrs);
1212             }
1213         }
1214         serverHost[j] = ts;
1215
1216         /* The cell field could be 0 if the server entry was created
1217          * first with the 'fs setserverprefs' call which doesn't set
1218          * the cell field. Thus if the afs_GetServer call above
1219          * follows later on it will find the server entry thus it will
1220          * simply return without setting any fields, so we set the
1221          * field ourselves below.
1222          */
1223         if (!ts->cell)
1224             ts->cell = cellp;
1225         afs_PutServer(ts, WRITE_LOCK);
1226         j++;
1227     }
1228
1229     ObtainWriteLock(&av->lock, 111);
1230
1231     memcpy(av->serverHost, serverHost, sizeof(serverHost));
1232
1233     /* from above */
1234     av->states |= type;
1235
1236     /* fill in volume types */
1237     av->rwVol = ((ve->flags & VLF_RWEXISTS) ? ve->volumeId[RWVOL] : 0);
1238     av->roVol = ((ve->flags & VLF_ROEXISTS) ? ve->volumeId[ROVOL] : 0);
1239     av->backVol = ((ve->flags & VLF_BACKEXISTS) ? ve->volumeId[BACKVOL] : 0);
1240
1241     if (ve->flags & VLF_DFSFILESET)
1242         av->states |= VForeign;
1243
1244     afs_SortServers(av->serverHost, AFS_MAXHOSTS);
1245 }                               /*InstallVolumeEntry */
1246
1247
1248 /**
1249  *   Reset volume info for the specified volume strecture. Mark volume
1250  * to be rechecked next time.
1251  * @param tv
1252  */
1253 void
1254 afs_ResetVolumeInfo(struct volume *tv)
1255 {
1256     int i;
1257
1258     AFS_STATCNT(afs_ResetVolumeInfo);
1259     ObtainWriteLock(&tv->lock, 117);
1260     tv->states |= VRecheck;
1261
1262     /* the hard-mount code in afs_Analyze may not be able to reset this flag
1263      * when VRecheck is set, so clear it here to ensure it gets cleared. */
1264     tv->states &= ~VHardMount;
1265
1266     for (i = 0; i < AFS_MAXHOSTS; i++)
1267         tv->status[i] = not_busy;
1268     if (tv->name) {
1269         afs_osi_Free(tv->name, strlen(tv->name) + 1);
1270         tv->name = NULL;
1271     }
1272     ReleaseWriteLock(&tv->lock);
1273 }