vlserver: Allow reading during ubik writes
[openafs.git] / src / vlserver / vlprocs.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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13
14 #include <sys/types.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <lock.h>
18 #include <afs/afsutil.h>
19 #include <ubik.h>
20 #include <rx/xdr.h>
21 #include <rx/rx.h>
22 #include <rx/rxkad.h>
23 #ifdef AFS_NT40_ENV
24 #include <winsock2.h>
25 #else
26 #include <netinet/in.h>
27 #endif
28 #include <afs/keys.h>
29 #include <afs/cellconfig.h>
30 #include "vlserver.h"
31 #include "vlserver_internal.h"
32 #include "afs/audit.h"
33 #ifndef AFS_NT40_ENV
34 #include <unistd.h>
35 #endif
36 #ifdef HAVE_POSIX_REGEX         /* use POSIX regexp library */
37 #include <regex.h>
38 #endif
39
40 extern int smallMem;
41 extern int extent_mod;
42 extern struct afsconf_dir *vldb_confdir;
43 extern struct ubik_dbase *VL_dbase;
44 int maxnservers;
45 #define ABORT(c) { errorcode = (c); goto abort; }
46 #undef END
47 #define END(c) { errorcode = (c); goto end; }
48
49 #define VLDBALLOCLIMIT  10000
50 #define VLDBALLOCINCR   2048
51
52 static int put_attributeentry(struct vl_ctx *ctx,
53                               struct vldbentry **, struct vldbentry **,
54                               struct vldbentry **, bulkentries *,
55                               struct nvlentry *, afs_int32 *, afs_int32 *);
56 static int put_nattributeentry(struct vl_ctx *ctx,
57                                struct nvldbentry **, struct nvldbentry **,
58                                struct nvldbentry **, nbulkentries *,
59                                struct nvlentry *, afs_int32, afs_int32,
60                                afs_int32 *, afs_int32 *);
61 static int RemoveEntry(struct vl_ctx *ctx, afs_int32 entryptr,
62                        struct nvlentry *tentry);
63 static void ReleaseEntry(struct nvlentry *tentry, afs_int32 releasetype);
64 static int check_vldbentry(struct vldbentry *aentry);
65 static int check_nvldbentry(struct nvldbentry *aentry);
66 static int vldbentry_to_vlentry(struct vl_ctx *ctx,
67                                 struct vldbentry *VldbEntry,
68                                 struct nvlentry *VlEntry);
69 static int nvldbentry_to_vlentry(struct vl_ctx *ctx,
70                                  struct nvldbentry *VldbEntry,
71                                  struct nvlentry *VlEntry);
72 static int get_vldbupdateentry(struct vl_ctx *ctx, afs_int32 blockindex,
73                                struct VldbUpdateEntry *updateentry,
74                                struct nvlentry *VlEntry);
75 static int repsite_exists(struct nvlentry *VlEntry, int server, int partition);
76 static void repsite_compress(struct nvlentry *VlEntry, int offset);
77 static void vlentry_to_vldbentry(struct vl_ctx *ctx,
78                                  struct nvlentry *VlEntry,
79                                  struct vldbentry *VldbEntry);
80 static void vlentry_to_nvldbentry(struct vl_ctx *ctx,
81                                   struct nvlentry *VlEntry,
82                                   struct nvldbentry *VldbEntry);
83 static void vlentry_to_uvldbentry(struct vl_ctx *ctx,
84                                   struct nvlentry *VlEntry,
85                                   struct uvldbentry *VldbEntry);
86 static int InvalidVolname(char *volname);
87 static int InvalidVoltype(afs_int32 voltype);
88 static int InvalidOperation(afs_int32 voloper);
89 static int InvalidReleasetype(afs_int32 releasetype);
90 static int IpAddrToRelAddr(struct vl_ctx *ctx, afs_uint32 ipaddr, int create);
91 static int ChangeIPAddr(struct vl_ctx *ctx, afs_uint32 ipaddr1,
92                         afs_uint32 ipaddr2);
93
94 #define AFS_RXINFO_LEN 128
95 static char *
96 rxinfo(char * str, struct rx_call *rxcall)
97 {
98     int code;
99     struct rx_connection *tconn;
100     char tname[64] = "";
101     char tinst[64] = "";
102     char tcell[64] = "";
103     afs_uint32 exp;
104     struct in_addr hostAddr;
105
106     tconn = rx_ConnectionOf(rxcall);
107     hostAddr.s_addr = rx_HostOf(rx_PeerOf(tconn));
108     code =
109         rxkad_GetServerInfo(rxcall->conn, NULL, &exp, tname, tinst, tcell,
110                             NULL);
111     if (!code)
112         sprintf(str, "%s %s%s%s%s%s", inet_ntoa(hostAddr), tname,
113                 (tinst[0] == '\0') ? "" : ".",
114                 (tinst[0] == '\0') ? "" : tinst,
115                 (tcell[0] == '\0') ? "" : "@",
116                 (tcell[0] == '\0') ? "" : tcell);
117     else
118         sprintf(str, "%s noauth", inet_ntoa(hostAddr));
119     return (str);
120 }
121
122 /* This is called to initialize the database, set the appropriate locks and make sure that the vldb header is valid */
123 int
124 Init_VLdbase(struct vl_ctx *ctx,
125              int locktype,      /* indicate read or write transaction */
126              int this_op)
127 {
128     int errorcode = 0, pass, wl;
129
130     for (pass = 1; pass <= 3; pass++) {
131         if (pass == 2) {        /* take write lock to rebuild the db */
132             errorcode = ubik_BeginTrans(VL_dbase, UBIK_WRITETRANS, &ctx->trans);
133             wl = 1;
134         } else if (locktype == LOCKREAD) {
135             errorcode =
136                 ubik_BeginTransReadAnyWrite(VL_dbase, UBIK_READTRANS, &ctx->trans);
137             wl = 0;
138         } else {
139             errorcode = ubik_BeginTrans(VL_dbase, UBIK_WRITETRANS, &ctx->trans);
140             wl = 1;
141         }
142         if (errorcode)
143             return errorcode;
144
145         errorcode = ubik_SetLock(ctx->trans, 1, 1, locktype);
146         if (errorcode) {
147             COUNT_ABO;
148             ubik_AbortTrans(ctx->trans);
149             return errorcode;
150         }
151
152         /* check that dbase is initialized and setup cheader */
153         /* 2nd pass we try to rebuild the header */
154         errorcode = CheckInit(ctx->trans, ((pass == 2) ? 1 : 0));
155         if (!errorcode && wl && extent_mod)
156             errorcode = readExtents(ctx->trans);        /* Fix the mh extent blocks */
157         if (errorcode) {
158             COUNT_ABO;
159             ubik_AbortTrans(ctx->trans);
160             /* Only rebuld if the database is empty */
161             /* Exit if can't rebuild */
162             if ((pass == 1) && (errorcode != VL_EMPTY))
163                 return errorcode;
164             if (pass == 2)
165                 return errorcode;
166         } else {                /* No errorcode */
167             if (pass == 2) {
168                 ubik_EndTrans(ctx->trans);      /* Rebuilt db. End trans, then retake original lock */
169             } else {
170                 break;          /* didn't rebuild and successful - exit */
171             }
172         }
173     }
174     if (errorcode == 0) {
175         errorcode = vlsetcache(ctx, locktype);
176     }
177     return errorcode;
178 }
179
180
181 /* Create a new vldb entry; both new volume id and name must be unique
182  * (non-existant in vldb).
183  */
184
185 afs_int32
186 SVL_CreateEntry(struct rx_call *rxcall, struct vldbentry *newentry)
187 {
188     struct vl_ctx ctx;
189     afs_int32 errorcode, blockindex;
190     struct nvlentry tentry;
191     char rxstr[AFS_RXINFO_LEN];
192
193     COUNT_REQ(VLCREATEENTRY);
194     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL)) {
195         errorcode = VL_PERM;
196         goto end;
197     }
198
199     /* Do some validity tests on new entry */
200     if ((errorcode = check_vldbentry(newentry))
201         || (errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
202         goto end;
203
204     VLog(1,
205          ("OCreate Volume %d %s\n", newentry->volumeId[RWVOL],
206           rxinfo(rxstr, rxcall)));
207     if (EntryIDExists(&ctx, newentry->volumeId, MAXTYPES, &errorcode)) {
208         /* at least one of the specified IDs already exists; we fail */
209         errorcode = VL_IDEXIST;
210         goto abort;
211     } else if (errorcode) {
212         goto abort;
213     }
214
215     /* Is this following check (by volume name) necessary?? */
216     /* If entry already exists, we fail */
217     if (FindByName(&ctx, newentry->name, &tentry, &errorcode)) {
218         errorcode = VL_NAMEEXIST;
219         goto abort;
220     } else if (errorcode) {
221         goto abort;
222     }
223
224     blockindex = AllocBlock(&ctx, &tentry);
225     if (blockindex == 0) {
226         errorcode = VL_CREATEFAIL;
227         goto abort;
228     }
229
230     memset(&tentry, 0, sizeof(struct nvlentry));
231     /* Convert to its internal representation; both in host byte order */
232     if ((errorcode = vldbentry_to_vlentry(&ctx, newentry, &tentry))) {
233         FreeBlock(&ctx, blockindex);
234         goto abort;
235     }
236
237     /* Actually insert the entry in vldb */
238     errorcode = ThreadVLentry(&ctx, blockindex, &tentry);
239     if (errorcode) {
240         FreeBlock(&ctx, blockindex);
241         goto abort;
242     } else {
243         errorcode = ubik_EndTrans(ctx.trans);
244         goto end;
245     }
246
247   abort:
248     COUNT_ABO;
249     ubik_AbortTrans(ctx.trans);
250
251   end:
252     osi_auditU(rxcall, VLCreateEntryEvent, errorcode, AUD_STR,
253                (newentry ? newentry->name : NULL), AUD_END);
254     return errorcode;
255 }
256
257
258 afs_int32
259 SVL_CreateEntryN(struct rx_call *rxcall, struct nvldbentry *newentry)
260 {
261     struct vl_ctx ctx;
262     afs_int32 errorcode, blockindex;
263     struct nvlentry tentry;
264     char rxstr[AFS_RXINFO_LEN];
265
266     COUNT_REQ(VLCREATEENTRYN);
267     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL)) {
268         errorcode = VL_PERM;
269         goto end;
270     }
271
272     /* Do some validity tests on new entry */
273     if ((errorcode = check_nvldbentry(newentry))
274         || (errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
275         goto end;
276
277     VLog(1,
278          ("Create Volume %d %s\n", newentry->volumeId[RWVOL],
279           rxinfo(rxstr, rxcall)));
280     if (EntryIDExists(&ctx, newentry->volumeId, MAXTYPES, &errorcode)) {
281         /* at least one of the specified IDs already exists; we fail */
282         errorcode = VL_IDEXIST;
283         goto abort;
284     } else if (errorcode) {
285         goto abort;
286     }
287
288     /* Is this following check (by volume name) necessary?? */
289     /* If entry already exists, we fail */
290     if (FindByName(&ctx, newentry->name, &tentry, &errorcode)) {
291         errorcode = VL_NAMEEXIST;
292         goto abort;
293     } else if (errorcode) {
294         goto abort;
295     }
296
297     blockindex = AllocBlock(&ctx, &tentry);
298     if (blockindex == 0) {
299         errorcode = VL_CREATEFAIL;
300         goto abort;
301     }
302
303     memset(&tentry, 0, sizeof(struct nvlentry));
304     /* Convert to its internal representation; both in host byte order */
305     if ((errorcode = nvldbentry_to_vlentry(&ctx, newentry, &tentry))) {
306         FreeBlock(&ctx, blockindex);
307         goto abort;
308     }
309
310     /* Actually insert the entry in vldb */
311     errorcode = ThreadVLentry(&ctx, blockindex, &tentry);
312     if (errorcode) {
313         FreeBlock(&ctx, blockindex);
314         goto abort;
315     } else {
316         errorcode = ubik_EndTrans(ctx.trans);
317         goto end;
318     }
319
320   abort:
321     COUNT_ABO;
322     ubik_AbortTrans(ctx.trans);
323
324   end:
325     osi_auditU(rxcall, VLCreateEntryEvent, errorcode, AUD_STR,
326                (newentry ? newentry->name : NULL), AUD_END);
327     return errorcode;
328 }
329
330
331 afs_int32
332 SVL_ChangeAddr(struct rx_call *rxcall, afs_uint32 ip1, afs_uint32 ip2)
333 {
334     struct vl_ctx ctx;
335     afs_int32 errorcode;
336     char rxstr[AFS_RXINFO_LEN];
337
338     COUNT_REQ(VLCHANGEADDR);
339     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL)) {
340         errorcode = VL_PERM;
341         goto end;
342     }
343
344     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
345         goto end;
346
347     VLog(1, ("Change Addr %u -> %u %s\n", ip1, ip2, rxinfo(rxstr, rxcall)));
348     if ((errorcode = ChangeIPAddr(&ctx, ip1, ip2)))
349         goto abort;
350     else {
351         errorcode = ubik_EndTrans(ctx.trans);
352         goto end;
353     }
354
355   abort:
356     COUNT_ABO;
357     ubik_AbortTrans(ctx.trans);
358
359   end:
360     osi_auditU(rxcall, VLChangeAddrEvent, errorcode, AUD_LONG, ip1, AUD_LONG,
361                ip2, AUD_END);
362     return errorcode;
363 }
364
365 /* Delete a vldb entry given the volume id. */
366 afs_int32
367 SVL_DeleteEntry(struct rx_call *rxcall, afs_uint32 volid, afs_int32 voltype)
368 {
369     struct vl_ctx ctx;
370     afs_int32 blockindex, errorcode;
371     struct nvlentry tentry;
372     char rxstr[AFS_RXINFO_LEN];
373
374     COUNT_REQ(VLDELETEENTRY);
375     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
376         END(VL_PERM);
377
378     if ((voltype != -1) && (InvalidVoltype(voltype)))
379         END(VL_BADVOLTYPE);
380
381     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
382         goto end;
383
384     VLog(1, ("Delete Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
385     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
386     if (blockindex == 0) {      /* volid not found */
387         if (!errorcode)
388             errorcode = VL_NOENT;
389         goto abort;
390     }
391
392     if (tentry.flags & VLDELETED) {     /* Already deleted; return */
393         ABORT(VL_ENTDELETED);
394     }
395     if ((errorcode = RemoveEntry(&ctx, blockindex, &tentry))) {
396         goto abort;
397     }
398     errorcode = (ubik_EndTrans(ctx.trans));
399     goto end;
400
401   abort:
402     COUNT_ABO;
403     ubik_AbortTrans(ctx.trans);
404
405   end:
406     osi_auditU(rxcall, VLDeleteEntryEvent, errorcode, AUD_LONG, volid,
407                AUD_END);
408     return errorcode;
409 }
410
411
412 /* Get a vldb entry given its volume id; make sure it's not a deleted entry. */
413 int
414 GetEntryByID(struct rx_call *rxcall,
415              afs_uint32 volid,
416              afs_int32 voltype,
417              char *aentry,      /* entry data copied here */
418              afs_int32 new,
419              afs_int32 this_op)
420 {
421     struct vl_ctx ctx;
422     afs_int32 blockindex, errorcode;
423     struct nvlentry tentry;
424     char rxstr[AFS_RXINFO_LEN];
425
426     if ((voltype != -1) && (InvalidVoltype(voltype)))
427         return VL_BADVOLTYPE;
428     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
429         return errorcode;
430
431     VLog(5, ("GetVolumeByID %u (%d) %s\n", volid, new,
432              rxinfo(rxstr, rxcall)));
433     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
434     if (blockindex == 0) {      /* entry not found */
435         if (!errorcode)
436             errorcode = VL_NOENT;
437         COUNT_ABO;
438         ubik_AbortTrans(ctx.trans);
439         return errorcode;
440     }
441     if (tentry.flags & VLDELETED) {     /* Entry is deleted! */
442         COUNT_ABO;
443         ubik_AbortTrans(ctx.trans);
444         return VL_ENTDELETED;
445     }
446     /* Convert from the internal to external form */
447     if (new == 1)
448         vlentry_to_nvldbentry(&ctx, &tentry, (struct nvldbentry *)aentry);
449     else if (new == 2)
450         vlentry_to_uvldbentry(&ctx, &tentry, (struct uvldbentry *)aentry);
451     else
452         vlentry_to_vldbentry(&ctx, &tentry, (struct vldbentry *)aentry);
453     return (ubik_EndTrans(ctx.trans));
454 }
455
456 afs_int32
457 SVL_GetEntryByID(struct rx_call *rxcall,
458                  afs_uint32 volid,
459                  afs_int32 voltype,
460                  vldbentry *aentry)             /* entry data copied here */
461 {
462     COUNT_REQ(VLGETENTRYBYID);
463     return (GetEntryByID(rxcall, volid, voltype, (char *)aentry, 0, this_op));
464 }
465
466 afs_int32
467 SVL_GetEntryByIDN(struct rx_call *rxcall,
468                   afs_uint32 volid,
469                   afs_int32 voltype,
470                   nvldbentry *aentry)   /* entry data copied here */
471 {
472     COUNT_REQ(VLGETENTRYBYIDN);
473     return (GetEntryByID(rxcall, volid, voltype, (char *)aentry, 1, this_op));
474 }
475
476 afs_int32
477 SVL_GetEntryByIDU(struct rx_call *rxcall,
478                   afs_uint32 volid,
479                   afs_int32 voltype,
480                   uvldbentry *aentry)   /* entry data copied here */
481 {
482     COUNT_REQ(VLGETENTRYBYIDU);
483     return (GetEntryByID(rxcall, volid, voltype, (char *)aentry, 2, this_op));
484 }
485
486
487
488 /* returns true if the id is a decimal integer, in which case we interpret
489  * it as an id.  make the cache manager much simpler */
490 static int
491 NameIsId(char *aname)
492 {
493     int tc;
494     while ((tc = *aname++)) {
495         if (tc > '9' || tc < '0')
496             return 0;
497     }
498     return 1;
499 }
500
501 /* Get a vldb entry given the volume's name; of course, very similar to
502  * VLGetEntryByID() above. */
503 afs_int32
504 GetEntryByName(struct rx_call *rxcall,
505                char *volname,
506                char *aentry,            /* entry data copied here */
507                int new,
508                int this_op)
509 {
510     struct vl_ctx ctx;
511     afs_int32 blockindex, errorcode;
512     struct nvlentry tentry;
513     char rxstr[AFS_RXINFO_LEN];
514
515     if (NameIsId(volname)) {
516         return GetEntryByID(rxcall, atoi(volname), -1, aentry, new, this_op);
517     }
518     if (InvalidVolname(volname))
519         return VL_BADNAME;
520     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
521         return errorcode;
522     VLog(5, ("GetVolumeByName %s (%d) %s\n", volname, new, rxinfo(rxstr, rxcall)));
523     blockindex = FindByName(&ctx, volname, &tentry, &errorcode);
524     if (blockindex == 0) {      /* entry not found */
525         if (!errorcode)
526             errorcode = VL_NOENT;
527         COUNT_ABO;
528         ubik_AbortTrans(ctx.trans);
529         return errorcode;
530     }
531     if (tentry.flags & VLDELETED) {     /* Entry is deleted */
532         COUNT_ABO;
533         ubik_AbortTrans(ctx.trans);
534         return VL_ENTDELETED;
535     }
536     /* Convert to external entry representation */
537     if (new == 1)
538         vlentry_to_nvldbentry(&ctx, &tentry, (struct nvldbentry *)aentry);
539     else if (new == 2)
540         vlentry_to_uvldbentry(&ctx, &tentry, (struct uvldbentry *)aentry);
541     else
542         vlentry_to_vldbentry(&ctx, &tentry, (struct vldbentry *)aentry);
543     return (ubik_EndTrans(ctx.trans));
544 }
545
546 afs_int32
547 SVL_GetEntryByNameO(struct rx_call *rxcall,
548                     char *volname,
549                     struct vldbentry *aentry)   /* entry data copied here */
550 {
551     COUNT_REQ(VLGETENTRYBYNAME);
552     return (GetEntryByName(rxcall, volname, (char *)aentry, 0, this_op));
553 }
554
555
556 afs_int32
557 SVL_GetEntryByNameN(struct rx_call *rxcall,
558                     char *volname,
559                     struct nvldbentry *aentry)  /* entry data copied here */
560 {
561     COUNT_REQ(VLGETENTRYBYNAMEN);
562     return (GetEntryByName(rxcall, volname, (char *)aentry, 1, this_op));
563 }
564
565 afs_int32
566 SVL_GetEntryByNameU(struct rx_call *rxcall,
567                     char *volname,
568                     struct uvldbentry *aentry)  /* entry data copied here */
569 {
570     COUNT_REQ(VLGETENTRYBYNAMEU);
571     return (GetEntryByName(rxcall, volname, (char *)aentry, 2, this_op));
572 }
573
574
575
576 /* Get the current value of the maximum volume id and bump the volume id counter by Maxvolidbump. */
577 afs_int32
578 SVL_GetNewVolumeId(struct rx_call *rxcall, afs_uint32 Maxvolidbump,
579                    afs_uint32 *newvolumeid)
580 {
581     afs_int32 errorcode;
582     afs_uint32 maxvolumeid;
583     struct vl_ctx ctx;
584     char rxstr[AFS_RXINFO_LEN];
585
586     COUNT_REQ(VLGETNEWVOLUMEID);
587     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
588         END(VL_PERM);
589
590     if (Maxvolidbump < 0 || Maxvolidbump > MAXBUMPCOUNT)
591         END(VL_BADVOLIDBUMP);
592
593     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
594         goto end;
595
596     *newvolumeid = maxvolumeid = NextUnusedID(&ctx,
597         ntohl(ctx.cheader->vital_header.MaxVolumeId), Maxvolidbump, &errorcode);
598     if (errorcode) {
599         goto abort;
600     }
601
602     maxvolumeid += Maxvolidbump;
603     VLog(1, ("GetNewVolid newmax=%u %s\n", maxvolumeid, rxinfo(rxstr, rxcall)));
604     ctx.cheader->vital_header.MaxVolumeId = htonl(maxvolumeid);
605     if (write_vital_vlheader(&ctx)) {
606         ABORT(VL_IO);
607     }
608     errorcode = (ubik_EndTrans(ctx.trans));
609     goto end;
610
611   abort:
612     COUNT_ABO;
613     ubik_AbortTrans(ctx.trans);
614
615   end:
616     osi_auditU(rxcall, VLGetNewVolumeIdEvent, errorcode, AUD_END);
617     return errorcode;
618 }
619
620
621 /* Simple replace the contents of the vldb entry, volid, with
622  * newentry. No individual checking/updating per field (alike
623  * VLUpdateEntry) is done. */
624
625 afs_int32
626 SVL_ReplaceEntry(struct rx_call *rxcall, afs_uint32 volid, afs_int32 voltype,
627                  struct vldbentry *newentry, afs_int32 releasetype)
628 {
629     struct vl_ctx ctx;
630     afs_int32 blockindex, errorcode, typeindex;
631     int hashnewname;
632     int hashVol[MAXTYPES];
633     struct nvlentry tentry;
634     afs_uint32 checkids[MAXTYPES];
635     char rxstr[AFS_RXINFO_LEN];
636
637     COUNT_REQ(VLREPLACEENTRY);
638     for (typeindex = 0; typeindex < MAXTYPES; typeindex++)
639         hashVol[typeindex] = 0;
640     hashnewname = 0;
641     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
642         END(VL_PERM);
643
644     if ((errorcode = check_vldbentry(newentry)))
645         goto end;
646
647     if (voltype != -1 && InvalidVoltype(voltype))
648         END(VL_BADVOLTYPE);
649
650     if (releasetype && InvalidReleasetype(releasetype))
651         END(VL_BADRELLOCKTYPE);
652     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
653         goto end;
654
655     VLog(1, ("OReplace Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
656     /* find vlentry we're changing */
657     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
658     if (blockindex == 0) {      /* entry not found */
659         if (!errorcode)
660             errorcode = VL_NOENT;
661         goto abort;
662     }
663
664     /* check that we're not trying to change the RW vol ID */
665     if (newentry->volumeId[RWVOL] != tentry.volumeId[RWVOL]) {
666         ABORT(VL_BADENTRY);
667     }
668
669     /* make sure none of the IDs we are changing to are already in use */
670     memset(&checkids, 0, sizeof(checkids));
671     for (typeindex = ROVOL; typeindex < MAXTYPES; typeindex++) {
672         if (tentry.volumeId[typeindex] != newentry->volumeId[typeindex]) {
673             checkids[typeindex] = newentry->volumeId[typeindex];
674         }
675     }
676     if (EntryIDExists(&ctx, checkids, MAXTYPES, &errorcode)) {
677         ABORT(VL_IDEXIST);
678     } else if (errorcode) {
679         goto abort;
680     }
681
682     /* make sure the name we're changing to doesn't already exist */
683     if (strcmp(newentry->name, tentry.name)) {
684         struct nvlentry tmp_entry;
685         if (FindByName(&ctx, newentry->name, &tmp_entry, &errorcode)) {
686             ABORT(VL_NAMEEXIST);
687         } else if (errorcode) {
688             goto abort;
689         }
690     }
691
692     /* unhash volid entries if they're disappearing or changing.
693      * Remember if we need to hash in the new value (we don't have to
694      * rehash if volid stays same */
695     for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
696         if (tentry.volumeId[typeindex] != newentry->volumeId[typeindex]) {
697             if (tentry.volumeId[typeindex])
698                 if ((errorcode =
699                     UnhashVolid(&ctx, typeindex, blockindex, &tentry))) {
700                     goto abort;
701                 }
702             /* we must rehash new id if the id is different and the ID is nonzero */
703             hashVol[typeindex] = 1;     /* must rehash this guy if he exists */
704         }
705     }
706
707     /* Rehash volname if it changes */
708     if (strcmp(newentry->name, tentry.name)) {  /* Name changes; redo hashing */
709         if ((errorcode = UnhashVolname(&ctx, blockindex, &tentry))) {
710             goto abort;
711         }
712         hashnewname = 1;
713     }
714
715     /* after this, tentry is new entry, not old one.  vldbentry_to_vlentry
716      * doesn't touch hash chains */
717     if ((errorcode = vldbentry_to_vlentry(&ctx, newentry, &tentry))) {
718         goto abort;
719     }
720
721     for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
722         if (hashVol[typeindex] && tentry.volumeId[typeindex]) {
723             if ((errorcode = HashVolid(&ctx, typeindex, blockindex, &tentry))) {
724                 goto abort;
725             }
726         }
727     }
728
729     if (hashnewname)
730         HashVolname(&ctx, blockindex, &tentry);
731
732     if (releasetype)
733         ReleaseEntry(&tentry, releasetype);     /* Unlock entry if necessary */
734     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
735         ABORT(VL_IO);
736     }
737
738     END(ubik_EndTrans(ctx.trans));
739
740   abort:
741     COUNT_ABO;
742     ubik_AbortTrans(ctx.trans);
743
744   end:
745     osi_auditU(rxcall, VLReplaceVLEntryEvent, errorcode, AUD_LONG, volid,
746                AUD_END);
747     return errorcode;
748 }
749
750 afs_int32
751 SVL_ReplaceEntryN(struct rx_call *rxcall, afs_uint32 volid, afs_int32 voltype,
752                   struct nvldbentry *newentry, afs_int32 releasetype)
753 {
754     struct vl_ctx ctx;
755     afs_int32 blockindex, errorcode, typeindex;
756     int hashnewname;
757     int hashVol[MAXTYPES];
758     struct nvlentry tentry;
759     char rxstr[AFS_RXINFO_LEN];
760
761     COUNT_REQ(VLREPLACEENTRYN);
762     for (typeindex = 0; typeindex < MAXTYPES; typeindex++)
763         hashVol[typeindex] = 0;
764     hashnewname = 0;
765     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
766         END(VL_PERM);
767
768     if ((errorcode = check_nvldbentry(newentry)))
769         goto end;
770
771     if (voltype != -1 && InvalidVoltype(voltype))
772         END(VL_BADVOLTYPE);
773
774     if (releasetype && InvalidReleasetype(releasetype))
775         END(VL_BADRELLOCKTYPE);
776     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
777         goto end;
778
779     VLog(1, ("Replace Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
780     /* find vlentry we're changing */
781     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
782     if (blockindex == 0) {      /* entry not found */
783         if (!errorcode)
784             errorcode = VL_NOENT;
785         goto abort;
786     }
787
788     /* check that we're not trying to change the RW vol ID */
789     if (newentry->volumeId[RWVOL] != tentry.volumeId[RWVOL]) {
790         ABORT(VL_BADENTRY);
791     }
792
793     /* unhash volid entries if they're disappearing or changing.
794      * Remember if we need to hash in the new value (we don't have to
795      * rehash if volid stays same */
796     for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
797         if (tentry.volumeId[typeindex] != newentry->volumeId[typeindex]) {
798             if (tentry.volumeId[typeindex])
799                 if ((errorcode =
800                     UnhashVolid(&ctx, typeindex, blockindex, &tentry))) {
801                     goto abort;
802                 }
803             /* we must rehash new id if the id is different and the ID is nonzero */
804             hashVol[typeindex] = 1;     /* must rehash this guy if he exists */
805         }
806     }
807
808     /* Rehash volname if it changes */
809     if (strcmp(newentry->name, tentry.name)) {  /* Name changes; redo hashing */
810         if ((errorcode = UnhashVolname(&ctx, blockindex, &tentry))) {
811             goto abort;
812         }
813         hashnewname = 1;
814     }
815
816     /* after this, tentry is new entry, not old one.  vldbentry_to_vlentry
817      * doesn't touch hash chains */
818     if ((errorcode = nvldbentry_to_vlentry(&ctx, newentry, &tentry))) {
819         goto abort;
820     }
821
822     for (typeindex = ROVOL; typeindex <= BACKVOL; typeindex++) {
823         if (hashVol[typeindex] && tentry.volumeId[typeindex]) {
824             if ((errorcode = HashVolid(&ctx, typeindex, blockindex, &tentry))) {
825                 goto abort;
826             }
827         }
828     }
829
830     if (hashnewname)
831         HashVolname(&ctx, blockindex, &tentry);
832
833     if (releasetype)
834         ReleaseEntry(&tentry, releasetype);     /* Unlock entry if necessary */
835     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
836         ABORT(VL_IO);
837     }
838
839     END(ubik_EndTrans(ctx.trans));
840
841   abort:
842     COUNT_ABO;
843     ubik_AbortTrans(ctx.trans);
844
845   end:
846     osi_auditU(rxcall, VLReplaceVLEntryEvent, errorcode, AUD_LONG, volid,
847                AUD_END);
848     return errorcode;
849 }
850
851
852 /* Update a vldb entry (accessed thru its volume id). Almost all of the
853  * entry's fields can be modified in a single call by setting the
854  * appropriate bits in the Mask field in VldbUpdateentry. */
855 /* this routine may never have been tested; use replace entry instead
856  * unless you're brave */
857 afs_int32
858 SVL_UpdateEntry(struct rx_call *rxcall,
859                 afs_uint32 volid,
860                 afs_int32 voltype,
861                 struct VldbUpdateEntry *updateentry,    /* Update entry copied here */
862                 afs_int32 releasetype)
863 {
864     struct vl_ctx ctx;
865     afs_int32 blockindex, errorcode;
866     struct nvlentry tentry;
867     char rxstr[AFS_RXINFO_LEN];
868
869     COUNT_REQ(VLUPDATEENTRY);
870     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
871         END(VL_PERM);
872     if ((voltype != -1) && (InvalidVoltype(voltype)))
873         END(VL_BADVOLTYPE);
874     if (releasetype && InvalidReleasetype(releasetype))
875         END(VL_BADRELLOCKTYPE);
876     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
877         goto end;
878
879     VLog(1, ("Update Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
880     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
881     if (blockindex == 0) {      /* entry not found */
882         if (!errorcode)
883             errorcode = VL_NOENT;
884         goto abort;
885     }
886
887     /* Do the actual updating of the entry, tentry. */
888     if ((errorcode =
889         get_vldbupdateentry(&ctx, blockindex, updateentry, &tentry))) {
890         goto abort;
891     }
892     if (releasetype)
893         ReleaseEntry(&tentry, releasetype);     /* Unlock entry if necessary */
894     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
895         ABORT(VL_IO);
896     }
897     END(ubik_EndTrans(ctx.trans));
898
899   abort:
900     COUNT_ABO;
901     ubik_AbortTrans(ctx.trans);
902
903   end:
904     osi_auditU(rxcall, VLUpdateEntryEvent, errorcode, AUD_LONG, volid,
905                AUD_END);
906     return errorcode;
907 }
908
909
910 afs_int32
911 SVL_UpdateEntryByName(struct rx_call *rxcall,
912                       char *volname,
913                       struct VldbUpdateEntry *updateentry, /* Update entry copied here */
914                       afs_int32 releasetype)
915 {
916     struct vl_ctx ctx;
917     afs_int32 blockindex, errorcode;
918     struct nvlentry tentry;
919
920     COUNT_REQ(VLUPDATEENTRYBYNAME);
921     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
922         END(VL_PERM);
923     if (releasetype && InvalidReleasetype(releasetype))
924         END(VL_BADRELLOCKTYPE);
925     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
926         goto end;
927
928     blockindex = FindByName(&ctx, volname, &tentry, &errorcode);
929     if (blockindex == 0) {      /* entry not found */
930         if (!errorcode)
931             errorcode = VL_NOENT;
932         goto abort;
933     }
934
935     /* Do the actual updating of the entry, tentry. */
936     if ((errorcode =
937         get_vldbupdateentry(&ctx, blockindex, updateentry, &tentry))) {
938         goto abort;
939     }
940     if (releasetype)
941         ReleaseEntry(&tentry, releasetype);     /* Unlock entry if necessary */
942     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
943         ABORT(VL_IO);
944     }
945     END(ubik_EndTrans(ctx.trans));
946
947   abort:
948     COUNT_ABO;
949     ubik_AbortTrans(ctx.trans);
950
951   end:
952     osi_auditU(rxcall, VLUpdateEntryEvent, errorcode, AUD_LONG, -1, AUD_END);
953     return errorcode;
954 }
955
956
957 /* Set a lock to the vldb entry for volid (of type voltype if not -1). */
958 afs_int32
959 SVL_SetLock(struct rx_call *rxcall, afs_uint32 volid, afs_int32 voltype,
960             afs_int32 voloper)
961 {
962     afs_int32 timestamp, blockindex, errorcode;
963     struct vl_ctx ctx;
964     struct nvlentry tentry;
965     char rxstr[AFS_RXINFO_LEN];
966
967     COUNT_REQ(VLSETLOCK);
968     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
969         END(VL_PERM);
970     if ((voltype != -1) && (InvalidVoltype(voltype)))
971         END(VL_BADVOLTYPE);
972     if (InvalidOperation(voloper))
973         END(VL_BADVOLOPER);
974     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
975         goto end;
976
977     VLog(1, ("SetLock Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
978     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
979     if (blockindex == NULLO) {
980         if (!errorcode)
981             errorcode = VL_NOENT;
982         goto abort;
983     }
984     if (tentry.flags & VLDELETED) {
985         ABORT(VL_ENTDELETED);
986     }
987     timestamp = FT_ApproxTime();
988
989     /* Check if entry is already locked; note that we unlock any entry
990      * locked more than MAXLOCKTIME seconds */
991     if ((tentry.LockTimestamp)
992         && ((timestamp - tentry.LockTimestamp) < MAXLOCKTIME)) {
993         ABORT(VL_ENTRYLOCKED);
994     }
995
996     /* Consider it an unlocked entry: set current timestamp, caller
997      * and active vol operation */
998     tentry.LockTimestamp = timestamp;
999     tentry.LockAfsId = 0;       /* Not implemented yet */
1000     if (tentry.flags & VLOP_RELEASE) {
1001         ABORT(VL_RERELEASE);
1002     }
1003     tentry.flags &= ~VLOP_ALLOPERS;     /* Clear any possible older operation bit */
1004     tentry.flags |= voloper;
1005
1006     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
1007         ABORT(VL_IO);
1008     }
1009     END(ubik_EndTrans(ctx.trans));
1010
1011   abort:
1012     COUNT_ABO;
1013     ubik_AbortTrans(ctx.trans);
1014
1015   end:
1016     osi_auditU(rxcall, VLSetLockEvent, errorcode, AUD_LONG, volid, AUD_END);
1017     return errorcode;
1018 }
1019
1020
1021 /* Release an already locked vldb entry. Releasetype determines what
1022  * fields (afsid and/or volume operation) will be cleared along with
1023  * the lock time stamp. */
1024
1025 afs_int32
1026 SVL_ReleaseLock(struct rx_call *rxcall, afs_uint32 volid, afs_int32 voltype,
1027                 afs_int32 releasetype)
1028 {
1029     afs_int32 blockindex, errorcode;
1030     struct vl_ctx ctx;
1031     struct nvlentry tentry;
1032     char rxstr[AFS_RXINFO_LEN];
1033
1034     COUNT_REQ(VLRELEASELOCK);
1035     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
1036         END(VL_PERM);
1037     if ((voltype != -1) && (InvalidVoltype(voltype)))
1038         END(VL_BADVOLTYPE);
1039     if (releasetype && InvalidReleasetype(releasetype))
1040         END(VL_BADRELLOCKTYPE);
1041     if ((errorcode = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
1042         goto end;
1043
1044     VLog(1, ("ReleaseLock Volume %u %s\n", volid, rxinfo(rxstr, rxcall)));
1045     blockindex = FindByID(&ctx, volid, voltype, &tentry, &errorcode);
1046     if (blockindex == NULLO) {
1047         if (!errorcode)
1048             errorcode = VL_NOENT;
1049         goto abort;
1050     }
1051     if (tentry.flags & VLDELETED) {
1052         ABORT(VL_ENTDELETED);
1053     }
1054     if (releasetype)
1055         ReleaseEntry(&tentry, releasetype);     /* Unlock the appropriate fields */
1056     if (vlentrywrite(ctx.trans, blockindex, &tentry, sizeof(tentry))) {
1057         ABORT(VL_IO);
1058     }
1059     END(ubik_EndTrans(ctx.trans));
1060
1061   abort:
1062     COUNT_ABO;
1063     ubik_AbortTrans(ctx.trans);
1064
1065   end:
1066     osi_auditU(rxcall, VLReleaseLockEvent, errorcode, AUD_LONG, volid,
1067                AUD_END);
1068     return errorcode;
1069 }
1070
1071
1072 /* ListEntry returns a single vldb entry, aentry, with offset previous_index;
1073  * the remaining parameters (i.e. next_index) are used so that sequential
1074  * calls to this routine will get the next (all) vldb entries.
1075  */
1076 afs_int32
1077 SVL_ListEntry(struct rx_call *rxcall, afs_int32 previous_index,
1078               afs_int32 *count, afs_int32 *next_index,
1079               struct vldbentry *aentry)
1080 {
1081     int errorcode;
1082     struct vl_ctx ctx;
1083     struct nvlentry tentry;
1084     char rxstr[AFS_RXINFO_LEN];
1085
1086     COUNT_REQ(VLLISTENTRY);
1087     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1088         return errorcode;
1089     VLog(25, ("OListEntry index=%d %s\n", previous_index,
1090               rxinfo(rxstr, rxcall)));
1091     *next_index = NextEntry(&ctx, previous_index, &tentry, count);
1092     if (*next_index)
1093         vlentry_to_vldbentry(&ctx, &tentry, aentry);
1094     return (ubik_EndTrans(ctx.trans));
1095 }
1096
1097 /* ListEntry returns a single vldb entry, aentry, with offset previous_index;
1098  * the remaining parameters (i.e. next_index) are used so that sequential
1099  * calls to this routine will get the next (all) vldb entries.
1100  */
1101 afs_int32
1102 SVL_ListEntryN(struct rx_call *rxcall, afs_int32 previous_index,
1103                afs_int32 *count, afs_int32 *next_index,
1104                struct nvldbentry *aentry)
1105 {
1106     int errorcode;
1107     struct vl_ctx ctx;
1108     struct nvlentry tentry;
1109     char rxstr[AFS_RXINFO_LEN];
1110
1111     COUNT_REQ(VLLISTENTRYN);
1112     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1113         return errorcode;
1114     VLog(25, ("ListEntry index=%d %s\n", previous_index, rxinfo(rxstr, rxcall)));
1115     *next_index = NextEntry(&ctx, previous_index, &tentry, count);
1116     if (*next_index)
1117         vlentry_to_nvldbentry(&ctx, &tentry, aentry);
1118     return (ubik_EndTrans(ctx.trans));
1119 }
1120
1121
1122 /* Retrieves in vldbentries all vldb entries that match the specified
1123  * attributes (by server number, partition, volume type, and flag); if volume
1124  * id is specified then the associated list for that entry is returned.
1125  * CAUTION: This could be a very expensive call since in most cases
1126  * sequential search of all vldb entries is performed.
1127  */
1128 afs_int32
1129 SVL_ListAttributes(struct rx_call *rxcall,
1130                    struct VldbListByAttributes *attributes,
1131                    afs_int32 *nentries,
1132                    bulkentries *vldbentries)
1133 {
1134     int errorcode, allocCount = 0;
1135     struct vl_ctx ctx;
1136     struct nvlentry tentry;
1137     struct vldbentry *Vldbentry = 0, *VldbentryFirst = 0, *VldbentryLast = 0;
1138     int pollcount = 0;
1139     char rxstr[AFS_RXINFO_LEN];
1140
1141     COUNT_REQ(VLLISTATTRIBUTES);
1142     vldbentries->bulkentries_val = 0;
1143     vldbentries->bulkentries_len = *nentries = 0;
1144     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1145         return errorcode;
1146     allocCount = VLDBALLOCCOUNT;
1147     Vldbentry = VldbentryFirst = vldbentries->bulkentries_val =
1148         (vldbentry *) malloc(allocCount * sizeof(vldbentry));
1149     if (Vldbentry == NULL) {
1150         COUNT_ABO;
1151         ubik_AbortTrans(ctx.trans);
1152         return VL_NOMEM;
1153     }
1154     VldbentryLast = VldbentryFirst + allocCount;
1155     /* Handle the attribute by volume id totally separate of the rest
1156      * (thus additional Mask values are ignored if VLLIST_VOLUMEID is set!) */
1157     if (attributes->Mask & VLLIST_VOLUMEID) {
1158         afs_int32 blockindex;
1159
1160         blockindex =
1161             FindByID(&ctx, attributes->volumeid, -1, &tentry, &errorcode);
1162         if (blockindex == 0) {
1163             if (!errorcode)
1164                 errorcode = VL_NOENT;
1165             COUNT_ABO;
1166             ubik_AbortTrans(ctx.trans);
1167             if (vldbentries->bulkentries_val)
1168                 free((char *)vldbentries->bulkentries_val);
1169             vldbentries->bulkentries_val = 0;
1170             vldbentries->bulkentries_len = 0;
1171             return errorcode;
1172         }
1173         if ((errorcode =
1174             put_attributeentry(&ctx, &Vldbentry, &VldbentryFirst, &VldbentryLast,
1175                                vldbentries, &tentry, nentries, &allocCount))) {
1176             COUNT_ABO;
1177             ubik_AbortTrans(ctx.trans);
1178             if (vldbentries->bulkentries_val)
1179                 free((char *)vldbentries->bulkentries_val);
1180             vldbentries->bulkentries_val = 0;
1181             vldbentries->bulkentries_len = 0;
1182             return VL_SIZEEXCEEDED;
1183         }
1184     } else {
1185         afs_int32 nextblockindex = 0, count = 0, k = 0, match = 0;
1186         while ((nextblockindex =
1187                NextEntry(&ctx, nextblockindex, &tentry, &count))) {
1188             if (++pollcount > 50) {
1189 #ifndef AFS_PTHREAD_ENV
1190                 IOMGR_Poll();
1191 #endif
1192                 pollcount = 0;
1193             }
1194             match = 0;
1195             if (attributes->Mask & VLLIST_SERVER) {
1196                 int serverindex;
1197                 if ((serverindex =
1198                      IpAddrToRelAddr(&ctx, attributes->server, 0)) == -1)
1199                     continue;
1200                 for (k = 0; k < OMAXNSERVERS; k++) {
1201                     if (tentry.serverNumber[k] == BADSERVERID)
1202                         break;
1203                     if (tentry.serverNumber[k] == serverindex) {
1204                         match = 1;
1205                         break;
1206                     }
1207                 }
1208                 if (!match)
1209                     continue;
1210             }
1211             if (attributes->Mask & VLLIST_PARTITION) {
1212                 if (match) {
1213                     if (tentry.serverPartition[k] != attributes->partition)
1214                         continue;
1215                 } else {
1216                     for (k = 0; k < OMAXNSERVERS; k++) {
1217                         if (tentry.serverNumber[k] == BADSERVERID)
1218                             break;
1219                         if (tentry.serverPartition[k] ==
1220                             attributes->partition) {
1221                             match = 1;
1222                             break;
1223                         }
1224                     }
1225                     if (!match)
1226                         continue;
1227                 }
1228             }
1229
1230             if (attributes->Mask & VLLIST_FLAG) {
1231                 if (!(tentry.flags & attributes->flag))
1232                     continue;
1233             }
1234             if ((errorcode =
1235                 put_attributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1236                                    &VldbentryLast, vldbentries, &tentry,
1237                                    nentries, &allocCount))) {
1238                 COUNT_ABO;
1239                 ubik_AbortTrans(ctx.trans);
1240                 if (vldbentries->bulkentries_val)
1241                     free((char *)vldbentries->bulkentries_val);
1242                 vldbentries->bulkentries_val = 0;
1243                 vldbentries->bulkentries_len = 0;
1244                 return errorcode;
1245             }
1246         }
1247     }
1248     if (vldbentries->bulkentries_len
1249         && (allocCount > vldbentries->bulkentries_len)) {
1250
1251         vldbentries->bulkentries_val =
1252             (vldbentry *) realloc(vldbentries->bulkentries_val,
1253                                   vldbentries->bulkentries_len *
1254                                   sizeof(vldbentry));
1255         if (vldbentries->bulkentries_val == NULL) {
1256             COUNT_ABO;
1257             ubik_AbortTrans(ctx.trans);
1258             return VL_NOMEM;
1259         }
1260     }
1261     VLog(5,
1262          ("ListAttrs nentries=%d %s\n", vldbentries->bulkentries_len,
1263           rxinfo(rxstr, rxcall)));
1264     return (ubik_EndTrans(ctx.trans));
1265 }
1266
1267 afs_int32
1268 SVL_ListAttributesN(struct rx_call *rxcall,
1269                     struct VldbListByAttributes *attributes,
1270                     afs_int32 *nentries,
1271                     nbulkentries *vldbentries)
1272 {
1273     int errorcode, allocCount = 0;
1274     struct vl_ctx ctx;
1275     struct nvlentry tentry;
1276     struct nvldbentry *Vldbentry = 0, *VldbentryFirst = 0, *VldbentryLast = 0;
1277     int pollcount = 0;
1278     char rxstr[AFS_RXINFO_LEN];
1279
1280     COUNT_REQ(VLLISTATTRIBUTESN);
1281     vldbentries->nbulkentries_val = 0;
1282     vldbentries->nbulkentries_len = *nentries = 0;
1283     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1284         return errorcode;
1285     allocCount = VLDBALLOCCOUNT;
1286     Vldbentry = VldbentryFirst = vldbentries->nbulkentries_val =
1287         (nvldbentry *) malloc(allocCount * sizeof(nvldbentry));
1288     if (Vldbentry == NULL) {
1289         COUNT_ABO;
1290         ubik_AbortTrans(ctx.trans);
1291         return VL_NOMEM;
1292     }
1293     VldbentryLast = VldbentryFirst + allocCount;
1294     /* Handle the attribute by volume id totally separate of the rest
1295      * (thus additional Mask values are ignored if VLLIST_VOLUMEID is set!) */
1296     if (attributes->Mask & VLLIST_VOLUMEID) {
1297         afs_int32 blockindex;
1298
1299         blockindex =
1300             FindByID(&ctx, attributes->volumeid, -1, &tentry, &errorcode);
1301         if (blockindex == 0) {
1302             if (!errorcode)
1303                 errorcode = VL_NOENT;
1304             COUNT_ABO;
1305             ubik_AbortTrans(ctx.trans);
1306             if (vldbentries->nbulkentries_val)
1307                 free((char *)vldbentries->nbulkentries_val);
1308             vldbentries->nbulkentries_val = 0;
1309             vldbentries->nbulkentries_len = 0;
1310             return errorcode;
1311         }
1312         if ((errorcode =
1313             put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst, &VldbentryLast,
1314                                 vldbentries, &tentry, 0, 0, nentries,
1315                                 &allocCount))) {
1316             COUNT_ABO;
1317             ubik_AbortTrans(ctx.trans);
1318             if (vldbentries->nbulkentries_val)
1319                 free((char *)vldbentries->nbulkentries_val);
1320             vldbentries->nbulkentries_val = 0;
1321             vldbentries->nbulkentries_len = 0;
1322             return VL_SIZEEXCEEDED;
1323         }
1324     } else {
1325         afs_int32 nextblockindex = 0, count = 0, k = 0, match = 0;
1326         while ((nextblockindex =
1327                NextEntry(&ctx, nextblockindex, &tentry, &count))) {
1328             if (++pollcount > 50) {
1329 #ifndef AFS_PTHREAD_ENV
1330                 IOMGR_Poll();
1331 #endif
1332                 pollcount = 0;
1333             }
1334
1335             match = 0;
1336             if (attributes->Mask & VLLIST_SERVER) {
1337                 int serverindex;
1338                 if ((serverindex =
1339                      IpAddrToRelAddr(&ctx, attributes->server, 0)) == -1)
1340                     continue;
1341                 for (k = 0; k < NMAXNSERVERS; k++) {
1342                     if (tentry.serverNumber[k] == BADSERVERID)
1343                         break;
1344                     if (tentry.serverNumber[k] == serverindex) {
1345                         match = 1;
1346                         break;
1347                     }
1348                 }
1349                 if (!match)
1350                     continue;
1351             }
1352             if (attributes->Mask & VLLIST_PARTITION) {
1353                 if (match) {
1354                     if (tentry.serverPartition[k] != attributes->partition)
1355                         continue;
1356                 } else {
1357                     for (k = 0; k < NMAXNSERVERS; k++) {
1358                         if (tentry.serverNumber[k] == BADSERVERID)
1359                             break;
1360                         if (tentry.serverPartition[k] ==
1361                             attributes->partition) {
1362                             match = 1;
1363                             break;
1364                         }
1365                     }
1366                     if (!match)
1367                         continue;
1368                 }
1369             }
1370
1371             if (attributes->Mask & VLLIST_FLAG) {
1372                 if (!(tentry.flags & attributes->flag))
1373                     continue;
1374             }
1375             if ((errorcode =
1376                 put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1377                                     &VldbentryLast, vldbentries, &tentry, 0,
1378                                     0, nentries, &allocCount))) {
1379                 COUNT_ABO;
1380                 ubik_AbortTrans(ctx.trans);
1381                 if (vldbentries->nbulkentries_val)
1382                     free((char *)vldbentries->nbulkentries_val);
1383                 vldbentries->nbulkentries_val = 0;
1384                 vldbentries->nbulkentries_len = 0;
1385                 return errorcode;
1386             }
1387         }
1388     }
1389     if (vldbentries->nbulkentries_len
1390         && (allocCount > vldbentries->nbulkentries_len)) {
1391
1392         vldbentries->nbulkentries_val =
1393             (nvldbentry *) realloc(vldbentries->nbulkentries_val,
1394                                    vldbentries->nbulkentries_len *
1395                                    sizeof(nvldbentry));
1396         if (vldbentries->nbulkentries_val == NULL) {
1397             COUNT_ABO;
1398             ubik_AbortTrans(ctx.trans);
1399             return VL_NOMEM;
1400         }
1401     }
1402     VLog(5,
1403          ("NListAttrs nentries=%d %s\n", vldbentries->nbulkentries_len,
1404           rxinfo(rxstr, rxcall)));
1405     return (ubik_EndTrans(ctx.trans));
1406 }
1407
1408
1409 afs_int32
1410 SVL_ListAttributesN2(struct rx_call *rxcall,
1411                      struct VldbListByAttributes *attributes,
1412                      char *name,                /* Wildcarded volume name */
1413                      afs_int32 startindex,
1414                      afs_int32 *nentries,
1415                      nbulkentries *vldbentries,
1416                      afs_int32 *nextstartindex)
1417 {
1418     int errorcode = 0, maxCount = VLDBALLOCCOUNT;
1419     struct vl_ctx ctx;
1420     struct nvlentry tentry;
1421     struct nvldbentry *Vldbentry = 0, *VldbentryFirst = 0, *VldbentryLast = 0;
1422     afs_int32 blockindex = 0, count = 0, k, match;
1423     afs_int32 matchindex = 0;
1424     int serverindex = -1;       /* no server found */
1425     int findserver = 0, findpartition = 0, findflag = 0, findname = 0;
1426     int pollcount = 0;
1427     int namematchRWBK, namematchRO, thismatch;
1428     int matchtype = 0;
1429     char volumename[VL_MAXNAMELEN+2]; /* regex anchors */
1430     char rxstr[AFS_RXINFO_LEN];
1431 #ifdef HAVE_POSIX_REGEX
1432     regex_t re;
1433     int need_regfree = 0;
1434 #else
1435     char *t;
1436 #endif
1437
1438     COUNT_REQ(VLLISTATTRIBUTESN2);
1439     vldbentries->nbulkentries_val = 0;
1440     vldbentries->nbulkentries_len = 0;
1441     *nentries = 0;
1442     *nextstartindex = -1;
1443
1444     errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op);
1445     if (errorcode)
1446         return errorcode;
1447
1448     Vldbentry = VldbentryFirst = vldbentries->nbulkentries_val =
1449         (nvldbentry *) malloc(maxCount * sizeof(nvldbentry));
1450     if (Vldbentry == NULL) {
1451         COUNT_ABO;
1452         ubik_AbortTrans(ctx.trans);
1453         return VL_NOMEM;
1454     }
1455
1456     VldbentryLast = VldbentryFirst + maxCount;
1457
1458     /* Handle the attribute by volume id totally separate of the rest
1459      * (thus additional Mask values are ignored if VLLIST_VOLUMEID is set!)
1460      */
1461     if (attributes->Mask & VLLIST_VOLUMEID) {
1462         blockindex =
1463             FindByID(&ctx, attributes->volumeid, -1, &tentry, &errorcode);
1464         if (blockindex == 0) {
1465             if (!errorcode)
1466                 errorcode = VL_NOENT;
1467         } else {
1468             errorcode =
1469                 put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1470                                     &VldbentryLast, vldbentries, &tentry, 0,
1471                                     0, nentries, &maxCount);
1472             if (errorcode)
1473                 goto done;
1474         }
1475     }
1476
1477     /* Search each entry in the database and return all entries
1478      * that match the request. It checks volumename (with
1479      * wildcarding), entry flags, server, and partition.
1480      */
1481     else {
1482         /* Get the server index for matching server address */
1483         if (attributes->Mask & VLLIST_SERVER) {
1484             serverindex =
1485                 IpAddrToRelAddr(&ctx, attributes->server, 0);
1486             if (serverindex == -1)
1487                 goto done;
1488             findserver = 1;
1489         }
1490         findpartition = ((attributes->Mask & VLLIST_PARTITION) ? 1 : 0);
1491         findflag = ((attributes->Mask & VLLIST_FLAG) ? 1 : 0);
1492         if (name && (strcmp(name, ".*") != 0) && (strcmp(name, "") != 0)) {
1493             sprintf(volumename, "^%s$", name);
1494 #ifdef HAVE_POSIX_REGEX
1495             if (regcomp(&re, volumename, REG_NOSUB) != 0) {
1496                 errorcode = VL_BADNAME;
1497                 goto done;
1498             }
1499             need_regfree = 1;
1500 #else
1501             t = (char *)re_comp(volumename);
1502             if (t) {
1503                 errorcode = VL_BADNAME;
1504                 goto done;
1505             }
1506 #endif
1507             findname = 1;
1508         }
1509
1510         /* Read each entry and see if it is the one we want */
1511         blockindex = startindex;
1512         while ((blockindex = NextEntry(&ctx, blockindex, &tentry, &count))) {
1513             if (++pollcount > 50) {
1514 #ifndef AFS_PTHREAD_ENV
1515                 IOMGR_Poll();
1516 #endif
1517                 pollcount = 0;
1518             }
1519
1520             /* Step through each server index searching for a match.
1521              * Match to an existing RW, BK, or RO volume name (preference
1522              * is in this order). Remember which index we matched against.
1523              */
1524             namematchRWBK = namematchRO = 0;    /* 0->notTried; 1->match; 2->noMatch */
1525             match = 0;
1526             for (k = 0;
1527                  (k < NMAXNSERVERS
1528                   && (tentry.serverNumber[k] != BADSERVERID)); k++) {
1529                 thismatch = 0;  /* does this index match */
1530
1531                 /* Match against the RW or BK volume name. Remember
1532                  * results in namematchRWBK. Prefer RW over BK.
1533                  */
1534                 if (tentry.serverFlags[k] & VLSF_RWVOL) {
1535                     /* Does the name match the RW name */
1536                     if (tentry.flags & VLF_RWEXISTS) {
1537                         if (findname) {
1538                             sprintf(volumename, "%s", tentry.name);
1539 #ifdef HAVE_POSIX_REGEX
1540                             if (regexec(&re, volumename, 0, NULL, 0) == 0) {
1541                                 thismatch = VLSF_RWVOL;
1542                             }
1543 #else
1544                             if (re_exec(volumename)) {
1545                                 thismatch = VLSF_RWVOL;
1546                             }
1547 #endif
1548                         } else {
1549                             thismatch = VLSF_RWVOL;
1550                         }
1551                     }
1552
1553                     /* Does the name match the BK name */
1554                     if (!thismatch && (tentry.flags & VLF_BACKEXISTS)) {
1555                         if (findname) {
1556                             sprintf(volumename, "%s.backup", tentry.name);
1557 #ifdef HAVE_POSIX_REGEX
1558                             if (regexec(&re, volumename, 0, NULL, 0) == 0) {
1559                                 thismatch = VLSF_BACKVOL;
1560                             }
1561 #else
1562                             if (re_exec(volumename)) {
1563                                 thismatch = VLSF_BACKVOL;
1564                             }
1565 #endif
1566                         } else {
1567                             thismatch = VLSF_BACKVOL;
1568                         }
1569                     }
1570
1571                     namematchRWBK = (thismatch ? 1 : 2);
1572                 }
1573
1574                 /* Match with the RO volume name. Compare once and
1575                  * remember results in namematchRO. Note that this will
1576                  * pick up entries marked NEWREPSITEs and DONTUSE.
1577                  */
1578                 else {
1579                     if (tentry.flags & VLF_ROEXISTS) {
1580                         if (findname) {
1581                             if (namematchRO) {
1582                                 thismatch =
1583                                     ((namematchRO == 1) ? VLSF_ROVOL : 0);
1584                             } else {
1585                                 sprintf(volumename, "%s.readonly",
1586                                         tentry.name);
1587 #ifdef HAVE_POSIX_REGEX
1588                             if (regexec(&re, volumename, 0, NULL, 0) == 0) {
1589                                 thismatch = VLSF_ROVOL;
1590                             }
1591 #else
1592                                 if (re_exec(volumename))
1593                                     thismatch = VLSF_ROVOL;
1594 #endif
1595                             }
1596                         } else {
1597                             thismatch = VLSF_ROVOL;
1598                         }
1599                     }
1600                     namematchRO = (thismatch ? 1 : 2);
1601                 }
1602
1603                 /* Is there a server match */
1604                 if (thismatch && findserver
1605                     && (tentry.serverNumber[k] != serverindex))
1606                     thismatch = 0;
1607
1608                 /* Is there a partition match */
1609                 if (thismatch && findpartition
1610                     && (tentry.serverPartition[k] != attributes->partition))
1611                     thismatch = 0;
1612
1613                 /* Is there a flag match */
1614                 if (thismatch && findflag
1615                     && !(tentry.flags & attributes->flag))
1616                     thismatch = 0;
1617
1618                 /* We found a match. Remember the index, and type */
1619                 if (thismatch) {
1620                     match = 1;
1621                     matchindex = k;
1622                     matchtype = thismatch;
1623                 }
1624
1625                 /* Since we prefer RW and BK volume matches over RO matches,
1626                  * if we have already checked the RWBK name, then we already
1627                  * found the best match and so end the search.
1628                  *
1629                  * If we tried matching against the RW, BK, and RO volume names
1630                  * and both failed, then we end the search (none will match).
1631                  */
1632                 if ((match && namematchRWBK)
1633                     || ((namematchRWBK == 2) && (namematchRO == 2)))
1634                     break;
1635             }
1636
1637             /* Passed all the tests. Take it */
1638             if (match) {
1639                 errorcode =
1640                     put_nattributeentry(&ctx, &Vldbentry, &VldbentryFirst,
1641                                         &VldbentryLast, vldbentries, &tentry,
1642                                         matchtype, matchindex, nentries,
1643                                         &maxCount);
1644                 if (errorcode)
1645                     goto done;
1646
1647                 if (*nentries >= maxCount)
1648                     break;      /* collected the max */
1649             }
1650         }
1651         *nextstartindex = (blockindex ? blockindex : -1);
1652     }
1653
1654   done:
1655 #ifdef HAVE_POSIX_REGEX
1656     if (need_regfree)
1657         regfree(&re);
1658 #endif
1659
1660     if (errorcode) {
1661         COUNT_ABO;
1662         ubik_AbortTrans(ctx.trans);
1663         if (vldbentries->nbulkentries_val)
1664             free((char *)vldbentries->nbulkentries_val);
1665         vldbentries->nbulkentries_val = 0;
1666         vldbentries->nbulkentries_len = 0;
1667         *nextstartindex = -1;
1668         return errorcode;
1669     } else {
1670         VLog(5,
1671              ("N2ListAttrs nentries=%d %s\n", vldbentries->nbulkentries_len,
1672               rxinfo(rxstr, rxcall)));
1673         return (ubik_EndTrans(ctx.trans));
1674     }
1675 }
1676
1677
1678 /* Retrieves in vldbentries all vldb entries that match the specified
1679  * attributes (by server number, partition, volume type, and flag); if
1680  * volume id is specified then the associated list for that entry is
1681  * returned. CAUTION: This could be a very expensive call since in most
1682  * cases sequential search of all vldb entries is performed.
1683  */
1684 afs_int32
1685 SVL_LinkedList(struct rx_call *rxcall,
1686                struct VldbListByAttributes *attributes,
1687                afs_int32 *nentries,
1688                vldb_list *vldbentries)
1689 {
1690     int errorcode;
1691     struct vl_ctx ctx;
1692     struct nvlentry tentry;
1693     vldblist vllist, *vllistptr;
1694     afs_int32 blockindex, count, match;
1695     afs_int32 k = 0;
1696     int serverindex;
1697     int pollcount = 0;
1698
1699     COUNT_REQ(VLLINKEDLIST);
1700     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1701         return errorcode;
1702
1703     *nentries = 0;
1704     vldbentries->node = NULL;
1705     vllistptr = &vldbentries->node;
1706
1707     /* List by volumeid */
1708     if (attributes->Mask & VLLIST_VOLUMEID) {
1709         blockindex =
1710             FindByID(&ctx, attributes->volumeid, -1, &tentry, &errorcode);
1711         if (!blockindex) {
1712             COUNT_ABO;
1713             ubik_AbortTrans(ctx.trans);
1714             return (errorcode ? errorcode : VL_NOENT);
1715         }
1716
1717         vllist = (single_vldbentry *) malloc(sizeof(single_vldbentry));
1718         if (vllist == NULL) {
1719             COUNT_ABO;
1720             ubik_AbortTrans(ctx.trans);
1721             return VL_NOMEM;
1722         }
1723         vlentry_to_vldbentry(&ctx, &tentry, &vllist->VldbEntry);
1724         vllist->next_vldb = NULL;
1725
1726         *vllistptr = vllist;    /* Thread onto list */
1727         vllistptr = &vllist->next_vldb;
1728         (*nentries)++;
1729     }
1730
1731     /* Search by server, partition, and flags */
1732     else {
1733         for (blockindex = NextEntry(&ctx, 0, &tentry, &count); blockindex;
1734              blockindex = NextEntry(&ctx, blockindex, &tentry, &count)) {
1735             match = 0;
1736
1737             if (++pollcount > 50) {
1738 #ifndef AFS_PTHREAD_ENV
1739                 IOMGR_Poll();
1740 #endif
1741                 pollcount = 0;
1742             }
1743
1744             /* Does this volume exist on the desired server */
1745             if (attributes->Mask & VLLIST_SERVER) {
1746                 serverindex =
1747                     IpAddrToRelAddr(&ctx, attributes->server, 0);
1748                 if (serverindex == -1)
1749                     continue;
1750                 for (k = 0; k < OMAXNSERVERS; k++) {
1751                     if (tentry.serverNumber[k] == BADSERVERID)
1752                         break;
1753                     if (tentry.serverNumber[k] == serverindex) {
1754                         match = 1;
1755                         break;
1756                     }
1757                 }
1758                 if (!match)
1759                     continue;
1760             }
1761
1762             /* Does this volume exist on the desired partition */
1763             if (attributes->Mask & VLLIST_PARTITION) {
1764                 if (match) {
1765                     if (tentry.serverPartition[k] != attributes->partition)
1766                         match = 0;
1767                 } else {
1768                     for (k = 0; k < OMAXNSERVERS; k++) {
1769                         if (tentry.serverNumber[k] == BADSERVERID)
1770                             break;
1771                         if (tentry.serverPartition[k] ==
1772                             attributes->partition) {
1773                             match = 1;
1774                             break;
1775                         }
1776                     }
1777                 }
1778                 if (!match)
1779                     continue;
1780             }
1781
1782             /* Does this volume have the desired flags */
1783             if (attributes->Mask & VLLIST_FLAG) {
1784                 if (!(tentry.flags & attributes->flag))
1785                     continue;
1786             }
1787
1788             vllist = (single_vldbentry *) malloc(sizeof(single_vldbentry));
1789             if (vllist == NULL) {
1790                 COUNT_ABO;
1791                 ubik_AbortTrans(ctx.trans);
1792                 return VL_NOMEM;
1793             }
1794             vlentry_to_vldbentry(&ctx, &tentry, &vllist->VldbEntry);
1795             vllist->next_vldb = NULL;
1796
1797             *vllistptr = vllist;        /* Thread onto list */
1798             vllistptr = &vllist->next_vldb;
1799             (*nentries)++;
1800             if (smallMem && (*nentries >= VLDBALLOCCOUNT)) {
1801                 COUNT_ABO;
1802                 ubik_AbortTrans(ctx.trans);
1803                 return VL_SIZEEXCEEDED;
1804             }
1805         }
1806     }
1807     *vllistptr = NULL;
1808     return (ubik_EndTrans(ctx.trans));
1809 }
1810
1811 afs_int32
1812 SVL_LinkedListN(struct rx_call *rxcall,
1813                 struct VldbListByAttributes *attributes,
1814                 afs_int32 *nentries,
1815                 nvldb_list *vldbentries)
1816 {
1817     int errorcode;
1818     struct vl_ctx ctx;
1819     struct nvlentry tentry;
1820     nvldblist vllist, *vllistptr;
1821     afs_int32 blockindex, count, match;
1822     afs_int32 k = 0;
1823     int serverindex;
1824     int pollcount = 0;
1825
1826     COUNT_REQ(VLLINKEDLISTN);
1827     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1828         return errorcode;
1829
1830     *nentries = 0;
1831     vldbentries->node = NULL;
1832     vllistptr = &vldbentries->node;
1833
1834     /* List by volumeid */
1835     if (attributes->Mask & VLLIST_VOLUMEID) {
1836         blockindex =
1837             FindByID(&ctx, attributes->volumeid, -1, &tentry, &errorcode);
1838         if (!blockindex) {
1839             COUNT_ABO;
1840             ubik_AbortTrans(ctx.trans);
1841             return (errorcode ? errorcode : VL_NOENT);
1842         }
1843
1844         vllist = (single_nvldbentry *) malloc(sizeof(single_nvldbentry));
1845         if (vllist == NULL) {
1846             COUNT_ABO;
1847             ubik_AbortTrans(ctx.trans);
1848             return VL_NOMEM;
1849         }
1850         vlentry_to_nvldbentry(&ctx, &tentry, &vllist->VldbEntry);
1851         vllist->next_vldb = NULL;
1852
1853         *vllistptr = vllist;    /* Thread onto list */
1854         vllistptr = &vllist->next_vldb;
1855         (*nentries)++;
1856     }
1857
1858     /* Search by server, partition, and flags */
1859     else {
1860         for (blockindex = NextEntry(&ctx, 0, &tentry, &count); blockindex;
1861              blockindex = NextEntry(&ctx, blockindex, &tentry, &count)) {
1862             match = 0;
1863
1864             if (++pollcount > 50) {
1865 #ifndef AFS_PTHREAD_ENV
1866                 IOMGR_Poll();
1867 #endif
1868                 pollcount = 0;
1869             }
1870
1871             /* Does this volume exist on the desired server */
1872             if (attributes->Mask & VLLIST_SERVER) {
1873                 serverindex =
1874                     IpAddrToRelAddr(&ctx, attributes->server, 0);
1875                 if (serverindex == -1)
1876                     continue;
1877                 for (k = 0; k < NMAXNSERVERS; k++) {
1878                     if (tentry.serverNumber[k] == BADSERVERID)
1879                         break;
1880                     if (tentry.serverNumber[k] == serverindex) {
1881                         match = 1;
1882                         break;
1883                     }
1884                 }
1885                 if (!match)
1886                     continue;
1887             }
1888
1889             /* Does this volume exist on the desired partition */
1890             if (attributes->Mask & VLLIST_PARTITION) {
1891                 if (match) {
1892                     if (tentry.serverPartition[k] != attributes->partition)
1893                         match = 0;
1894                 } else {
1895                     for (k = 0; k < NMAXNSERVERS; k++) {
1896                         if (tentry.serverNumber[k] == BADSERVERID)
1897                             break;
1898                         if (tentry.serverPartition[k] ==
1899                             attributes->partition) {
1900                             match = 1;
1901                             break;
1902                         }
1903                     }
1904                 }
1905                 if (!match)
1906                     continue;
1907             }
1908
1909             /* Does this volume have the desired flags */
1910             if (attributes->Mask & VLLIST_FLAG) {
1911                 if (!(tentry.flags & attributes->flag))
1912                     continue;
1913             }
1914
1915             vllist = (single_nvldbentry *) malloc(sizeof(single_nvldbentry));
1916             if (vllist == NULL) {
1917                 COUNT_ABO;
1918                 ubik_AbortTrans(ctx.trans);
1919                 return VL_NOMEM;
1920             }
1921             vlentry_to_nvldbentry(&ctx, &tentry, &vllist->VldbEntry);
1922             vllist->next_vldb = NULL;
1923
1924             *vllistptr = vllist;        /* Thread onto list */
1925             vllistptr = &vllist->next_vldb;
1926             (*nentries)++;
1927             if (smallMem && (*nentries >= VLDBALLOCCOUNT)) {
1928                 COUNT_ABO;
1929                 ubik_AbortTrans(ctx.trans);
1930                 return VL_SIZEEXCEEDED;
1931             }
1932         }
1933     }
1934     *vllistptr = NULL;
1935     return (ubik_EndTrans(ctx.trans));
1936 }
1937
1938 /* Get back vldb header statistics (allocs, frees, maxvolumeid,
1939  * totalentries, etc) and dynamic statistics (number of requests and/or
1940  * aborts per remote procedure call, etc)
1941  */
1942 afs_int32
1943 SVL_GetStats(struct rx_call *rxcall,
1944              vldstats *stats,
1945              vital_vlheader *vital_header)
1946 {
1947     afs_int32 errorcode;
1948     struct vl_ctx ctx;
1949     char rxstr[AFS_RXINFO_LEN];
1950
1951     COUNT_REQ(VLGETSTATS);
1952 #ifdef  notdef
1953     /* Allow users to get statistics freely */
1954     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL)) /* Must be in 'UserList' to use */
1955         return VL_PERM;
1956 #endif
1957     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1958         return errorcode;
1959     VLog(5, ("GetStats %s\n", rxinfo(rxstr, rxcall)));
1960     memcpy((char *)vital_header, (char *)&ctx.cheader->vital_header,
1961            sizeof(vital_vlheader));
1962     memcpy((char *)stats, (char *)&dynamic_statistics, sizeof(vldstats));
1963     return (ubik_EndTrans(ctx.trans));
1964 }
1965
1966 /* Get the list of file server addresses from the VLDB.  Currently it's pretty
1967  * easy to do.  In the future, it might require a little bit of grunging
1968  * through the VLDB, but that's life.
1969  */
1970 afs_int32
1971 SVL_GetAddrs(struct rx_call *rxcall,
1972              afs_int32 Handle,
1973              afs_int32 spare2,
1974              struct VLCallBack *spare3,
1975              afs_int32 *nentries,
1976              bulkaddrs *addrsp)
1977 {
1978     afs_int32 errorcode;
1979     struct vl_ctx ctx;
1980     int nservers, i;
1981     afs_uint32 *taddrp;
1982
1983     COUNT_REQ(VLGETADDRS);
1984     addrsp->bulkaddrs_len = *nentries = 0;
1985     addrsp->bulkaddrs_val = 0;
1986     memset(spare3, 0, sizeof(struct VLCallBack));
1987
1988     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
1989         return errorcode;
1990
1991     VLog(5, ("GetAddrs\n"));
1992     addrsp->bulkaddrs_val = taddrp =
1993         (afs_uint32 *) malloc(sizeof(afs_int32) * (MAXSERVERID + 1));
1994     nservers = *nentries = addrsp->bulkaddrs_len = 0;
1995
1996     if (!taddrp) {
1997         COUNT_ABO;
1998         ubik_AbortTrans(ctx.trans);
1999         return VL_NOMEM;
2000     }
2001
2002     for (i = 0; i <= MAXSERVERID; i++) {
2003         if ((*taddrp = ntohl(ctx.cheader->IpMappedAddr[i]))) {
2004             taddrp++;
2005             nservers++;
2006         }
2007     }
2008
2009     addrsp->bulkaddrs_len = *nentries = nservers;
2010     return (ubik_EndTrans(ctx.trans));
2011 }
2012
2013 #define PADDR(addr) VLog(0,("%d.%d.%d.%d", (addr>>24)&0xff, (addr>>16)&0xff, (addr>>8) &0xff, addr&0xff));
2014
2015 afs_int32
2016 SVL_RegisterAddrs(struct rx_call *rxcall, afsUUID *uuidp, afs_int32 spare1,
2017                   bulkaddrs *addrsp)
2018 {
2019     afs_int32 code;
2020     struct vl_ctx ctx;
2021     int cnt, h, i, j, k, m, base, index;
2022     struct extentaddr *exp = 0, *tex;
2023     afsUUID tuuid;
2024     afs_uint32 addrs[VL_MAXIPADDRS_PERMH];
2025     afs_int32 fbase;
2026     int count, willChangeEntry, foundUuidEntry, willReplaceCnt;
2027     int WillReplaceEntry, WillChange[MAXSERVERID + 1];
2028     int FoundUuid = 0;
2029     int ReplaceEntry = 0;
2030     int srvidx, mhidx;
2031
2032     COUNT_REQ(VLREGADDR);
2033     if (!afsconf_SuperUser(vldb_confdir, rxcall, NULL))
2034         return (VL_PERM);
2035     if ((code = Init_VLdbase(&ctx, LOCKWRITE, this_op)))
2036         return code;
2037
2038     /* Eliminate duplicates from IP address list */
2039     for (k = 0, cnt = 0; k < addrsp->bulkaddrs_len; k++) {
2040         if (addrsp->bulkaddrs_val[k] == 0)
2041             continue;
2042         for (m = 0; m < cnt; m++) {
2043             if (addrs[m] == addrsp->bulkaddrs_val[k])
2044                 break;
2045         }
2046         if (m == cnt) {
2047             if (m == VL_MAXIPADDRS_PERMH) {
2048                 VLog(0,
2049                      ("Number of addresses exceeds %d. Cannot register IP addr 0x%x in VLDB\n",
2050                       VL_MAXIPADDRS_PERMH, addrsp->bulkaddrs_val[k]));
2051             } else {
2052                 addrs[m] = addrsp->bulkaddrs_val[k];
2053                 cnt++;
2054             }
2055         }
2056     }
2057     if (cnt <= 0) {
2058         ubik_AbortTrans(ctx.trans);
2059         return VL_INDEXERANGE;
2060     }
2061
2062     count = 0;
2063     willReplaceCnt = 0;
2064     foundUuidEntry = 0;
2065     /* For each server registered within the VLDB */
2066     for (srvidx = 0; srvidx <= MAXSERVERID; srvidx++) {
2067         willChangeEntry = 0;
2068         WillReplaceEntry = 1;
2069         if ((ctx.hostaddress[srvidx] & 0xff000000) == 0xff000000) {
2070             /* The server is registered as a multihomed */
2071             base = (ctx.hostaddress[srvidx] >> 16) & 0xff;
2072             index = ctx.hostaddress[srvidx] & 0x0000ffff;
2073             if (base >= VL_MAX_ADDREXTBLKS) {
2074                 VLog(0,
2075                      ("Internal error: Multihome extent base is too large. Base %d index %d\n",
2076                       base, index));
2077                 continue;
2078             }
2079             if (index >= VL_MHSRV_PERBLK) {
2080                 VLog(0,
2081                      ("Internal error: Multihome extent index is too large. Base %d index %d\n",
2082                       base, index));
2083                 continue;
2084             }
2085             if (!ctx.ex_addr[base]) {
2086                 VLog(0,
2087                      ("Internal error: Multihome extent does not exist. Base %d\n",
2088                       base));
2089                 continue;
2090             }
2091
2092             /* See if the addresses to register will change this server entry */
2093             exp = &ctx.ex_addr[base][index];
2094             tuuid = exp->ex_hostuuid;
2095             afs_ntohuuid(&tuuid);
2096             if (afs_uuid_equal(uuidp, &tuuid)) {
2097                 foundUuidEntry = 1;
2098                 FoundUuid = srvidx;
2099             } else {
2100                 for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2101                     if (!exp->ex_addrs[mhidx])
2102                         continue;
2103                     for (k = 0; k < cnt; k++) {
2104                         if (ntohl(exp->ex_addrs[mhidx]) == addrs[k]) {
2105                             willChangeEntry = 1;
2106                             WillChange[count] = srvidx;
2107                             break;
2108                         }
2109                     }
2110                     if (k >= cnt)
2111                         WillReplaceEntry = 0;
2112                 }
2113             }
2114         } else {
2115             /* The server is not registered as a multihomed.
2116              * See if the addresses to register will replace this server entry.
2117              */
2118             for (k = 0; k < cnt; k++) {
2119                 if (ctx.hostaddress[srvidx] == addrs[k]) {
2120                     willChangeEntry = 1;
2121                     WillChange[count] = srvidx;
2122                     WillReplaceEntry = 1;
2123                     break;
2124                 }
2125             }
2126         }
2127         if (willChangeEntry) {
2128             if (WillReplaceEntry) {
2129                 willReplaceCnt++;
2130                 ReplaceEntry = srvidx;
2131             }
2132             count++;
2133         }
2134     }
2135
2136     /* If we found the uuid in the VLDB and if we are replacing another
2137      * entire entry, then complain and fail. Also, if we did not find
2138      * the uuid in the VLDB and the IP addresses being registered was
2139      * found in more than one other entry, then we don't know which one
2140      * to replace and will complain and fail.
2141      */
2142     if ((foundUuidEntry && (willReplaceCnt > 0))
2143         || (!foundUuidEntry && (count > 1))) {
2144         VLog(0,
2145              ("The following fileserver is being registered in the VLDB:\n"));
2146         VLog(0, ("      ["));
2147         for (k = 0; k < cnt; k++) {
2148             if (k > 0)
2149                 VLog(0,(" "));
2150             PADDR(addrs[k]);
2151         }
2152         VLog(0,("]\n"));
2153
2154         if (foundUuidEntry) {
2155             VLog(0,
2156                  ("   It would have replaced the existing VLDB server entry:\n"));
2157             VLog(0, ("      entry %d: [", FoundUuid));
2158             base = (ctx.hostaddress[FoundUuid] >> 16) & 0xff;
2159             index = ctx.hostaddress[FoundUuid] & 0x0000ffff;
2160             exp = &ctx.ex_addr[base][index];
2161             for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2162                 if (!exp->ex_addrs[mhidx])
2163                     continue;
2164                 if (mhidx > 0)
2165                     VLog(0,(" "));
2166                 PADDR(ntohl(exp->ex_addrs[mhidx]));
2167             }
2168             VLog(0, ("]\n"));
2169         }
2170
2171         if (count == 1)
2172             VLog(0, ("   Yet another VLDB server entry exists:\n"));
2173         else
2174             VLog(0, ("   Yet other VLDB server entries exist:\n"));
2175         for (j = 0; j < count; j++) {
2176             srvidx = WillChange[j];
2177             VLog(0, ("      entry %d: ", srvidx));
2178             if ((ctx.hostaddress[srvidx] & 0xff000000) == 0xff000000) {
2179                 VLog(0, ("["));
2180                 base = (ctx.hostaddress[srvidx] >> 16) & 0xff;
2181                 index = ctx.hostaddress[srvidx] & 0x0000ffff;
2182                 exp = &ctx.ex_addr[base][index];
2183                 for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
2184                     if (!exp->ex_addrs[mhidx])
2185                         continue;
2186                     if (mhidx > 0)
2187                         VLog(0, (" "));
2188                     PADDR(ntohl(exp->ex_addrs[mhidx]));
2189                 }
2190                 VLog(0, ("]"));
2191             } else {
2192                 PADDR(ctx.hostaddress[srvidx]);
2193             }
2194             VLog(0, ("\n"));
2195         }
2196
2197         if (count == 1)
2198             VLog(0, ("   You must 'vos changeaddr' this other server entry\n"));
2199         else
2200             VLog(0,
2201                 ("   You must 'vos changeaddr' these other server entries\n"));
2202         if (foundUuidEntry)
2203             VLog(0,
2204                 ("   and/or remove the sysid file from the registering fileserver\n"));
2205         VLog(0, ("   before the fileserver can be registered in the VLDB.\n"));
2206
2207         ubik_AbortTrans(ctx.trans);
2208         return VL_MULTIPADDR;
2209     }
2210
2211     /* Passed the checks. Now find and update the existing mh entry, or create
2212      * a new mh entry.
2213      */
2214     if (foundUuidEntry) {
2215         /* Found the entry with same uuid. See if we need to change it */
2216         int change = 0;
2217
2218         fbase = (ctx.hostaddress[FoundUuid] >> 16) & 0xff;
2219         index = ctx.hostaddress[FoundUuid] & 0x0000ffff;
2220         exp = &ctx.ex_addr[fbase][index];
2221
2222         /* Determine if the entry has changed */
2223         for (k = 0; ((k < cnt) && !change); k++) {
2224             if (ntohl(exp->ex_addrs[k]) != addrs[k])
2225                 change = 1;
2226         }
2227         for (; ((k < VL_MAXIPADDRS_PERMH) && !change); k++) {
2228             if (exp->ex_addrs[k] != 0)
2229                 change = 1;
2230         }
2231         if (!change) {
2232             return (ubik_EndTrans(ctx.trans));
2233         }
2234     }
2235
2236     VLog(0, ("The following fileserver is being registered in the VLDB:\n"));
2237     VLog(0, ("      ["));
2238     for (k = 0; k < cnt; k++) {
2239         if (k > 0)
2240             VLog(0, (" "));
2241         PADDR(addrs[k]);
2242     }
2243     VLog(0, ("]\n"));
2244
2245     if (foundUuidEntry) {
2246         VLog(0,
2247             ("   It will replace the following existing entry in the VLDB (same uuid):\n"));
2248         VLog(0, ("      entry %d: [", FoundUuid));
2249         for (k = 0; k < VL_MAXIPADDRS_PERMH; k++) {
2250             if (exp->ex_addrs[k] == 0)
2251                 continue;
2252             if (k > 0)
2253                 VLog(0, (" "));
2254             PADDR(ntohl(exp->ex_addrs[k]));
2255         }
2256         VLog(0, ("]\n"));
2257     } else if (willReplaceCnt || (count == 1)) {
2258         /* If we are not replacing an entry and there is only one entry to change,
2259          * then we will replace that entry.
2260          */
2261         if (!willReplaceCnt) {
2262             ReplaceEntry = WillChange[0];
2263             willReplaceCnt++;
2264         }
2265
2266         /* Have an entry that needs to be replaced */
2267         if ((ctx.hostaddress[ReplaceEntry] & 0xff000000) == 0xff000000) {
2268             fbase = (ctx.hostaddress[ReplaceEntry] >> 16) & 0xff;
2269             index = ctx.hostaddress[ReplaceEntry] & 0x0000ffff;
2270             exp = &ctx.ex_addr[fbase][index];
2271
2272             VLog(0,
2273                 ("   It will replace the following existing entry in the VLDB (new uuid):\n"));
2274             VLog(0, ("      entry %d: [", ReplaceEntry));
2275             for (k = 0; k < VL_MAXIPADDRS_PERMH; k++) {
2276                 if (exp->ex_addrs[k] == 0)
2277                     continue;
2278                 if (k > 0)
2279                     VLog(0, (" "));
2280                 PADDR(ntohl(exp->ex_addrs[k]));
2281             }
2282             VLog(0, ("]\n"));
2283         } else {
2284             /* Not a mh entry. So we have to create a new mh entry and
2285              * put it on the ReplaceEntry slot of the ctx.hostaddress array.
2286              */
2287             VLog(0, ("   It will replace existing entry %d, ", ReplaceEntry));
2288             PADDR(ctx.hostaddress[ReplaceEntry]);
2289             VLog(0,(", in the VLDB (new uuid):\n"));
2290
2291             code =
2292                 FindExtentBlock(&ctx, uuidp, 1, ReplaceEntry, &exp, &fbase);
2293             if (code || !exp) {
2294                 ubik_AbortTrans(ctx.trans);
2295                 return (code ? code : VL_IO);
2296             }
2297         }
2298     } else {
2299         /* There is no entry for this server, must create a new mh entry as
2300          * well as use a new slot of the ctx.hostaddress array.
2301          */
2302         VLog(0, ("   It will create a new entry in the VLDB.\n"));
2303         code = FindExtentBlock(&ctx, uuidp, 1, -1, &exp, &fbase);
2304         if (code || !exp) {
2305             ubik_AbortTrans(ctx.trans);
2306             return (code ? code : VL_IO);
2307         }
2308     }
2309
2310     /* Now we have a mh entry to fill in. Update the uuid, bump the
2311      * uniquifier, and fill in its IP addresses.
2312      */
2313     tuuid = *uuidp;
2314     afs_htonuuid(&tuuid);
2315     exp->ex_hostuuid = tuuid;
2316     exp->ex_uniquifier = htonl(ntohl(exp->ex_uniquifier) + 1);
2317     for (k = 0; k < cnt; k++) {
2318         exp->ex_addrs[k] = htonl(addrs[k]);
2319     }
2320     for (; k < VL_MAXIPADDRS_PERMH; k++) {
2321         exp->ex_addrs[k] = 0;
2322     }
2323
2324     /* Write the new mh entry out */
2325     if (vlwrite
2326         (ctx.trans,
2327          DOFFSET(ntohl(ctx.ex_addr[0]->ex_contaddrs[fbase]),
2328                  (char *)ctx.ex_addr[fbase], (char *)exp), (char *)exp,
2329          sizeof(*exp))) {
2330         ubik_AbortTrans(ctx.trans);
2331         return VL_IO;
2332     }
2333
2334     /* Remove any common addresses from other mh entres. We know these entries
2335      * are being changed and not replaced so they are mh entries.
2336      */
2337     m = 0;
2338     for (i = 0; i < count; i++) {
2339         afs_int32 doff;
2340
2341         /* Skip the entry we replaced */
2342         if (willReplaceCnt && (WillChange[i] == ReplaceEntry))
2343             continue;
2344
2345         base = (ctx.hostaddress[WillChange[i]] >> 16) & 0xff;
2346         index = ctx.hostaddress[WillChange[i]] & 0x0000ffff;
2347         tex = &ctx.ex_addr[fbase][index];
2348
2349         if (++m == 1)
2350             VLog(0,
2351                 ("   The following existing entries in the VLDB will be updated:\n"));
2352
2353         VLog(0, ("      entry %d: [", WillChange[i]));
2354         for (h = j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
2355             if (tex->ex_addrs[j]) {
2356                 if (j > 0)
2357                     printf(" ");
2358                 PADDR(ntohl(tex->ex_addrs[j]));
2359             }
2360
2361             for (k = 0; k < cnt; k++) {
2362                 if (ntohl(tex->ex_addrs[j]) == addrs[k])
2363                     break;
2364             }
2365             if (k >= cnt) {
2366                 /* Not found, so we keep it */
2367                 tex->ex_addrs[h] = tex->ex_addrs[j];
2368                 h++;
2369             }
2370         }
2371         for (j = h; j < VL_MAXIPADDRS_PERMH; j++) {
2372             tex->ex_addrs[j] = 0;       /* zero rest of mh entry */
2373         }
2374         VLog(0, ("]\n"));
2375
2376         /* Write out the modified mh entry */
2377         tex->ex_uniquifier = htonl(ntohl(tex->ex_uniquifier) + 1);
2378         doff =
2379             DOFFSET(ntohl(ctx.ex_addr[0]->ex_contaddrs[base]),
2380                     (char *)ctx.ex_addr[base], (char *)tex);
2381         if (vlwrite(ctx.trans, doff, (char *)tex, sizeof(*tex))) {
2382             ubik_AbortTrans(ctx.trans);
2383             return VL_IO;
2384         }
2385     }
2386
2387     return (ubik_EndTrans(ctx.trans));
2388 }
2389
2390 afs_int32
2391 SVL_GetAddrsU(struct rx_call *rxcall,
2392               struct ListAddrByAttributes *attributes,
2393               afsUUID *uuidpo,
2394               afs_int32 *uniquifier,
2395               afs_int32 *nentries,
2396               bulkaddrs *addrsp)
2397 {
2398     afs_int32 errorcode, index = -1, offset;
2399     struct vl_ctx ctx;
2400     int nservers, i, j, base = 0;
2401     struct extentaddr *exp = 0;
2402     afsUUID tuuid;
2403     afs_uint32 *taddrp, taddr;
2404     char rxstr[AFS_RXINFO_LEN];
2405
2406     COUNT_REQ(VLGETADDRSU);
2407     addrsp->bulkaddrs_len = *nentries = 0;
2408     addrsp->bulkaddrs_val = 0;
2409     VLog(5, ("GetAddrsU %s\n", rxinfo(rxstr, rxcall)));
2410     if ((errorcode = Init_VLdbase(&ctx, LOCKREAD, this_op)))
2411         return errorcode;
2412
2413     if (attributes->Mask & VLADDR_IPADDR) {
2414         if (attributes->Mask & (VLADDR_INDEX | VLADDR_UUID)) {
2415             ubik_AbortTrans(ctx.trans);
2416             return VL_BADMASK;
2417         }
2418         for (base = 0; base < VL_MAX_ADDREXTBLKS; base++) {
2419             if (!ctx.ex_addr[base])
2420                 break;
2421             for (i = 1; i < VL_MHSRV_PERBLK; i++) {
2422                 exp = &ctx.ex_addr[base][i];
2423                 tuuid = exp->ex_hostuuid;
2424                 afs_ntohuuid(&tuuid);
2425                 if (afs_uuid_is_nil(&tuuid))
2426                     continue;
2427                 for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
2428                     if (exp->ex_addrs[j]
2429                         && (ntohl(exp->ex_addrs[j]) == attributes->ipaddr)) {
2430                         break;
2431                     }
2432                 }
2433                 if (j < VL_MAXIPADDRS_PERMH)
2434                     break;
2435             }
2436             if (i < VL_MHSRV_PERBLK)
2437                 break;
2438         }
2439         if (base >= VL_MAX_ADDREXTBLKS) {
2440             ubik_AbortTrans(ctx.trans);
2441             return VL_NOENT;
2442         }
2443     } else if (attributes->Mask & VLADDR_INDEX) {
2444         if (attributes->Mask & (VLADDR_IPADDR | VLADDR_UUID)) {
2445             ubik_AbortTrans(ctx.trans);
2446             return VL_BADMASK;
2447         }
2448         index = attributes->index;
2449         if (index < 1 || index >= (VL_MAX_ADDREXTBLKS * VL_MHSRV_PERBLK)) {
2450             ubik_AbortTrans(ctx.trans);
2451             return VL_INDEXERANGE;
2452         }
2453         base = index / VL_MHSRV_PERBLK;
2454         offset = index % VL_MHSRV_PERBLK;
2455         if (offset == 0) {
2456             ubik_AbortTrans(ctx.trans);
2457             return VL_NOENT;
2458         }
2459         if (!ctx.ex_addr[base]) {
2460             ubik_AbortTrans(ctx.trans);
2461             return VL_INDEXERANGE;
2462         }
2463         exp = &ctx.ex_addr[base][offset];
2464     } else if (attributes->Mask & VLADDR_UUID) {
2465         if (attributes->Mask & (VLADDR_IPADDR | VLADDR_INDEX)) {
2466             ubik_AbortTrans(ctx.trans);
2467             return VL_BADMASK;
2468         }
2469         if (!ctx.ex_addr[0]) {  /* mh servers probably aren't setup on this vldb */
2470             ubik_AbortTrans(ctx.trans);
2471             return VL_NOENT;
2472         }
2473         if ((errorcode =
2474             FindExtentBlock(&ctx, &attributes->uuid, 0, -1, &exp, &base))) {
2475             ubik_AbortTrans(ctx.trans);
2476             return errorcode;
2477         }
2478     } else {
2479         ubik_AbortTrans(ctx.trans);
2480         return VL_BADMASK;
2481     }
2482
2483     if (exp == NULL) {
2484         ubik_AbortTrans(ctx.trans);
2485         return VL_NOENT;
2486     }
2487     addrsp->bulkaddrs_val = taddrp =
2488         (afs_uint32 *) malloc(sizeof(afs_int32) * (MAXSERVERID + 1));
2489     nservers = *nentries = addrsp->bulkaddrs_len = 0;
2490     if (!taddrp) {
2491         COUNT_ABO;
2492         ubik_AbortTrans(ctx.trans);
2493         return VL_NOMEM;
2494     }
2495     tuuid = exp->ex_hostuuid;
2496     afs_ntohuuid(&tuuid);
2497     if (afs_uuid_is_nil(&tuuid)) {
2498         ubik_AbortTrans(ctx.trans);
2499         return VL_NOENT;
2500     }
2501     if (uuidpo)
2502         *uuidpo = tuuid;
2503     if (uniquifier)
2504         *uniquifier = ntohl(exp->ex_uniquifier);
2505     for (i = 0; i < VL_MAXIPADDRS_PERMH; i++) {
2506         if (exp->ex_addrs[i]) {
2507             taddr = ntohl(exp->ex_addrs[i]);
2508             /* Weed out duplicates */
2509             for (j = 0; j < nservers; j++) {
2510                 if (taddrp[j] == taddr)
2511                     break;
2512             }
2513             if ((j == nservers) && (j <= MAXSERVERID)) {
2514                 taddrp[nservers] = taddr;
2515                 nservers++;
2516             }
2517         }
2518     }
2519     addrsp->bulkaddrs_len = *nentries = nservers;
2520     return (ubik_EndTrans(ctx.trans));
2521 }
2522
2523 /* ============> End of Exported vldb RPC functions <============= */
2524
2525
2526 /* Routine that copies the given vldb entry to the output buffer, vldbentries. */
2527 static int
2528 put_attributeentry(struct vl_ctx *ctx,
2529                    struct vldbentry **Vldbentry,
2530                    struct vldbentry **VldbentryFirst,
2531                    struct vldbentry **VldbentryLast,
2532                    bulkentries *vldbentries,
2533                    struct nvlentry *entry,
2534                    afs_int32 *nentries,
2535                    afs_int32 *alloccnt)
2536 {
2537     vldbentry *reall;
2538     afs_int32 allo;
2539
2540     if (*Vldbentry == *VldbentryLast) {
2541         if (smallMem)
2542             return VL_SIZEEXCEEDED;     /* no growing if smallMem defined */
2543
2544         /* Allocate another set of memory; each time allocate twice as
2545          * many blocks as the last time. When we reach VLDBALLOCLIMIT,
2546          * then grow in increments of VLDBALLOCINCR.
2547          */
2548         allo = (*alloccnt > VLDBALLOCLIMIT) ? VLDBALLOCINCR : *alloccnt;
2549         reall =
2550             (vldbentry *) realloc(*VldbentryFirst,
2551                                   (*alloccnt + allo) * sizeof(vldbentry));
2552         if (reall == NULL)
2553             return VL_NOMEM;
2554
2555         *VldbentryFirst = vldbentries->bulkentries_val = reall;
2556         *Vldbentry = *VldbentryFirst + *alloccnt;
2557         *VldbentryLast = *Vldbentry + allo;
2558         *alloccnt += allo;
2559     }
2560     vlentry_to_vldbentry(ctx, entry, *Vldbentry);
2561     (*Vldbentry)++;
2562     (*nentries)++;
2563     vldbentries->bulkentries_len++;
2564     return 0;
2565 }
2566
2567 static int
2568 put_nattributeentry(struct vl_ctx *ctx,
2569                     struct nvldbentry **Vldbentry,
2570                     struct nvldbentry **VldbentryFirst,
2571                     struct nvldbentry **VldbentryLast,
2572                     nbulkentries *vldbentries,
2573                     struct nvlentry *entry,
2574                     afs_int32 matchtype,
2575                     afs_int32 matchindex,
2576                     afs_int32 *nentries,
2577                     afs_int32 *alloccnt)
2578 {
2579     nvldbentry *reall;
2580     afs_int32 allo;
2581
2582     if (*Vldbentry == *VldbentryLast) {
2583         if (smallMem)
2584             return VL_SIZEEXCEEDED;     /* no growing if smallMem defined */
2585
2586         /* Allocate another set of memory; each time allocate twice as
2587          * many blocks as the last time. When we reach VLDBALLOCLIMIT,
2588          * then grow in increments of VLDBALLOCINCR.
2589          */
2590         allo = (*alloccnt > VLDBALLOCLIMIT) ? VLDBALLOCINCR : *alloccnt;
2591         reall =
2592             (nvldbentry *) realloc(*VldbentryFirst,
2593                                    (*alloccnt + allo) * sizeof(nvldbentry));
2594         if (reall == NULL)
2595             return VL_NOMEM;
2596
2597         *VldbentryFirst = vldbentries->nbulkentries_val = reall;
2598         *Vldbentry = *VldbentryFirst + *alloccnt;
2599         *VldbentryLast = *Vldbentry + allo;
2600         *alloccnt += allo;
2601     }
2602     vlentry_to_nvldbentry(ctx, entry, *Vldbentry);
2603     (*Vldbentry)->matchindex = (matchtype << 16) + matchindex;
2604     (*Vldbentry)++;
2605     (*nentries)++;
2606     vldbentries->nbulkentries_len++;
2607     return 0;
2608 }
2609
2610
2611 /* Common code to actually remove a vldb entry from the database. */
2612 static int
2613 RemoveEntry(struct vl_ctx *ctx, afs_int32 entryptr,
2614             struct nvlentry *tentry)
2615 {
2616     int errorcode;
2617
2618     if ((errorcode = UnthreadVLentry(ctx, entryptr, tentry)))
2619         return errorcode;
2620     if ((errorcode = FreeBlock(ctx, entryptr)))
2621         return errorcode;
2622     return 0;
2623 }
2624
2625 static void
2626 ReleaseEntry(struct nvlentry *tentry, afs_int32 releasetype)
2627 {
2628     if (releasetype & LOCKREL_TIMESTAMP)
2629         tentry->LockTimestamp = 0;
2630     if (releasetype & LOCKREL_OPCODE)
2631         tentry->flags &= ~VLOP_ALLOPERS;
2632     if (releasetype & LOCKREL_AFSID)
2633         tentry->LockAfsId = 0;
2634 }
2635
2636
2637 /* Verify that the incoming vldb entry is valid; multi type of error codes
2638  * are returned. */
2639 static int
2640 check_vldbentry(struct vldbentry *aentry)
2641 {
2642     afs_int32 i;
2643
2644     if (InvalidVolname(aentry->name))
2645         return VL_BADNAME;
2646     if (aentry->nServers <= 0 || aentry->nServers > OMAXNSERVERS)
2647         return VL_BADSERVER;
2648     for (i = 0; i < aentry->nServers; i++) {
2649 /*      if (aentry->serverNumber[i] < 0 || aentry->serverNumber[i] > MAXSERVERID)
2650             return VL_BADSERVER;        */
2651         if (aentry->serverPartition[i] < 0
2652             || aentry->serverPartition[i] > MAXPARTITIONID)
2653             return VL_BADPARTITION;
2654         if (aentry->serverFlags[i] < 0
2655             || aentry->serverFlags[i] > MAXSERVERFLAG)
2656             return VL_BADSERVERFLAG;
2657     }
2658     return 0;
2659 }
2660
2661 static int
2662 check_nvldbentry(struct nvldbentry *aentry)
2663 {
2664     afs_int32 i;
2665
2666     if (InvalidVolname(aentry->name))
2667         return VL_BADNAME;
2668     if (aentry->nServers <= 0 || aentry->nServers > NMAXNSERVERS)
2669         return VL_BADSERVER;
2670     for (i = 0; i < aentry->nServers; i++) {
2671 /*      if (aentry->serverNumber[i] < 0 || aentry->serverNumber[i] > MAXSERVERID)
2672             return VL_BADSERVER;        */
2673         if (aentry->serverPartition[i] < 0
2674             || aentry->serverPartition[i] > MAXPARTITIONID)
2675             return VL_BADPARTITION;
2676         if (aentry->serverFlags[i] < 0
2677             || aentry->serverFlags[i] > MAXSERVERFLAG)
2678             return VL_BADSERVERFLAG;
2679     }
2680     return 0;
2681 }
2682
2683
2684 /* Convert from the external vldb entry representation to its internal
2685    (more compact) form.  This call should not change the hash chains! */
2686 static int
2687 vldbentry_to_vlentry(struct vl_ctx *ctx,
2688                      struct vldbentry *VldbEntry,
2689                      struct nvlentry *VlEntry)
2690 {
2691     int i, serverindex;
2692
2693     if (strcmp(VlEntry->name, VldbEntry->name))
2694         strncpy(VlEntry->name, VldbEntry->name, sizeof(VlEntry->name));
2695     for (i = 0; i < VldbEntry->nServers; i++) {
2696         serverindex = IpAddrToRelAddr(ctx, VldbEntry->serverNumber[i], 1);
2697         if (serverindex == -1)
2698             return VL_BADSERVER;
2699         VlEntry->serverNumber[i] = serverindex;
2700         VlEntry->serverPartition[i] = VldbEntry->serverPartition[i];
2701         VlEntry->serverFlags[i] = VldbEntry->serverFlags[i];
2702     }
2703     for (; i < OMAXNSERVERS; i++)
2704         VlEntry->serverNumber[i] = VlEntry->serverPartition[i] =
2705             VlEntry->serverFlags[i] = BADSERVERID;
2706     for (i = 0; i < MAXTYPES; i++)
2707         VlEntry->volumeId[i] = VldbEntry->volumeId[i];
2708     VlEntry->cloneId = VldbEntry->cloneId;
2709     VlEntry->flags = VldbEntry->flags;
2710     return 0;
2711 }
2712
2713 static int
2714 nvldbentry_to_vlentry(struct vl_ctx *ctx,
2715                       struct nvldbentry *VldbEntry,
2716                       struct nvlentry *VlEntry)
2717 {
2718     int i, serverindex;
2719
2720     if (strcmp(VlEntry->name, VldbEntry->name))
2721         strncpy(VlEntry->name, VldbEntry->name, sizeof(VlEntry->name));
2722     for (i = 0; i < VldbEntry->nServers; i++) {
2723         serverindex = IpAddrToRelAddr(ctx, VldbEntry->serverNumber[i], 1);
2724         if (serverindex == -1)
2725             return VL_BADSERVER;
2726         VlEntry->serverNumber[i] = serverindex;
2727         VlEntry->serverPartition[i] = VldbEntry->serverPartition[i];
2728         VlEntry->serverFlags[i] = VldbEntry->serverFlags[i];
2729     }
2730     for (; i < NMAXNSERVERS; i++)
2731         VlEntry->serverNumber[i] = VlEntry->serverPartition[i] =
2732             VlEntry->serverFlags[i] = BADSERVERID;
2733     for (i = 0; i < MAXTYPES; i++)
2734         VlEntry->volumeId[i] = VldbEntry->volumeId[i];
2735     VlEntry->cloneId = VldbEntry->cloneId;
2736     VlEntry->flags = VldbEntry->flags;
2737     return 0;
2738 }
2739
2740
2741 /* Update the vldb entry with the new fields as indicated by the value of
2742  * the Mask entry in the updateentry structure. All necessary validation
2743  * checks are performed.
2744  */
2745 static int
2746 get_vldbupdateentry(struct vl_ctx *ctx,
2747                     afs_int32 blockindex,
2748                     struct VldbUpdateEntry *updateentry,
2749                     struct nvlentry *VlEntry)
2750 {
2751     int i, j, errorcode, serverindex;
2752     afs_uint32 checkids[MAXTYPES];
2753
2754     /* check if any specified new IDs are already present in the db. Do
2755      * this check before doing anything else, so we don't get a half-
2756      * updated entry. */
2757     memset(&checkids, 0, sizeof(checkids));
2758     if (updateentry->Mask & VLUPDATE_RWID) {
2759         checkids[RWVOL] = updateentry->spares3; /* rw id */
2760     }
2761     if (updateentry->Mask & VLUPDATE_READONLYID) {
2762         checkids[ROVOL] = updateentry->ReadOnlyId;
2763     }
2764     if (updateentry->Mask & VLUPDATE_BACKUPID) {
2765         checkids[BACKVOL] = updateentry->BackupId;
2766     }
2767
2768     if (EntryIDExists(ctx, checkids, MAXTYPES, &errorcode)) {
2769         return VL_IDEXIST;
2770     } else if (errorcode) {
2771         return errorcode;
2772     }
2773
2774     if (updateentry->Mask & VLUPDATE_VOLUMENAME) {
2775         struct nvlentry tentry;
2776
2777         if (InvalidVolname(updateentry->name))
2778             return VL_BADNAME;
2779
2780         if (FindByName(ctx, updateentry->name, &tentry, &errorcode)) {
2781             return VL_NAMEEXIST;
2782         } else if (errorcode) {
2783             return errorcode;
2784         }
2785
2786         if ((errorcode = UnhashVolname(ctx, blockindex, VlEntry)))
2787             return errorcode;
2788         strncpy(VlEntry->name, updateentry->name, sizeof(VlEntry->name));
2789         HashVolname(ctx, blockindex, VlEntry);
2790     }
2791
2792     if (updateentry->Mask & VLUPDATE_VOLNAMEHASH) {
2793         if ((errorcode = UnhashVolname(ctx, blockindex, VlEntry))) {
2794             if (errorcode != VL_NOENT)
2795                 return errorcode;
2796         }
2797         HashVolname(ctx, blockindex, VlEntry);
2798     }
2799
2800     if (updateentry->Mask & VLUPDATE_FLAGS) {
2801         VlEntry->flags = updateentry->flags;
2802     }
2803     if (updateentry->Mask & VLUPDATE_CLONEID) {
2804         VlEntry->cloneId = updateentry->cloneId;
2805     }
2806     if (updateentry->Mask & VLUPDATE_RWID) {
2807         if ((errorcode = UnhashVolid(ctx, RWVOL, blockindex, VlEntry))) {
2808             if (errorcode != VL_NOENT)
2809                 return errorcode;
2810         }
2811         VlEntry->volumeId[RWVOL] = updateentry->spares3;        /* rw id */
2812         if ((errorcode = HashVolid(ctx, RWVOL, blockindex, VlEntry)))
2813             return errorcode;
2814     }
2815     if (updateentry->Mask & VLUPDATE_READONLYID) {
2816         if ((errorcode = UnhashVolid(ctx, ROVOL, blockindex, VlEntry))) {
2817             if (errorcode != VL_NOENT)
2818                 return errorcode;
2819         }
2820         VlEntry->volumeId[ROVOL] = updateentry->ReadOnlyId;
2821         if ((errorcode = HashVolid(ctx, ROVOL, blockindex, VlEntry)))
2822             return errorcode;
2823     }
2824     if (updateentry->Mask & VLUPDATE_BACKUPID) {
2825         if ((errorcode = UnhashVolid(ctx, BACKVOL, blockindex, VlEntry))) {
2826             if (errorcode != VL_NOENT)
2827                 return errorcode;
2828         }
2829         VlEntry->volumeId[BACKVOL] = updateentry->BackupId;
2830         if ((errorcode = HashVolid(ctx, BACKVOL, blockindex, VlEntry)))
2831             return errorcode;
2832     }
2833     if (updateentry->Mask & VLUPDATE_REPSITES) {
2834         if (updateentry->nModifiedRepsites <= 0
2835             || updateentry->nModifiedRepsites > OMAXNSERVERS)
2836             return VL_BADSERVER;
2837         for (i = 0; i < updateentry->nModifiedRepsites; i++) {
2838 /*          if (updateentry->RepsitesTargetServer[i] < 0 || updateentry->RepsitesTargetServer[i] > MAXSERVERID)
2839                 return VL_BADSERVER;    */
2840             if (updateentry->RepsitesTargetPart[i] < 0
2841                 || updateentry->RepsitesTargetPart[i] > MAXPARTITIONID)
2842                 return VL_BADPARTITION;
2843             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_DELETE) {
2844                 if ((j =
2845                      repsite_exists(VlEntry,
2846                                     IpAddrToRelAddr(ctx, updateentry->
2847                                                     RepsitesTargetServer[i],
2848                                                     1),
2849                                     updateentry->RepsitesTargetPart[i])) !=
2850                     -1)
2851                     repsite_compress(VlEntry, j);
2852                 else
2853                     return VL_NOREPSERVER;
2854             }
2855             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_ADD) {
2856 /*              if (updateentry->RepsitesNewServer[i] < 0 || updateentry->RepsitesNewServer[i] > MAXSERVERID)
2857                     return VL_BADSERVER;                */
2858                 if (updateentry->RepsitesNewPart[i] < 0
2859                     || updateentry->RepsitesNewPart[i] > MAXPARTITIONID)
2860                     return VL_BADPARTITION;
2861                 if (repsite_exists
2862                     (VlEntry,
2863                      IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i], 1),
2864                      updateentry->RepsitesNewPart[i]) != -1)
2865                     return VL_DUPREPSERVER;
2866                 for (j = 0;
2867                      VlEntry->serverNumber[j] != BADSERVERID
2868                      && j < OMAXNSERVERS; j++);
2869                 if (j >= OMAXNSERVERS)
2870                     return VL_REPSFULL;
2871                 if ((serverindex =
2872                      IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i],
2873                                      1)) == -1)
2874                     return VL_BADSERVER;
2875                 VlEntry->serverNumber[j] = serverindex;
2876                 VlEntry->serverPartition[j] = updateentry->RepsitesNewPart[i];
2877                 if (updateentry->RepsitesNewFlags[i] < 0
2878                     || updateentry->RepsitesNewFlags[i] > MAXSERVERFLAG)
2879                     return VL_BADSERVERFLAG;
2880                 VlEntry->serverFlags[j] = updateentry->RepsitesNewFlags[i];
2881             }
2882             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODSERV) {
2883 /*n             if (updateentry->RepsitesNewServer[i] < 0 || updateentry->RepsitesNewServer[i] > MAXSERVERID)
2884                     return VL_BADSERVER;            */
2885                 if ((j =
2886                      repsite_exists(VlEntry,
2887                                     IpAddrToRelAddr(ctx, updateentry->
2888                                                     RepsitesTargetServer[i],
2889                                                     1),
2890                                     updateentry->RepsitesTargetPart[i])) !=
2891                     -1) {
2892                     VlEntry->serverNumber[j] =
2893                         IpAddrToRelAddr(ctx, updateentry->RepsitesNewServer[i],
2894                                         1);
2895                 } else
2896                     return VL_NOREPSERVER;
2897             }
2898             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODPART) {
2899                 if (updateentry->RepsitesNewPart[i] < 0
2900                     || updateentry->RepsitesNewPart[i] > MAXPARTITIONID)
2901                     return VL_BADPARTITION;
2902                 if ((j =
2903                      repsite_exists(VlEntry,
2904                                     IpAddrToRelAddr(ctx, updateentry->
2905                                                     RepsitesTargetServer[i],
2906                                                     1),
2907                                     updateentry->RepsitesTargetPart[i])) !=
2908                     -1)
2909                     VlEntry->serverPartition[j] =
2910                         updateentry->RepsitesNewPart[i];
2911                 else
2912                     return VL_NOREPSERVER;
2913             }
2914             if (updateentry->RepsitesMask[i] & VLUPDATE_REPS_MODFLAG) {
2915                 if ((j =
2916                      repsite_exists(VlEntry,
2917                                     IpAddrToRelAddr(ctx, updateentry->
2918                                                     RepsitesTargetServer[i],
2919                                                     1),
2920                                     updateentry->RepsitesTargetPart[i])) !=
2921                     -1) {
2922                     if (updateentry->RepsitesNewFlags[i] < 0
2923                         || updateentry->RepsitesNewFlags[i] > MAXSERVERFLAG)
2924                         return VL_BADSERVERFLAG;
2925                     VlEntry->serverFlags[j] =
2926                         updateentry->RepsitesNewFlags[i];
2927                 } else
2928                     return VL_NOREPSERVER;
2929             }
2930         }
2931     }
2932     return 0;
2933 }
2934
2935
2936 /* Check if the specified [server,partition] entry is found in the vldb
2937  * entry's repsite table; it's offset in the table is returned, if it's
2938  * present there. */
2939 static int
2940 repsite_exists(struct nvlentry *VlEntry, int server, int partition)
2941 {
2942     int i;
2943
2944     for (i = 0; VlEntry->serverNumber[i] != BADSERVERID && i < OMAXNSERVERS;
2945          i++) {
2946         if ((VlEntry->serverNumber[i] == server)
2947             && (VlEntry->serverPartition[i] == partition))
2948             return i;
2949     }
2950     return -1;
2951 }
2952
2953
2954
2955 /* Repsite table compression: used when deleting a repsite entry so that
2956  * all active repsite entries are on the top of the table. */
2957 static void
2958 repsite_compress(struct nvlentry *VlEntry, int offset)
2959 {
2960     int repsite_offset = offset;
2961     for (;
2962          VlEntry->serverNumber[repsite_offset] != BADSERVERID
2963          && repsite_offset < OMAXNSERVERS - 1; repsite_offset++) {
2964         VlEntry->serverNumber[repsite_offset] =
2965             VlEntry->serverNumber[repsite_offset + 1];
2966         VlEntry->serverPartition[repsite_offset] =
2967             VlEntry->serverPartition[repsite_offset + 1];
2968         VlEntry->serverFlags[repsite_offset] =
2969             VlEntry->serverFlags[repsite_offset + 1];
2970     }
2971     VlEntry->serverNumber[repsite_offset] = BADSERVERID;
2972 }
2973
2974
2975 /* Convert from the internal (compacted) vldb entry to the external
2976  * representation used by the interface. */
2977 static void
2978 vlentry_to_vldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
2979                      struct vldbentry *VldbEntry)
2980 {
2981     int i, j;
2982
2983     memset(VldbEntry, 0, sizeof(struct vldbentry));
2984     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
2985     for (i = 0; i < OMAXNSERVERS; i++) {
2986         if (VlEntry->serverNumber[i] == BADSERVERID)
2987             break;
2988         if ((ctx->hostaddress[j = VlEntry->serverNumber[i]] & 0xff000000) ==
2989             0xff000000) {
2990             struct extentaddr *exp;
2991             int base, index;
2992
2993             base = (ctx->hostaddress[j] >> 16) & 0xff;
2994             index = ctx->hostaddress[j] & 0x0000ffff;
2995             exp = &ctx->ex_addr[base][index];
2996             /* For now return the first ip address back */
2997             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
2998                 if (exp->ex_addrs[j]) {
2999                     VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[j]);
3000                     break;
3001                 }
3002             }
3003         } else
3004             VldbEntry->serverNumber[i] =
3005                 ctx->hostaddress[VlEntry->serverNumber[i]];
3006         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3007         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3008     }
3009     VldbEntry->nServers = i;
3010     for (i = 0; i < MAXTYPES; i++)
3011         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3012     VldbEntry->cloneId = VlEntry->cloneId;
3013     VldbEntry->flags = VlEntry->flags;
3014 }
3015
3016
3017 /* Convert from the internal (compacted) vldb entry to the external
3018  * representation used by the interface. */
3019 static void
3020 vlentry_to_nvldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
3021                       struct nvldbentry *VldbEntry)
3022 {
3023     int i, j;
3024
3025     memset(VldbEntry, 0, sizeof(struct vldbentry));
3026     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
3027     for (i = 0; i < NMAXNSERVERS; i++) {
3028         if (VlEntry->serverNumber[i] == BADSERVERID)
3029             break;
3030         if ((ctx->hostaddress[j = VlEntry->serverNumber[i]] & 0xff000000) ==
3031             0xff000000) {
3032             struct extentaddr *exp;
3033             int base, index;
3034
3035             base = (ctx->hostaddress[j] >> 16) & 0xff;
3036             index = ctx->hostaddress[j] & 0x0000ffff;
3037             exp = &ctx->ex_addr[base][index];
3038             /* For now return the first ip address back */
3039             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
3040                 if (exp->ex_addrs[j]) {
3041                     VldbEntry->serverNumber[i] = ntohl(exp->ex_addrs[j]);
3042                     break;
3043                 }
3044             }
3045         } else
3046             VldbEntry->serverNumber[i] =
3047                 ctx->hostaddress[VlEntry->serverNumber[i]];
3048         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3049         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3050     }
3051     VldbEntry->nServers = i;
3052     for (i = 0; i < MAXTYPES; i++)
3053         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3054     VldbEntry->cloneId = VlEntry->cloneId;
3055     VldbEntry->flags = VlEntry->flags;
3056 }
3057
3058 static void
3059 vlentry_to_uvldbentry(struct vl_ctx *ctx, struct nvlentry *VlEntry,
3060                       struct uvldbentry *VldbEntry)
3061 {
3062     int i, j;
3063
3064     memset(VldbEntry, 0, sizeof(struct vldbentry));
3065     strncpy(VldbEntry->name, VlEntry->name, sizeof(VldbEntry->name));
3066     for (i = 0; i < NMAXNSERVERS; i++) {
3067         if (VlEntry->serverNumber[i] == BADSERVERID)
3068             break;
3069         VldbEntry->serverFlags[i] = VlEntry->serverFlags[i];
3070         VldbEntry->serverUnique[i] = 0;
3071         if ((ctx->hostaddress[j = VlEntry->serverNumber[i]] & 0xff000000) ==
3072             0xff000000) {
3073             struct extentaddr *exp;
3074             int base, index;
3075             afsUUID tuuid;
3076
3077             base = (ctx->hostaddress[j] >> 16) & 0xff;
3078             index = ctx->hostaddress[j] & 0x0000ffff;
3079             exp = &ctx->ex_addr[base][index];
3080             tuuid = exp->ex_hostuuid;
3081             afs_ntohuuid(&tuuid);
3082             VldbEntry->serverFlags[i] |= VLSERVER_FLAG_UUID;
3083             VldbEntry->serverNumber[i] = tuuid;
3084             VldbEntry->serverUnique[i] = ntohl(exp->ex_uniquifier);
3085         } else {
3086             VldbEntry->serverNumber[i].time_low =
3087                 ctx->hostaddress[VlEntry->serverNumber[i]];
3088         }
3089         VldbEntry->serverPartition[i] = VlEntry->serverPartition[i];
3090
3091     }
3092     VldbEntry->nServers = i;
3093     for (i = 0; i < MAXTYPES; i++)
3094         VldbEntry->volumeId[i] = VlEntry->volumeId[i];
3095     VldbEntry->cloneId = VlEntry->cloneId;
3096     VldbEntry->flags = VlEntry->flags;
3097 }
3098
3099 #define LEGALCHARS ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
3100
3101
3102 /* Verify that the volname is a valid volume name. */
3103 static int
3104 InvalidVolname(char *volname)
3105 {
3106     char *map;
3107     int slen;
3108
3109     map = LEGALCHARS;
3110     slen = strlen(volname);
3111     if (slen >= VL_MAXNAMELEN)
3112         return 1;
3113     return (slen != strspn(volname, map));
3114 }
3115
3116
3117 /* Verify that the given volume type is valid. */
3118 static int
3119 InvalidVoltype(afs_int32 voltype)
3120 {
3121     if (voltype != RWVOL && voltype != ROVOL && voltype != BACKVOL)
3122         return 1;
3123     return 0;
3124 }
3125
3126
3127 static int
3128 InvalidOperation(afs_int32 voloper)
3129 {
3130     if (voloper != VLOP_MOVE && voloper != VLOP_RELEASE
3131         && voloper != VLOP_BACKUP && voloper != VLOP_DELETE
3132         && voloper != VLOP_DUMP)
3133         return 1;
3134     return 0;
3135 }
3136
3137 static int
3138 InvalidReleasetype(afs_int32 releasetype)
3139 {
3140     if ((releasetype & LOCKREL_TIMESTAMP) || (releasetype & LOCKREL_OPCODE)
3141         || (releasetype & LOCKREL_AFSID))
3142         return 0;
3143     return 1;
3144 }
3145
3146 static int
3147 IpAddrToRelAddr(struct vl_ctx *ctx, afs_uint32 ipaddr, int create)
3148 {
3149     int i, j;
3150     afs_int32 code, base, index;
3151     struct extentaddr *exp;
3152
3153     for (i = 0; i <= MAXSERVERID; i++) {
3154         if (ctx->hostaddress[i] == ipaddr)
3155             return i;
3156         if ((ctx->hostaddress[i] & 0xff000000) == 0xff000000) {
3157             base = (ctx->hostaddress[i] >> 16) & 0xff;
3158             index = ctx->hostaddress[i] & 0x0000ffff;
3159             if (base >= VL_MAX_ADDREXTBLKS) {
3160                 VLog(0,
3161                      ("Internal error: Multihome extent base is too large. Base %d index %d\n",
3162                       base, index));
3163                 return -1;      /* EINVAL */
3164             }
3165             if (index >= VL_MHSRV_PERBLK) {
3166                 VLog(0,
3167                      ("Internal error: Multihome extent index is too large. Base %d index %d\n",
3168                       base, index));
3169                 return -1;      /* EINVAL */
3170             }
3171             if (!ctx->ex_addr[base]) {
3172                 VLog(0,
3173                      ("Internal error: Multihome extent does not exist. Base %d\n",
3174                       base));
3175                 return -1;      /* EINVAL */
3176             }
3177             exp = &ctx->ex_addr[base][index];
3178             for (j = 0; j < VL_MAXIPADDRS_PERMH; j++) {
3179                 if (exp->ex_addrs[j] && (ntohl(exp->ex_addrs[j]) == ipaddr)) {
3180                     return i;
3181                 }
3182             }
3183         }
3184     }
3185
3186     /* allocate the new server a server id pronto */
3187     if (create) {
3188         for (i = 0; i <= MAXSERVERID; i++) {
3189             if (ctx->cheader->IpMappedAddr[i] == 0) {
3190                 ctx->cheader->IpMappedAddr[i] = htonl(ipaddr);
3191                 code =
3192                     vlwrite(ctx->trans,
3193                             DOFFSET(0, ctx->cheader, &ctx->cheader->IpMappedAddr[i]),
3194                             (char *)&ctx->cheader->IpMappedAddr[i],
3195                             sizeof(afs_int32));
3196                 ctx->hostaddress[i] = ipaddr;
3197                 if (code)
3198                     return -1;
3199                 return i;
3200             }
3201         }
3202     }
3203     return -1;
3204 }
3205
3206 static int
3207 ChangeIPAddr(struct vl_ctx *ctx, afs_uint32 ipaddr1, afs_uint32 ipaddr2)
3208 {
3209     int i, j;
3210     afs_int32 code;
3211     struct extentaddr *exp = NULL;
3212     int base = 0;
3213     int index, mhidx;
3214     afsUUID tuuid;
3215     afs_int32 blockindex, count;
3216     int pollcount = 0;
3217     struct nvlentry tentry;
3218     int ipaddr1_id = -1, ipaddr2_id = -1;
3219
3220     /* Don't let addr change to 256.*.*.* : Causes internal error below */
3221     if ((ipaddr2 & 0xff000000) == 0xff000000)
3222         return (VL_BADSERVER);
3223
3224     /* If we are removing an address, ip1 will be -1 and ip2 will be
3225      * the original address. This prevents an older revision vlserver
3226      * from removing the IP address (won't find server 0xfffffff in
3227      * the VLDB). An older revision vlserver does not have the check
3228      * to see if any volumes exist on the server being removed.
3229      */
3230     if (ipaddr1 == 0xffffffff) {
3231         ipaddr1 = ipaddr2;
3232         ipaddr2 = 0;
3233     }
3234
3235     for (i = 0; i <= MAXSERVERID; i++) {
3236         if ((ctx->hostaddress[i] & 0xff000000) == 0xff000000) {
3237             base = (ctx->hostaddress[i] >> 16) & 0xff;
3238             index = ctx->hostaddress[i] & 0x0000ffff;
3239             if ((base >= VL_MAX_ADDREXTBLKS) || (index >= VL_MHSRV_PERBLK)) {
3240                 VLog(0,
3241                      ("Internal error: Multihome extent addr is too large. Base %d index %d\n",
3242                       base, index));
3243                 return -1;      /* EINVAL */
3244             }
3245
3246             exp = &ctx->ex_addr[base][index];
3247             for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
3248                 if (!exp->ex_addrs[mhidx])
3249                     continue;
3250                 if (ntohl(exp->ex_addrs[mhidx]) == ipaddr1) {
3251                     ipaddr1_id = i;
3252                 }
3253                 if (ipaddr2 != 0 && ntohl(exp->ex_addrs[mhidx]) == ipaddr2) {
3254                     ipaddr2_id = i;
3255                 }
3256             }
3257         } else {
3258             if (ctx->hostaddress[i] == ipaddr1) {
3259                 exp = NULL;
3260                 ipaddr1_id = i;
3261             }
3262             if (ipaddr2 != 0 && ctx->hostaddress[i] == ipaddr2) {
3263                 ipaddr2_id = i;
3264             }
3265         }
3266
3267         if (ipaddr1_id >= 0 && (ipaddr2 == 0 || ipaddr2_id >= 0)) {
3268             /* we've either found both IPs already in the VLDB, or we found
3269              * ipaddr1, and we're not going to find ipaddr2 because it's 0 */
3270             break;
3271         }
3272     }
3273
3274     if (ipaddr1_id < 0) {
3275         return VL_NOENT;        /* not found */
3276     }
3277
3278     if (ipaddr2_id >= 0 && ipaddr2_id != ipaddr1_id) {
3279         char buf1[16], buf2[16];
3280         VLog(0, ("Cannot change IP address from %s to %s because the latter "
3281                  "is in use by server id %d\n",
3282                  afs_inet_ntoa_r(htonl(ipaddr1), buf1),
3283                  afs_inet_ntoa_r(htonl(ipaddr2), buf2),
3284                  ipaddr2_id));
3285         return VL_MULTIPADDR;
3286     }
3287
3288     /* If we are removing a server entry, a volume cannot
3289      * exist on the server. If one does, don't remove the
3290      * server entry: return error "volume entry exists".
3291      */
3292     if (ipaddr2 == 0) {
3293         for (blockindex = NextEntry(ctx, 0, &tentry, &count); blockindex;
3294              blockindex = NextEntry(ctx, blockindex, &tentry, &count)) {
3295             if (++pollcount > 50) {
3296 #ifndef AFS_PTHREAD_ENV
3297                 IOMGR_Poll();
3298 #endif
3299                 pollcount = 0;
3300             }
3301             for (j = 0; j < NMAXNSERVERS; j++) {
3302                 if (tentry.serverNumber[j] == BADSERVERID)
3303                     break;
3304                 if (tentry.serverNumber[j] == ipaddr1_id) {
3305                     return VL_IDEXIST;
3306                 }
3307             }
3308         }
3309     }
3310
3311     /* Log a message saying we are changing/removing an IP address */
3312     VLog(0,
3313          ("The following IP address is being %s:\n",
3314           (ipaddr2 ? "changed" : "removed")));
3315     VLog(0, ("      entry %d: ", i));
3316     if (exp) {
3317         VLog(0, ("["));
3318         for (mhidx = 0; mhidx < VL_MAXIPADDRS_PERMH; mhidx++) {
3319             if (!exp->ex_addrs[mhidx])
3320                 continue;
3321             if (mhidx > 0)
3322                 VLog(0, (" "));
3323             PADDR(ntohl(exp->ex_addrs[mhidx]));
3324         }
3325         VLog(0, ("]"));
3326     } else {
3327         PADDR(ipaddr1);
3328     }
3329     if (ipaddr2) {
3330         VLog(0, (" -> "));
3331         PADDR(ipaddr2);
3332     }
3333     VLog(0, ("\n"));
3334
3335     /* Change the registered uuuid addresses */
3336     if (exp) {
3337         memset(&tuuid, 0, sizeof(afsUUID));
3338         afs_htonuuid(&tuuid);
3339         exp->ex_hostuuid = tuuid;
3340         code =
3341             vlwrite(ctx->trans,
3342                     DOFFSET(ntohl(ctx->ex_addr[0]->ex_contaddrs[base]),
3343                             (char *)ctx->ex_addr[base], (char *)exp),
3344                     (char *)&tuuid, sizeof(tuuid));
3345         if (code)
3346             return VL_IO;
3347     }
3348
3349     /* Now change the host address entry */
3350     ctx->cheader->IpMappedAddr[ipaddr1_id] = htonl(ipaddr2);
3351     code =
3352         vlwrite(ctx->trans, DOFFSET(0, ctx->cheader, &ctx->cheader->IpMappedAddr[ipaddr1_id]),
3353                 (char *)
3354                 &ctx->cheader->IpMappedAddr[ipaddr1_id], sizeof(afs_int32));
3355     ctx->hostaddress[ipaddr1_id] = ipaddr2;
3356     if (code)
3357         return VL_IO;
3358
3359     return 0;
3360 }
3361
3362 /* see if the vlserver is back yet */
3363 afs_int32
3364 SVL_ProbeServer(struct rx_call *rxcall)
3365 {
3366     return 0;
3367 }