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