Commit | Line | Data |
---|---|---|
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 | ||
32 | extern int smallMem; | |
33 | extern int restrictedQueryLevel; | |
34 | extern int extent_mod; | |
35 | extern struct afsconf_dir *vldb_confdir; | |
36 | extern struct ubik_dbase *VL_dbase; | |
37 | int 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 | ||
46 | static int put_attributeentry(struct vl_ctx *ctx, | |
47 | struct vldbentry **, struct vldbentry **, | |
48 | struct vldbentry **, bulkentries *, | |
49 | struct nvlentry *, afs_int32 *, afs_int32 *); | |
50 | static 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 *); | |
55 | static int RemoveEntry(struct vl_ctx *ctx, afs_int32 entryptr, | |
56 | struct nvlentry *tentry); | |
57 | static void ReleaseEntry(struct nvlentry *tentry, afs_int32 releasetype); | |
58 | static int check_vldbentry(struct vldbentry *aentry); | |
59 | static int check_nvldbentry(struct nvldbentry *aentry); | |
60 | static int vldbentry_to_vlentry(struct vl_ctx *ctx, | |
61 | struct vldbentry *VldbEntry, | |
62 | struct nvlentry *VlEntry); | |
63 | static int nvldbentry_to_vlentry(struct vl_ctx *ctx, | |
64 | struct nvldbentry *VldbEntry, | |
65 | struct nvlentry *VlEntry); | |
66 | static int get_vldbupdateentry(struct vl_ctx *ctx, afs_int32 blockindex, | |
67 | struct VldbUpdateEntry *updateentry, | |
68 | struct nvlentry *VlEntry); | |
69 | static int repsite_exists(struct nvlentry *VlEntry, int server, int partition); | |
70 | static void repsite_compress(struct nvlentry *VlEntry, int offset); | |
71 | static int vlentry_to_vldbentry(struct vl_ctx *ctx, | |
72 | struct nvlentry *VlEntry, | |
73 | struct vldbentry *VldbEntry); | |
74 | static int vlentry_to_nvldbentry(struct vl_ctx *ctx, | |
75 | struct nvlentry *VlEntry, | |
76 | struct nvldbentry *VldbEntry); | |
77 | static int vlentry_to_uvldbentry(struct vl_ctx *ctx, | |
78 | struct nvlentry *VlEntry, | |
79 | struct uvldbentry *VldbEntry); | |
80 | static int InvalidVolname(char *volname); | |
81 | static int InvalidVoltype(afs_int32 voltype); | |
82 | static int InvalidOperation(afs_int32 voloper); | |
83 | static int InvalidReleasetype(afs_int32 releasetype); | |
84 | static int IpAddrToRelAddr(struct vl_ctx *ctx, afs_uint32 ipaddr, int create); | |
85 | static int ChangeIPAddr(struct vl_ctx *ctx, afs_uint32 ipaddr1, | |
86 | afs_uint32 ipaddr2); | |
87 | ||
88 | static_inline void | |
89 | countRequest(int opcode) | |
90 | { | |
91 | if (opcode != 0) { | |
92 | dynamic_statistics.requests[opcode - VL_LOWEST_OPCODE]++; | |
93 | } | |
94 | } | |
95 | ||
96 | static_inline void | |
97 | countAbort(int opcode) | |
98 | { | |
99 | if (opcode != 0) { | |
100 | dynamic_statistics.aborts[opcode - VL_LOWEST_OPCODE]++; | |
101 | } | |
102 | } | |
103 | ||
104 | ||
105 | static_inline int | |
106 | multiHomedExtentBase(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 | ||
141 | static_inline int | |
142 | multiHomedExtent(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 | |
150 | static char * | |
151 | rxkadInfo(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 | ||
173 | static char * | |
174 | rxinfo(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 */ | |
197 | int | |
198 | Init_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 | ||
267 | static afs_int32 | |
268 | CreateEntry(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 | ||
334 | afs_int32 | |
335 | SVL_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 | ||
345 | static afs_int32 | |
346 | CreateEntryN(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 | ||
412 | afs_int32 | |
413 | SVL_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 | ||
423 | static afs_int32 | |
424 | ChangeAddr(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 | ||
453 | afs_int32 | |
454 | SVL_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. */ | |
465 | static afs_int32 | |
466 | DeleteEntry(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 | ||
506 | afs_int32 | |
507 | SVL_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. */ | |
519 | static int | |
520 | GetEntryByID(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 | ||
564 | abort: | |
565 | countAbort(this_op); | |
566 | ubik_AbortTrans(ctx.trans); | |
567 | return code; | |
568 | } | |
569 | ||
570 | afs_int32 | |
571 | SVL_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 | ||
580 | afs_int32 | |
581 | SVL_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 | ||
590 | afs_int32 | |
591 | SVL_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 */ | |
602 | static int | |
603 | NameIsId(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. */ | |
615 | static afs_int32 | |
616 | GetEntryByName(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 | ||
661 | abort: | |
662 | countAbort(this_op); | |
663 | ubik_AbortTrans(ctx.trans); | |
664 | return code; | |
665 | ||
666 | } | |
667 | ||
668 | afs_int32 | |
669 | SVL_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 | ||
677 | afs_int32 | |
678 | SVL_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 | ||
686 | afs_int32 | |
687 | SVL_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. */ | |
696 | static afs_int32 | |
697 | getNewVolumeId(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 | ||
736 | afs_int32 | |
737 | SVL_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 | ||
752 | static afs_int32 | |
753 | ReplaceEntry(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 | ||
874 | afs_int32 | |
875 | SVL_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 | ||
885 | static afs_int32 | |
886 | ReplaceEntryN(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 | ||
983 | afs_int32 | |
984 | SVL_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 */ | |
1000 | static afs_int32 | |
1001 | UpdateEntry(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 | ||
1049 | afs_int32 | |
1050 | SVL_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 | ||
1063 | static afs_int32 | |
1064 | UpdateEntryByName(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 | ||
1107 | afs_int32 | |
1108 | SVL_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). */ | |
1121 | static afs_int32 | |
1122 | SetLock(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 | ||
1181 | afs_int32 | |
1182 | SVL_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 | ||
1196 | static afs_int32 | |
1197 | ReleaseLock(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 | ||
1239 | afs_int32 | |
1240 | SVL_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 | */ | |
1254 | static afs_int32 | |
1255 | ListEntry(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 | ||
1287 | afs_int32 | |
1288 | SVL_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 | */ | |
1303 | static afs_int32 | |
1304 | ListEntryN(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 | ||
1336 | afs_int32 | |
1337 | SVL_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 | */ | |
1354 | static afs_int32 | |
1355 | ListAttributes(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 | ||
1477 | abort: | |
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 | ||
1488 | afs_int32 | |
1489 | SVL_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 | ||
1501 | static afs_int32 | |
1502 | ListAttributesN(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 | ||
1625 | abort: | |
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 | ||
1635 | afs_int32 | |
1636 | SVL_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 | ||
1648 | static afs_int32 | |
1649 | ListAttributesN2(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 | ||
1948 | afs_int32 | |
1949 | SVL_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 | */ | |
1971 | static afs_int32 | |
1972 | LinkedList(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 | ||
2106 | abort: | |
2107 | countAbort(this_op); | |
2108 | ubik_AbortTrans(ctx.trans); | |
2109 | return code; | |
2110 | } | |
2111 | ||
2112 | afs_int32 | |
2113 | SVL_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 | ||
2125 | static afs_int32 | |
2126 | LinkedListN(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 | ||
2260 | abort: | |
2261 | countAbort(this_op); | |
2262 | ubik_AbortTrans(ctx.trans); | |
2263 | return code; | |
2264 | } | |
2265 | ||
2266 | afs_int32 | |
2267 | SVL_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 | */ | |
2283 | static afs_int32 | |
2284 | GetStats(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 | ||
2308 | afs_int32 | |
2309 | SVL_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 | */ | |
2324 | afs_int32 | |
2325 | SVL_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 | ||
2366 | abort: | |
2367 | countAbort(this_op); | |
2368 | ubik_AbortTrans(ctx.trans); | |
2369 | return code; | |
2370 | } | |
2371 | ||
2372 | static_inline void | |
2373 | append_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 | ||
2383 | afs_int32 | |
2384 | SVL_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 | ||
2737 | abort: | |
2738 | countAbort(this_op); | |
2739 | ubik_AbortTrans(ctx.trans); | |
2740 | return code; | |
2741 | } | |
2742 | ||
2743 | afs_int32 | |
2744 | SVL_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 | ||
2864 | abort: | |
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. */ | |
2874 | static int | |
2875 | put_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 | ||
2918 | static int | |
2919 | put_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. */ | |
2966 | static int | |
2967 | RemoveEntry(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 | ||
2979 | static void | |
2980 | ReleaseEntry(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. */ | |
2993 | static int | |
2994 | check_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 | ||
3015 | static int | |
3016 | check_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! */ | |
3040 | static int | |
3041 | vldbentry_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 | ||
3067 | static int | |
3068 | nvldbentry_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 | */ | |
3099 | static int | |
3100 | get_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. */ | |
3293 | static int | |
3294 | repsite_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. */ | |
3311 | static void | |
3312 | repsite_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. */ | |
3331 | static int | |
3332 | vlentry_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. */ | |
3372 | static int | |
3373 | vlentry_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 | ||
3411 | static int | |
3412 | vlentry_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. */ | |
3457 | static int | |
3458 | InvalidVolname(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. */ | |
3472 | static int | |
3473 | InvalidVoltype(afs_int32 voltype) | |
3474 | { | |
3475 | if (voltype != RWVOL && voltype != ROVOL && voltype != BACKVOL) | |
3476 | return 1; | |
3477 | return 0; | |
3478 | } | |
3479 | ||
3480 | ||
3481 | static int | |
3482 | InvalidOperation(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 | ||
3491 | static int | |
3492 | InvalidReleasetype(afs_int32 releasetype) | |
3493 | { | |
3494 | if ((releasetype & LOCKREL_TIMESTAMP) || (releasetype & LOCKREL_OPCODE) | |
3495 | || (releasetype & LOCKREL_AFSID)) | |
3496 | return 0; | |
3497 | return 1; | |
3498 | } | |
3499 | ||
3500 | static int | |
3501 | IpAddrToRelAddr(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 | ||
3542 | static int | |
3543 | ChangeIPAddr(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 */ | |
3707 | afs_int32 | |
3708 | SVL_ProbeServer(struct rx_call *rxcall) | |
3709 | { | |
3710 | return 0; | |
3711 | } |