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