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