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