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