2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * This file is a reimplementation of volser/vsproc.s. Every attempt
12 * has been made to keep it as similar as possible to aid comprehension
13 * of the code. For most functions, two parameters have been added
14 * the cell handle, and a status variable. For those functions that
15 * require one, a server handle may also be added.
17 * Other changes were made to provide thread safe functions and
18 * eliminate the practice of reporting errors to STDOUT.
21 #include <afsconfig.h>
22 #include <afs/param.h>
26 #include <afs/afs_AdminErrors.h>
30 #include "lockprocs.h"
31 #include "../adminutil/afs_AdminInternal.h"
32 #include "afs_vosAdmin.h"
34 static afs_int32
GroupEntries(struct rx_connection
*server
, volintInfo
* pntr
, afs_int32 count
,
35 struct qHead
*myQueue
, afs_int32 apart
);
39 afs_int32 vldbEntryIndex
;
42 static struct rx_connection
*
43 UV_Bind(afs_cell_handle_p cellHandle
, afs_int32 aserver
, afs_int32 port
)
45 return rx_GetCachedConnection(htonl(aserver
), htons(port
), VOLSERVICE_ID
,
46 cellHandle
->tokens
->afs_sc
[cellHandle
->
49 cellHandle
->tokens
->sc_index
);
53 /* if <okvol> is allright(indicated by beibg able to
54 * start a transaction, delete the <delvol> */
56 CheckAndDeleteVolume(struct rx_connection
*aconn
, afs_int32 apart
,
57 afs_uint32 okvol
, afs_uint32 delvol
)
59 afs_int32 error
, code
, tid
, rcode
;
64 code
= AFSVolTransCreate(aconn
, delvol
, apart
, ITOffline
, &tid
);
67 code
= AFSVolDeleteVolume(aconn
, tid
);
70 code
= AFSVolEndTrans(aconn
, tid
, &rcode
);
77 code
= AFSVolTransCreate(aconn
, okvol
, apart
, ITOffline
, &tid
);
79 code
= AFSVolEndTrans(aconn
, tid
, &rcode
);
84 code
= AFSVolTransCreate(aconn
, delvol
, apart
, ITOffline
, &tid
);
87 code
= AFSVolDeleteVolume(aconn
, tid
);
90 code
= AFSVolEndTrans(aconn
, tid
, &rcode
);
101 /* forcibly remove a volume. Very dangerous call */
103 UV_NukeVolume(afs_cell_handle_p cellHandle
, struct rx_connection
*server
,
104 unsigned int partition
, afs_uint32 volumeId
, afs_status_p st
)
107 afs_status_t tst
= 0;
109 tst
= AFSVolNukeVolume(server
, partition
, volumeId
);
121 /* create a volume, given a server, partition number, volume name --> sends
122 * back new vol id in <anewid>*/
124 UV_CreateVolume(afs_cell_handle_p cellHandle
, struct rx_connection
*server
,
125 unsigned int partition
, char *volumeName
,
126 unsigned int quota
, afs_uint32
*volumeId
, afs_status_p st
)
129 afs_status_t tst
= 0;
132 struct nvldbentry entry
;
133 struct volintInfo tstatus
;
135 memset(&tstatus
, 0, sizeof(tstatus
));
137 tstatus
.maxquota
= quota
;
139 /* next the next 3 available ids from the VLDB */
140 tst
= ubik_VL_GetNewVolumeId(cellHandle
->vos
, 0, 3, volumeId
);
142 goto fail_UV_CreateVolume
;
146 AFSVolCreateVolume(server
, partition
, volumeName
, volser_RW
, 0,
149 goto fail_UV_CreateVolume
;
152 AFSVolSetInfo(server
, tid
, &tstatus
);
154 tst
= AFSVolSetFlags(server
, tid
, 0);
156 goto fail_UV_CreateVolume
;
159 /* set up the vldb entry for this volume */
160 strncpy(entry
.name
, volumeName
, VOLSER_OLDMAXVOLNAME
);
162 entry
.serverNumber
[0] = ntohl(rx_HostOf(rx_PeerOf(server
)));
163 entry
.serverPartition
[0] = partition
;
164 entry
.flags
= VLF_RWEXISTS
;
165 entry
.serverFlags
[0] = VLSF_RWVOL
;
166 entry
.volumeId
[RWVOL
] = *volumeId
;
167 entry
.volumeId
[ROVOL
] = *volumeId
+ 1;
168 entry
.volumeId
[BACKVOL
] = *volumeId
+ 2;
171 if (!VLDB_CreateEntry(cellHandle
, &entry
, &tst
)) {
172 AFSVolDeleteVolume(server
, tid
);
173 goto fail_UV_CreateVolume
;
176 tst
= AFSVolEndTrans(server
, tid
, &rcode
);
179 goto fail_UV_CreateVolume
;
183 fail_UV_CreateVolume
:
186 AFSVolEndTrans(server
, tid
, &rcode
);
196 /* Delete the volume <volid>on <aserver> <apart>
197 * the physical entry gets removed from the vldb only if the ref count
201 UV_DeleteVolume(afs_cell_handle_p cellHandle
, struct rx_connection
*server
,
202 unsigned int partition
, afs_uint32 volumeId
,
206 afs_status_t tst
= 0;
207 afs_status_t temp
= 0;
208 int serverAddr
= ntohl(rx_HostOf(rx_PeerOf(server
)));
212 struct nvldbentry entry
;
214 afs_int32 avoltype
= -1, vtype
;
215 int notondisk
= 0, notinvldb
= 0;
217 /* Find and read the VLDB entry for this volume */
219 ubik_VL_SetLock(cellHandle
->vos
, 0, volumeId
, avoltype
,
222 if (tst
!= VL_NOENT
) {
223 goto fail_UV_DeleteVolume
;
229 if (!aVLDB_GetEntryByID(cellHandle
, volumeId
, avoltype
, &entry
, &tst
)) {
230 goto fail_UV_DeleteVolume
;
235 /* Whether volume is in the VLDB or not. Delete the volume on disk */
236 tst
= AFSVolTransCreate(server
, volumeId
, partition
, ITOffline
, &ttid
);
241 goto fail_UV_DeleteVolume
;
244 tst
= AFSVolDeleteVolume(server
, ttid
);
246 goto fail_UV_DeleteVolume
;
248 tst
= AFSVolEndTrans(server
, ttid
, &rcode
);
249 tst
= (tst
? tst
: rcode
);
252 goto fail_UV_DeleteVolume
;
257 goto fail_UV_DeleteVolume
;
260 if (volumeId
== entry
.volumeId
[BACKVOL
]) {
261 if (!(entry
.flags
& VLF_BACKEXISTS
)
262 || !Lp_Match(cellHandle
, &entry
, serverAddr
, partition
, &tst
)) {
264 goto fail_UV_DeleteVolume
;
267 entry
.flags
&= ~VLF_BACKEXISTS
;
271 else if (volumeId
== entry
.volumeId
[ROVOL
]) {
272 if (!Lp_ROMatch(cellHandle
, &entry
, serverAddr
, partition
, &tst
)) {
274 goto fail_UV_DeleteVolume
;
277 Lp_SetROValue(cellHandle
, &entry
, serverAddr
, partition
, 0, 0);
279 if (!Lp_ROMatch(cellHandle
, &entry
, 0, 0, &tst
)) {
280 entry
.flags
&= ~VLF_ROEXISTS
;
285 else if (volumeId
== entry
.volumeId
[RWVOL
]) {
286 if (!(entry
.flags
& VLF_RWEXISTS
)
287 || !Lp_Match(cellHandle
, &entry
, serverAddr
, partition
, &tst
)) {
289 goto fail_UV_DeleteVolume
;
292 /* Delete backup if it exists */
294 AFSVolTransCreate(server
, entry
.volumeId
[BACKVOL
], partition
,
297 tst
= AFSVolDeleteVolume(server
, ttid
);
299 goto fail_UV_DeleteVolume
;
301 tst
= AFSVolEndTrans(server
, ttid
, &rcode
);
303 tst
= (tst
? tst
: rcode
);
305 goto fail_UV_DeleteVolume
;
309 Lp_SetRWValue(cellHandle
, &entry
, serverAddr
, partition
, 0L, 0L);
311 entry
.flags
&= ~(VLF_BACKEXISTS
| VLF_RWEXISTS
);
317 notinvldb
= 2; /* Not found on this server and partition */
318 goto fail_UV_DeleteVolume
;
321 if ((entry
.nServers
<= 0) || !(entry
.flags
& (VLF_ROEXISTS
| VLF_RWEXISTS
))) {
322 tst
= ubik_VL_DeleteEntry(cellHandle
->vos
, 0, volumeId
, vtype
);
324 goto fail_UV_DeleteVolume
;
327 if (!VLDB_ReplaceEntry
328 (cellHandle
, volumeId
, vtype
, &entry
,
329 (LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
), &tst
)) {
330 goto fail_UV_DeleteVolume
;
336 fail_UV_DeleteVolume
:
338 if (notondisk
&& notinvldb
) {
340 tst
= ADMVOSVOLUMENOEXIST
;
344 temp
= AFSVolEndTrans(server
, ttid
, &rcode
);
345 temp
= (temp
? temp
: rcode
);
354 ubik_VL_ReleaseLock(cellHandle
->vos
, 0, volumeId
, -1,
355 (LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
));
368 #define ONERR(ec, es, ep) if (ec) { fprintf(STDERR, (es), (ep)); error = (ec); goto mfail; }
370 /* Move volume <afromvol> on <afromserver> <afrompart> to <atoserver>
371 * <atopart>. The operation is almost idempotent
375 UV_MoveVolume(afs_cell_handle_p cellHandle
, afs_uint32 afromvol
,
376 afs_int32 afromserver
, afs_int32 afrompart
, afs_int32 atoserver
,
377 afs_int32 atopart
, afs_status_p st
)
380 afs_status_t tst
= 0;
381 afs_status_t etst
= 0;
382 struct rx_connection
*toconn
, *fromconn
;
383 afs_int32 fromtid
, totid
, clonetid
;
386 char tmpName
[VOLSER_MAXVOLNAME
+ 1];
389 struct restoreCookie cookie
;
390 afs_uint32 newVol
, volid
, backupId
;
391 struct volser_status tstatus
;
392 struct destServer destination
;
394 struct nvldbentry entry
;
397 afs_int32 store_flags
;
399 #ifdef ENABLE_BUGFIX_1165
400 volEntries volumeInfo
;
401 struct volintInfo
*infop
= 0;
405 fromconn
= (struct rx_connection
*)0;
406 toconn
= (struct rx_connection
*)0;
414 if (!aVLDB_GetEntryByID(cellHandle
, afromvol
, -1, &entry
, &tst
)) {
415 goto fail_UV_MoveVolume
;
418 if (entry
.volumeId
[RWVOL
] != afromvol
) {
419 tst
= ADMVOSVOLUMEMOVERWONLY
;
420 goto fail_UV_MoveVolume
;
424 ubik_VL_SetLock(cellHandle
->vos
, 0, afromvol
, RWVOL
, VLOP_MOVE
);
426 goto fail_UV_MoveVolume
;
430 if (!aVLDB_GetEntryByID(cellHandle
, afromvol
, RWVOL
, &entry
, &tst
)) {
431 goto fail_UV_MoveVolume
;
434 backupId
= entry
.volumeId
[BACKVOL
];
436 if (!Lp_Match(cellHandle
, &entry
, afromserver
, afrompart
, &tst
)) {
437 /* the from server and partition do not exist in the vldb entry corresponding to volid */
438 if (!Lp_Match(cellHandle
, &entry
, atoserver
, atopart
, &tst
)) {
439 /* the to server and partition do not exist in the vldb entry corresponding to volid */
441 ubik_VL_ReleaseLock(cellHandle
->vos
, 0, afromvol
, -1,
442 (LOCKREL_OPCODE
| LOCKREL_AFSID
|
445 goto fail_UV_MoveVolume
;
447 tst
= VOLSERVOLMOVED
;
448 goto fail_UV_MoveVolume
;
451 /* delete the volume afromvol on src_server */
452 /* from-info does not exist but to-info does =>
453 * we have already done the move, but the volume
454 * may still be existing physically on from fileserver
456 fromconn
= UV_Bind(cellHandle
, afromserver
, AFSCONF_VOLUMEPORT
);
460 AFSVolTransCreate(fromconn
, afromvol
, afrompart
, ITOffline
,
462 if (!tst
) { /* volume exists - delete it */
464 AFSVolSetFlags(fromconn
, fromtid
,
465 VTDeleteOnSalvage
| VTOutOfService
);
467 goto fail_UV_MoveVolume
;
470 tst
= AFSVolDeleteVolume(fromconn
, fromtid
);
472 goto fail_UV_MoveVolume
;
475 tst
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
480 goto fail_UV_MoveVolume
;
484 /*delete the backup volume now */
487 AFSVolTransCreate(fromconn
, backupId
, afrompart
, ITOffline
,
489 if (!tst
) { /* backup volume exists - delete it */
491 AFSVolSetFlags(fromconn
, fromtid
,
492 VTDeleteOnSalvage
| VTOutOfService
);
494 goto fail_UV_MoveVolume
;
497 tst
= AFSVolDeleteVolume(fromconn
, fromtid
);
499 goto fail_UV_MoveVolume
;
502 tst
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
507 goto fail_UV_MoveVolume
;
512 goto fail_UV_MoveVolume
;
515 /* From-info matches the vldb info about volid,
516 * its ok start the move operation, the backup volume
517 * on the old site is deleted in the process
519 if (afrompart
== atopart
) {
520 if (!VLDB_IsSameAddrs
521 (cellHandle
, afromserver
, atoserver
, &same
, &tst
)) {
522 goto fail_UV_MoveVolume
;
525 tst
= VOLSERVOLMOVED
;
526 goto fail_UV_MoveVolume
;
530 toconn
= UV_Bind(cellHandle
, atoserver
, AFSCONF_VOLUMEPORT
); /* get connections to the servers */
531 fromconn
= UV_Bind(cellHandle
, afromserver
, AFSCONF_VOLUMEPORT
);
532 fromtid
= totid
= 0; /* initialize to uncreated */
535 * clone the read/write volume locally.
538 tst
= AFSVolTransCreate(fromconn
, afromvol
, afrompart
, ITBusy
, &fromtid
);
540 goto fail_UV_MoveVolume
;
545 tst
= ubik_VL_GetNewVolumeId(cellHandle
->vos
, 0, 1, &newVol
);
547 goto fail_UV_MoveVolume
;
550 /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
551 strcpy(vname
, "move-clone-temp");
552 tst
= AFSVolClone(fromconn
, fromtid
, 0, readonlyVolume
, vname
, &newVol
);
554 goto fail_UV_MoveVolume
;
557 /* lookup the name of the volume we just cloned */
559 tst
= AFSVolGetName(fromconn
, fromtid
, &volName
);
561 goto fail_UV_MoveVolume
;
565 tst
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
570 goto fail_UV_MoveVolume
;
574 * Create the destination volume
578 AFSVolTransCreate(fromconn
, newVol
, afrompart
, ITOffline
, &clonetid
);
580 goto fail_UV_MoveVolume
;
582 tst
= AFSVolSetFlags(fromconn
, clonetid
, VTDeleteOnSalvage
| VTOutOfService
); /*redundant */
584 goto fail_UV_MoveVolume
;
587 /* remember time from which we've dumped the volume */
588 tst
= AFSVolGetStatus(fromconn
, clonetid
, &tstatus
);
590 goto fail_UV_MoveVolume
;
593 fromDate
= tstatus
.creationDate
- CLOCKSKEW
;
595 #ifdef ENABLE_BUGFIX_1165
597 * Get the internal volume state from the source volume. We'll use such info (i.e. dayUse)
598 * to copy it to the new volume (via AFSSetInfo later on) so that when we move volumes we
599 * don't use this information...
601 volumeInfo
.volEntries_val
= (volintInfo
*) 0; /*this hints the stub to allocate space */
602 volumeInfo
.volEntries_len
= 0;
603 tst
= AFSVolListOneVolume(fromconn
, afrompart
, afromvol
, &volumeInfo
);
605 goto fail_UV_MoveVolume
;
608 infop
= (volintInfo
*) volumeInfo
.volEntries_val
;
609 infop
->maxquota
= -1; /* Else it will replace the default quota */
612 /* create a volume on the target machine */
614 tst
= AFSVolTransCreate(toconn
, volid
, atopart
, ITOffline
, &totid
);
615 if (!tst
) { /*delete the existing volume */
617 tst
= AFSVolDeleteVolume(toconn
, totid
);
619 goto fail_UV_MoveVolume
;
622 tst
= AFSVolEndTrans(toconn
, totid
, &rcode
);
627 goto fail_UV_MoveVolume
;
633 AFSVolCreateVolume(toconn
, atopart
, volName
, volser_RW
, volid
, &volid
,
636 goto fail_UV_MoveVolume
;
639 strncpy(tmpName
, volName
, VOLSER_OLDMAXVOLNAME
);
643 tst
= AFSVolSetFlags(toconn
, totid
, (VTDeleteOnSalvage
| VTOutOfService
));
645 goto fail_UV_MoveVolume
;
649 * Now dump the clone to the new volume
652 destination
.destHost
= atoserver
;
653 destination
.destPort
= AFSCONF_VOLUMEPORT
;
654 destination
.destSSID
= 1;
656 /* Copy the clone to the new volume */
657 strncpy(cookie
.name
, tmpName
, VOLSER_OLDMAXVOLNAME
);
659 cookie
.parent
= entry
.volumeId
[RWVOL
];
661 tst
= AFSVolForward(fromconn
, clonetid
, 0, &destination
, totid
, &cookie
);
663 goto fail_UV_MoveVolume
;
666 tst
= AFSVolEndTrans(fromconn
, clonetid
, &rcode
);
671 goto fail_UV_MoveVolume
;
675 * reattach to the main-line volume, and incrementally dump it.
678 tst
= AFSVolTransCreate(fromconn
, afromvol
, afrompart
, ITBusy
, &fromtid
);
680 goto fail_UV_MoveVolume
;
683 /* now do the incremental */
685 AFSVolForward(fromconn
, fromtid
, fromDate
, &destination
, totid
,
688 goto fail_UV_MoveVolume
;
691 /* now adjust the flags so that the new volume becomes official */
692 tst
= AFSVolSetFlags(fromconn
, fromtid
, VTOutOfService
);
694 goto fail_UV_MoveVolume
;
697 tst
= AFSVolSetFlags(toconn
, totid
, 0);
699 goto fail_UV_MoveVolume
;
701 #ifdef ENABLE_BUGFIX_1165
702 tst
= AFSVolSetInfo(toconn
, totid
, infop
);
704 goto fail_UV_MoveVolume
;
708 /* put new volume online */
709 tst
= AFSVolEndTrans(toconn
, totid
, &rcode
);
714 goto fail_UV_MoveVolume
;
717 Lp_SetRWValue(cellHandle
, &entry
, afromserver
, afrompart
, atoserver
,
719 store_flags
= entry
.flags
;
720 entry
.flags
&= ~VLF_BACKEXISTS
;
722 if (!VLDB_ReplaceEntry
723 (cellHandle
, afromvol
, -1, &entry
,
724 (LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
), &tst
)) {
725 goto fail_UV_MoveVolume
;
727 entry
.flags
= store_flags
;
730 if (atoserver
!= afromserver
) {
731 /* set forwarding pointer for moved volumes */
732 tst
= AFSVolSetForwarding(fromconn
, fromtid
, htonl(atoserver
));
734 goto fail_UV_MoveVolume
;
738 tst
= AFSVolDeleteVolume(fromconn
, fromtid
); /* zap original volume */
740 goto fail_UV_MoveVolume
;
743 tst
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
748 goto fail_UV_MoveVolume
;
751 /* Delete the backup volume on the original site */
753 AFSVolTransCreate(fromconn
, backupId
, afrompart
, ITOffline
, &fromtid
);
756 AFSVolSetFlags(fromconn
, fromtid
,
757 VTDeleteOnSalvage
| VTOutOfService
);
759 goto fail_UV_MoveVolume
;
762 tst
= AFSVolDeleteVolume(fromconn
, fromtid
);
764 goto fail_UV_MoveVolume
;
767 tst
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
772 goto fail_UV_MoveVolume
;
776 tst
= 0; /* no backup volume? that's okay */
781 AFSVolTransCreate(fromconn
, newVol
, afrompart
, ITOffline
, &clonetid
);
783 goto fail_UV_MoveVolume
;
786 /* now delete the clone */
788 tst
= AFSVolDeleteVolume(fromconn
, clonetid
);
790 goto fail_UV_MoveVolume
;
793 tst
= AFSVolEndTrans(fromconn
, clonetid
, &rcode
);
798 goto fail_UV_MoveVolume
;
804 /* normal cleanup code */
808 ubik_VL_ReleaseLock(cellHandle
->vos
, 0, afromvol
, -1,
809 (LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
));
817 etst
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
820 tst
= (etst
? etst
: rcode
);
825 etst
= AFSVolEndTrans(fromconn
, clonetid
, &rcode
);
828 tst
= (etst
? etst
: rcode
);
833 etst
= AFSVolEndTrans(toconn
, totid
, &rcode
);
836 tst
= (etst
? etst
: rcode
);
841 #ifdef ENABLE_BUGFIX_1165
846 rx_ReleaseCachedConnection(fromconn
);
848 rx_ReleaseCachedConnection(toconn
);
856 /* come here only when the sky falls */
860 /* unlock VLDB entry */
862 ubik_VL_ReleaseLock(cellHandle
->vos
, 0, afromvol
, -1,
863 (LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
));
866 AFSVolEndTrans(fromconn
, clonetid
, &rcode
);
868 AFSVolEndTrans(toconn
, totid
, &rcode
);
869 if (fromtid
) { /* put it on-line */
870 AFSVolSetFlags(fromconn
, fromtid
, 0);
871 AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
874 if (!aVLDB_GetEntryByID(cellHandle
, afromvol
, -1, &entry
, &tst
)) {
878 /* Delete either the volume on the source location or the target location.
879 * If the vldb entry still points to the source location, then we know the
880 * volume move didn't finish so we remove the volume from the target
881 * location. Otherwise, we remove the volume from the source location.
883 if (Lp_Match(cellHandle
, &entry
, afromserver
, afrompart
, &tst
)) { /* didn't move - delete target volume */
885 if (volid
&& toconn
) {
887 AFSVolTransCreate(toconn
, volid
, atopart
, ITOffline
, &totid
);
889 AFSVolSetFlags(toconn
, totid
,
890 VTDeleteOnSalvage
| VTOutOfService
);
891 AFSVolDeleteVolume(toconn
, totid
);
892 AFSVolEndTrans(toconn
, totid
, &rcode
);
896 /* put source volume on-line */
899 AFSVolTransCreate(fromconn
, afromvol
, afrompart
, ITBusy
,
902 AFSVolSetFlags(fromconn
, fromtid
, 0);
903 AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
906 } else { /* yep, move complete */
907 /* delete backup volume */
910 AFSVolTransCreate(fromconn
, backupId
, afrompart
, ITOffline
,
913 AFSVolSetFlags(fromconn
, fromtid
,
914 VTDeleteOnSalvage
| VTOutOfService
);
915 AFSVolDeleteVolume(fromconn
, fromtid
);
916 AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
919 /* delete source volume */
921 AFSVolTransCreate(fromconn
, afromvol
, afrompart
, ITBusy
,
924 AFSVolSetFlags(fromconn
, fromtid
,
925 VTDeleteOnSalvage
| VTOutOfService
);
926 if (atoserver
!= afromserver
)
927 AFSVolSetForwarding(fromconn
, fromtid
, htonl(atoserver
));
928 AFSVolDeleteVolume(fromconn
, fromtid
);
929 AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
934 /* common cleanup - delete local clone */
937 AFSVolTransCreate(fromconn
, newVol
, afrompart
, ITOffline
,
940 AFSVolDeleteVolume(fromconn
, clonetid
);
941 AFSVolEndTrans(fromconn
, clonetid
, &rcode
);
945 /* unlock VLDB entry */
946 ubik_VL_ReleaseLock(cellHandle
->vos
, 0, afromvol
, -1,
947 (LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
));
949 done
: /* routine cleanup */
952 #ifdef ENABLE_BUGFIX_1165
957 rx_ReleaseCachedConnection(fromconn
);
959 rx_ReleaseCachedConnection(toconn
);
967 /* Make a new backup of volume <avolid> on <aserver> and <apart>
968 * if one already exists, update it
972 UV_BackupVolume(afs_cell_handle_p cellHandle
, afs_int32 aserver
,
973 afs_int32 apart
, afs_uint32 avolid
, afs_status_p st
)
976 afs_status_t tst
= 0, temp
= 0;
977 afs_int32 ttid
= 0, btid
= 0;
980 char vname
[VOLSER_MAXVOLNAME
+ 1];
981 struct nvldbentry entry
;
982 int vldblocked
= 0, vldbmod
= 0, backexists
= 1;
983 struct rx_connection
*aconn
= UV_Bind(cellHandle
, aserver
,
987 /* the calls to VLDB will succeed only if avolid is a RW volume,
988 * since we are following the RW hash chain for searching */
989 if (!aVLDB_GetEntryByID(cellHandle
, avolid
, RWVOL
, &entry
, &tst
)) {
990 goto fail_UV_BackupVolume
;
993 /* These operations require the VLDB be locked since it means the VLDB
994 * will change or the vldb is already locked.
996 if (!(entry
.flags
& VLF_BACKEXISTS
) || /* backup volume doesnt exist */
997 (entry
.flags
& VLOP_ALLOPERS
) || /* vldb lock already held */
998 (entry
.volumeId
[BACKVOL
] == INVALID_BID
)) {
999 /* no assigned backup volume id */
1002 ubik_VL_SetLock(cellHandle
->vos
, 0, avolid
, RWVOL
,
1005 goto fail_UV_BackupVolume
;
1009 /* Reread the vldb entry */
1010 if (!aVLDB_GetEntryByID(cellHandle
, avolid
, RWVOL
, &entry
, &tst
)) {
1011 goto fail_UV_BackupVolume
;
1015 if (!ISNAMEVALID(entry
.name
)) {
1016 tst
= VOLSERBADNAME
;
1017 goto fail_UV_BackupVolume
;
1020 backupID
= entry
.volumeId
[BACKVOL
];
1021 if (backupID
== INVALID_BID
) {
1022 /* Get a backup volume id from the VLDB and update the vldb
1025 tst
= ubik_VL_GetNewVolumeId(cellHandle
->vos
, 0, 1, &backupID
);
1027 goto fail_UV_BackupVolume
;
1029 entry
.volumeId
[BACKVOL
] = backupID
;
1033 /* Test to see if the backup volume exists by trying to create
1034 * a transaction on the backup volume. We've assumed the backup exists.
1036 tst
= AFSVolTransCreate(aconn
, backupID
, apart
, ITOffline
, &btid
);
1038 if (tst
!= VNOVOL
) {
1039 goto fail_UV_BackupVolume
;
1041 backexists
= 0; /* backup volume does not exist */
1044 tst
= AFSVolEndTrans(aconn
, btid
, &rcode
);
1047 tst
= (tst
? tst
: rcode
);
1048 goto fail_UV_BackupVolume
;
1052 /* Now go ahead and try to clone the RW volume.
1053 * First start a transaction on the RW volume
1055 tst
= AFSVolTransCreate(aconn
, avolid
, apart
, ITBusy
, &ttid
);
1057 goto fail_UV_BackupVolume
;
1060 /* Clone or reclone the volume, depending on whether the backup
1061 * volume exists or not
1064 tst
= AFSVolReClone(aconn
, ttid
, backupID
);
1066 goto fail_UV_BackupVolume
;
1069 strcpy(vname
, entry
.name
);
1070 strcat(vname
, ".backup");
1072 tst
= AFSVolClone(aconn
, ttid
, 0, backupVolume
, vname
, &backupID
);
1074 goto fail_UV_BackupVolume
;
1078 /* End transaction on the RW volume */
1079 tst
= AFSVolEndTrans(aconn
, ttid
, &rcode
);
1082 tst
= (tst
? tst
: rcode
);
1083 goto fail_UV_BackupVolume
;
1086 /* Mork vldb as backup exists */
1087 if (!(entry
.flags
& VLF_BACKEXISTS
)) {
1088 entry
.flags
|= VLF_BACKEXISTS
;
1092 /* Now go back to the backup volume and bring it on line */
1093 tst
= AFSVolTransCreate(aconn
, backupID
, apart
, ITOffline
, &btid
);
1095 goto fail_UV_BackupVolume
;
1098 tst
= AFSVolSetFlags(aconn
, btid
, 0);
1100 goto fail_UV_BackupVolume
;
1103 tst
= AFSVolEndTrans(aconn
, btid
, &rcode
);
1106 tst
= (tst
? tst
: rcode
);
1107 goto fail_UV_BackupVolume
;
1111 /* Will update the vldb below */
1113 fail_UV_BackupVolume
:
1116 temp
= AFSVolEndTrans(aconn
, ttid
, &rcode
);
1117 if (temp
|| rcode
) {
1119 tst
= (temp
? temp
: rcode
);
1124 temp
= AFSVolEndTrans(aconn
, btid
, &rcode
);
1125 if (temp
|| rcode
) {
1127 tst
= (temp
? temp
: rcode
);
1131 /* Now update the vldb - if modified */
1134 if (!VLDB_ReplaceEntry
1135 (cellHandle
, avolid
, RWVOL
, &entry
,
1136 (LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
),
1144 ubik_VL_ReleaseLock(cellHandle
->vos
, 0, avolid
, RWVOL
,
1145 (LOCKREL_OPCODE
| LOCKREL_AFSID
|
1146 LOCKREL_TIMESTAMP
));
1156 rx_ReleaseCachedConnection(aconn
);
1166 DelVol(struct rx_connection
*conn
, afs_uint32 vid
, afs_int32 part
,
1169 afs_int32 acode
, rcode
, tid
;
1172 acode
= AFSVolTransCreate(conn
, vid
, part
, flags
, &tid
);
1173 if (!acode
) { /* It really was there */
1174 acode
= AFSVolDeleteVolume(conn
, tid
);
1175 AFSVolEndTrans(conn
, tid
, &rcode
);
1181 #define ONERROR(ec, ep, es) if (ec) { fprintf(STDERR, (es), (ep)); error = (ec); goto rfail; }
1182 #define ERROREXIT(ec) { error = (ec); goto rfail; }
1184 #if 0 /* doesn't appear to be used, why compile it */
1186 CloneVol(afs_cell_handle_p cellHandle
, struct rx_connection
*conn
,
1187 afs_uint32 rwvid
, afs_int32 part
, afs_uint32
* rovidp
, int nottemp
,
1188 struct nvldbentry
*entry
, afs_int32
* vidCreateDate
, afs_status_p st
)
1191 afs_status_t tst
= 0, etst
= 0;
1192 afs_int32 rcode
= 0, tid
= 0;
1193 struct volser_status volstatus
;
1196 /* Begin transaction on RW volume marking it busy (clients will wait) */
1197 tst
= AFSVolTransCreate(conn
, rwvid
, part
, ITBusy
, &tid
);
1202 /* Get the RO volume id. Allocate a new one if need to */
1203 *rovidp
= entry
->volumeId
[ROVOL
];
1204 if (*rovidp
== INVALID_BID
) {
1205 tst
= ubik_VL_GetNewVolumeId(cellHandle
->vos
, 0, 1, rovidp
);
1210 entry
->volumeId
[ROVOL
] = *rovidp
;
1213 /* If we are creating the ro clone, what are we calling it.
1214 * Depends on whether its a temporary clone or not.
1217 strcpy(vname
, entry
->name
);
1218 strcat(vname
, ".readonly");
1220 strcpy(vname
, "readonly-clone-temp"); /* Should be unique? */
1223 /* Create the new clone. If it exists, then reclone it */
1224 tst
= AFSVolClone(conn
, tid
, 0, readonlyVolume
, vname
, rovidp
);
1225 if (tst
== VVOLEXISTS
) {
1226 tst
= AFSVolReClone(conn
, tid
, *rovidp
);
1235 /* Bring the volume back on-line as soon as possible */
1237 afs_int32 fromtid
= 0;
1239 /* Now bring the RO clone on-line */
1240 tst
= AFSVolTransCreate(conn
, *rovidp
, part
, ITOffline
, &fromtid
);
1245 tst
= AFSVolSetFlags(conn
, fromtid
, 0);
1250 tst
= AFSVolEndTrans(conn
, fromtid
, &rcode
);
1259 /* Get the time the RW was created for return information */
1260 tst
= AFSVolGetStatus(conn
, tid
, &volstatus
);
1264 *vidCreateDate
= volstatus
.creationDate
;
1270 tst
= AFSVolEndTrans(conn
, tid
, &rcode
);
1287 /* Get a "transaction" on this replica. Create the volume
1288 * if necessary. Return the time from which a dump should
1289 * be made (0 if it's a new volume)
1292 GetTrans(afs_cell_handle_p cellHandle
, struct nvldbentry
*vldbEntryPtr
,
1293 afs_int32 index
, struct rx_connection
**connPtr
,
1294 afs_int32
* transPtr
, afs_int32
* timePtr
, afs_status_p st
)
1297 afs_status_t tst
= 0;
1299 struct volser_status tstatus
;
1302 *connPtr
= (struct rx_connection
*)0;
1306 /* get connection to the replication site */
1308 UV_Bind(cellHandle
, vldbEntryPtr
->serverNumber
[index
],
1309 AFSCONF_VOLUMEPORT
);
1311 /* server is down */
1316 volid
= vldbEntryPtr
->volumeId
[ROVOL
];
1319 AFSVolTransCreate(*connPtr
, volid
,
1320 vldbEntryPtr
->serverPartition
[index
], ITOffline
,
1324 /* If the volume does not exist, create it */
1325 if (!volid
|| tst
) {
1326 char volname
[VL_MAXNAMELEN
];
1328 if (volid
&& (tst
!= VNOVOL
)) {
1332 strlcpy(volname
, vldbEntryPtr
->name
, sizeof(volname
));
1333 if (strlcat(volname
, ".readonly", sizeof(volname
))
1334 >= sizeof(volname
)) {
1340 AFSVolCreateVolume(*connPtr
, vldbEntryPtr
->serverPartition
[index
],
1342 vldbEntryPtr
->volumeId
[RWVOL
], &volid
,
1347 vldbEntryPtr
->volumeId
[ROVOL
] = volid
;
1349 /* The following is a bit redundant, since create sets these flags by default */
1351 AFSVolSetFlags(*connPtr
, *transPtr
,
1352 VTDeleteOnSalvage
| VTOutOfService
);
1358 /* Otherwise, the transaction did succeed, so get the creation date of the
1359 * latest RO volume on the replication site
1362 tst
= AFSVolGetStatus(*connPtr
, *transPtr
, &tstatus
);
1366 *timePtr
= tstatus
.creationDate
- CLOCKSKEW
;
1372 if ((rc
== 0) && (*transPtr
)) {
1373 AFSVolEndTrans(*connPtr
, *transPtr
, &rcode
);
1384 SimulateForwardMultiple(struct rx_connection
*fromconn
, afs_int32 fromtid
,
1385 afs_int32 fromdate
, manyDests
* tr
, afs_int32 flags
,
1386 void *cookie
, manyResults
* results
)
1390 for (i
= 0; i
< tr
->manyDests_len
; i
++) {
1391 results
->manyResults_val
[i
] =
1392 AFSVolForward(fromconn
, fromtid
, fromdate
,
1393 &(tr
->manyDests_val
[i
].server
),
1394 tr
->manyDests_val
[i
].trans
, cookie
);
1401 * Determine if a volume exists on a server and partition.
1402 * Try creating a transaction on the volume. If we can,
1403 * the volume exists, if not, then return the error code.
1404 * Some error codes mean the volume is unavailable but
1405 * still exists - so we catch these error codes.
1408 VolumeExists(afs_cell_handle_p cellHandle
, afs_int32 server
,
1409 afs_int32 partition
, afs_int32 volumeid
, afs_status_p st
)
1412 afs_status_t tst
= 0;
1413 struct rx_connection
*conn
= (struct rx_connection
*)0;
1414 volEntries volumeInfo
;
1416 conn
= UV_Bind(cellHandle
, server
, AFSCONF_VOLUMEPORT
);
1418 volumeInfo
.volEntries_val
= (volintInfo
*) 0;
1419 volumeInfo
.volEntries_len
= 0;
1420 tst
= AFSVolListOneVolume(conn
, partition
, volumeid
, &volumeInfo
);
1421 if (volumeInfo
.volEntries_val
)
1422 free(volumeInfo
.volEntries_val
);
1423 if (tst
== VOLSERILLEGAL_PARTITION
) {
1426 rx_ReleaseCachedConnection(conn
);
1436 /* release volume <afromvol> on <afromserver> <afrompart> to all the
1437 * sites if forceflag is 1.If its 0 complete the release if the previous
1438 * release aborted else start a new release */
1440 UV_ReleaseVolume(afs_cell_handle_p cellHandle
, afs_uint32 afromvol
,
1441 afs_int32 afromserver
, afs_int32 afrompart
, int forceflag
,
1445 afs_status_t tst
= 0, etst
= 0;
1449 afs_uint32 cloneVolId
, roVolId
;
1450 struct replica
*replicas
= 0;
1451 struct nvldbentry entry
;
1452 int i
, volcount
, m
, fullrelease
, vldbindex
;
1454 struct restoreCookie cookie
;
1455 struct rx_connection
**toconns
= 0;
1456 struct release
*times
= 0;
1458 struct rx_connection
*fromconn
= (struct rx_connection
*)0;
1460 afs_int32 clonetid
= 0, onlinetid
;
1461 afs_int32 fromtid
= 0;
1462 afs_uint32 fromdate
= 0, thisdate
;
1465 manyResults results
;
1466 int rwindex
, roindex
, roclone
, roexists
;
1467 afs_int32 rwcrdate
= 0;
1471 } remembertime
[NMAXNSERVERS
];
1472 int releasecount
= 0;
1473 struct volser_status volstatus
;
1475 memset(remembertime
, 0, sizeof(remembertime
));
1476 memset(&results
, 0, sizeof(results
));
1479 ubik_VL_SetLock(cellHandle
->vos
, 0, afromvol
, RWVOL
,
1481 if ((tst
) && (tst
!= VL_RERELEASE
)) {
1482 goto fail_UV_ReleaseVolume
;
1486 /* Get the vldb entry in readable format */
1487 if (!aVLDB_GetEntryByID(cellHandle
, afromvol
, RWVOL
, &entry
, &tst
)) {
1488 goto fail_UV_ReleaseVolume
;
1491 if (!ISNAMEVALID(entry
.name
)) {
1492 tst
= VOLSERBADNAME
;
1493 goto fail_UV_ReleaseVolume
;
1496 if (entry
.volumeId
[RWVOL
] != afromvol
) {
1497 tst
= ADMVOSVOLUMERELEASERWONLY
;
1498 goto fail_UV_ReleaseVolume
;
1501 if (entry
.nServers
<= 1) {
1502 tst
= ADMVOSVOLUMENOREPLICAS
;
1503 goto fail_UV_ReleaseVolume
;
1506 if (strlen(entry
.name
) > (VOLSER_OLDMAXVOLNAME
- 10)) {
1507 tst
= VOLSERBADNAME
;
1508 goto fail_UV_ReleaseVolume
;
1511 /* roclone is true if one of the RO volumes is on the same
1512 * partition as the RW volume. In this case, we make the RO volume
1513 * on the same partition a clone instead of a complete copy.
1517 Lp_ROMatch(cellHandle
, &entry
, afromserver
, afrompart
, &tst
) - 1;
1518 roclone
= ((roindex
== -1) ? 0 : 1);
1519 rwindex
= Lp_GetRwIndex(cellHandle
, &entry
, 0);
1522 goto fail_UV_ReleaseVolume
;
1525 /* Make sure we have a RO volume id to work with */
1526 if (entry
.volumeId
[ROVOL
] == INVALID_BID
) {
1527 /* need to get a new RO volume id */
1528 tst
= ubik_VL_GetNewVolumeId(cellHandle
->vos
, 0, 1, &roVolId
);
1530 goto fail_UV_ReleaseVolume
;
1533 entry
.volumeId
[ROVOL
] = roVolId
;
1534 if (!VLDB_ReplaceEntry(cellHandle
, afromvol
, RWVOL
, &entry
, 0, &tst
)) {
1535 goto fail_UV_ReleaseVolume
;
1539 /* Will we be completing a previously unfinished release. -force overrides */
1540 for (fullrelease
= 1, i
= 0; (fullrelease
&& (i
< entry
.nServers
)); i
++) {
1541 if (entry
.serverFlags
[i
] & VLSF_NEWREPSITE
)
1544 if (forceflag
&& !fullrelease
)
1547 /* Determine which volume id to use and see if it exists */
1550 || (entry
.cloneId
== 0)) ? entry
.volumeId
[ROVOL
] : entry
.cloneId
);
1551 VolumeExists(cellHandle
, afromserver
, afrompart
, cloneVolId
, &tst
);
1552 roexists
= ((tst
== ENODEV
) ? 0 : 1);
1553 if (!roexists
&& !fullrelease
)
1554 fullrelease
= 1; /* Do a full release if RO clone does not exist */
1556 fromconn
= UV_Bind(cellHandle
, afromserver
, AFSCONF_VOLUMEPORT
);
1559 goto fail_UV_ReleaseVolume
;
1563 /* If the RO clone exists, then if the clone is a temporary
1564 * clone, delete it. Or if the RO clone is marked RO_DONTUSE
1565 * (it was recently added), then also delete it. We do not
1566 * want to "reclone" a temporary RO clone.
1569 && (!roclone
|| (entry
.serverFlags
[roindex
] & VLSF_DONTUSE
))) {
1570 tst
= DelVol(fromconn
, cloneVolId
, afrompart
, ITOffline
);
1571 if (tst
&& (tst
!= VNOVOL
)) {
1572 goto fail_UV_ReleaseVolume
;
1577 /* Mark all the ROs in the VLDB entry as RO_DONTUSE. We don't
1578 * write this entry out to the vlserver until after the first
1579 * RO volume is released (temp RO clones don't count).
1581 for (i
= 0; i
< entry
.nServers
; i
++) {
1582 entry
.serverFlags
[i
] &= ~VLSF_NEWREPSITE
;
1583 entry
.serverFlags
[i
] |= VLSF_DONTUSE
;
1585 entry
.serverFlags
[rwindex
] |= VLSF_NEWREPSITE
;
1586 entry
.serverFlags
[rwindex
] &= ~VLSF_DONTUSE
;
1588 /* Begin transaction on RW and mark it busy while we clone it */
1590 AFSVolTransCreate(fromconn
, afromvol
, afrompart
, ITBusy
,
1593 goto fail_UV_ReleaseVolume
;
1596 /* Clone or reclone the volume */
1598 tst
= AFSVolReClone(fromconn
, clonetid
, cloneVolId
);
1600 goto fail_UV_ReleaseVolume
;
1604 strcpy(vname
, entry
.name
);
1605 strcat(vname
, ".readonly");
1607 strcpy(vname
, "readonly-clone-temp");
1610 AFSVolClone(fromconn
, clonetid
, 0, readonlyVolume
, vname
,
1613 goto fail_UV_ReleaseVolume
;
1617 /* Get the time the RW was created for future information */
1618 tst
= AFSVolGetStatus(fromconn
, clonetid
, &volstatus
);
1620 goto fail_UV_ReleaseVolume
;
1622 rwcrdate
= volstatus
.creationDate
;
1624 /* End the transaction on the RW volume */
1625 tst
= AFSVolEndTrans(fromconn
, clonetid
, &rcode
);
1627 tst
= (tst
? tst
: rcode
);
1629 goto fail_UV_ReleaseVolume
;
1632 /* Remember clone volume ID in case we fail or are interrupted */
1633 entry
.cloneId
= cloneVolId
;
1636 /* Bring the RO clone online - though not if it's a temporary clone */
1638 AFSVolTransCreate(fromconn
, cloneVolId
, afrompart
, ITOffline
,
1641 goto fail_UV_ReleaseVolume
;
1644 etst
= AFSVolSetFlags(fromconn
, onlinetid
, 0);
1646 tst
= AFSVolEndTrans(fromconn
, onlinetid
, &rcode
);
1647 tst
= (tst
? tst
: rcode
);
1649 goto fail_UV_ReleaseVolume
;
1653 goto fail_UV_ReleaseVolume
;
1656 /* Sleep so that a client searching for an online volume won't
1657 * find the clone offline and then the next RO offline while the
1658 * release brings the clone online and the next RO offline (race).
1659 * There is a fix in the 3.4 client that does not need this sleep
1660 * anymore, but we don't know what clients we have.
1662 if (entry
.nServers
> 2)
1665 /* Mark the RO clone in the VLDB as a good site (already released) */
1666 entry
.serverFlags
[roindex
] |= VLSF_NEWREPSITE
;
1667 entry
.serverFlags
[roindex
] &= ~VLSF_DONTUSE
;
1668 entry
.flags
|= VLF_ROEXISTS
;
1672 /* Write out the VLDB entry only if the clone is not a temporary
1673 * clone. If we did this to a temporary clone then we would end
1674 * up marking all the ROs as "old release" making the ROs
1675 * temporarily unavailable.
1677 if (!VLDB_ReplaceEntry
1678 (cellHandle
, afromvol
, RWVOL
, &entry
, 0, &tst
)) {
1679 goto fail_UV_ReleaseVolume
;
1684 /* Now we will release from the clone to the remaining RO replicas.
1685 * The first 2 ROs (counting the non-temporary RO clone) are released
1686 * individually: releasecount. This is to reduce the race condition
1687 * of clients trying to find an on-line RO volume. The remaining ROs
1688 * are released in parallel but no more than half the number of ROs
1689 * (rounded up) at a time: nservers.
1692 strcpy(vname
, entry
.name
);
1693 strcat(vname
, ".readonly");
1694 memset(&cookie
, 0, sizeof(cookie
));
1695 strncpy(cookie
.name
, vname
, VOLSER_OLDMAXVOLNAME
);
1696 cookie
.type
= ROVOL
;
1697 cookie
.parent
= entry
.volumeId
[RWVOL
];
1700 nservers
= entry
.nServers
/ 2; /* how many to do at once, excluding clone */
1701 replicas
= calloc(nservers
+ 1, sizeof(struct replica
));
1702 times
= calloc(nservers
+ 1, sizeof(struct release
));
1703 toconns
= calloc(nservers
+ 1, sizeof(struct rx_connection
*));
1704 results
.manyResults_val
= calloc(nservers
+ 1, sizeof(afs_int32
));
1705 if (!replicas
|| !times
|| !!!results
.manyResults_val
|| !toconns
) {
1707 goto fail_UV_ReleaseVolume
;
1710 /* Create a transaction on the cloned volume */
1712 AFSVolTransCreate(fromconn
, cloneVolId
, afrompart
, ITBusy
, &fromtid
);
1714 goto fail_UV_ReleaseVolume
;
1717 /* For each index in the VLDB */
1718 for (vldbindex
= 0; vldbindex
< entry
.nServers
;) {
1720 /* Get a transaction on the replicas. Pick replacas which have an old release. */
1722 ((volcount
< nservers
) && (vldbindex
< entry
.nServers
));
1724 /* The first two RO volumes will be released individually.
1725 * The rest are then released in parallel. This is a hack
1726 * for clients not recognizing right away when a RO volume
1727 * comes back on-line.
1729 if ((volcount
== 1) && (releasecount
< 2))
1732 if (vldbindex
== roindex
)
1733 continue; /* the clone */
1734 if ((entry
.serverFlags
[vldbindex
] & VLSF_NEWREPSITE
)
1735 && !(entry
.serverFlags
[vldbindex
] & VLSF_DONTUSE
))
1737 if (!(entry
.serverFlags
[vldbindex
] & VLSF_ROVOL
))
1738 continue; /* not a RO vol */
1741 /* Get a Transaction on this replica. Get a new connection if
1742 * necessary. Create the volume if necessary. Return the
1743 * time from which the dump should be made (0 if it's a new
1744 * volume). Each volume might have a different time.
1746 replicas
[volcount
].server
.destHost
=
1747 entry
.serverNumber
[vldbindex
];
1748 replicas
[volcount
].server
.destPort
= AFSCONF_VOLUMEPORT
;
1749 replicas
[volcount
].server
.destSSID
= 1;
1750 times
[volcount
].vldbEntryIndex
= vldbindex
;
1753 (cellHandle
, &entry
, vldbindex
, &(toconns
[volcount
]),
1754 &(replicas
[volcount
].trans
), &(times
[volcount
].time
),
1759 /* Thisdate is the date from which we want to pick up all changes */
1760 if (forceflag
|| !fullrelease
1761 || (rwcrdate
> times
[volcount
].time
)) {
1762 /* If the forceflag is set, then we want to do a full dump.
1763 * If it's not a full release, we can't be sure that the creation
1764 * date is good (so we also do a full dump).
1765 * If the RW volume was replaced (its creation date is newer than
1766 * the last release), then we can't be sure what has changed (so
1767 * we do a full dump).
1770 } else if (remembertime
[vldbindex
].validtime
) {
1771 /* Trans was prev ended. Use the time from the prev trans
1772 * because, prev trans may have created the volume. In which
1773 * case time[volcount].time would be now instead of 0.
1776 (remembertime
[vldbindex
].time
<
1777 times
[volcount
].time
) ? remembertime
[vldbindex
].
1778 time
: times
[volcount
].time
;
1780 thisdate
= times
[volcount
].time
;
1782 remembertime
[vldbindex
].validtime
= 1;
1783 remembertime
[vldbindex
].time
= thisdate
;
1785 if (volcount
== 0) {
1786 fromdate
= thisdate
;
1788 /* Include this volume if it is within 15 minutes of the earliest */
1790 thisdate
) ? (fromdate
- thisdate
) : (thisdate
-
1792 AFSVolEndTrans(toconns
[volcount
],
1793 replicas
[volcount
].trans
, &rcode
);
1794 replicas
[volcount
].trans
= 0;
1797 if (thisdate
< fromdate
)
1798 fromdate
= thisdate
;
1805 /* Release the ones we have collected */
1806 tr
.manyDests_val
= &(replicas
[0]);
1807 tr
.manyDests_len
= results
.manyResults_len
= volcount
;
1809 AFSVolForwardMultiple(fromconn
, fromtid
, fromdate
, &tr
,
1810 0 /*spare */ , &cookie
, &results
);
1811 if (tst
== RXGEN_OPCODE
) { /* RPC Interface Mismatch */
1813 SimulateForwardMultiple(fromconn
, fromtid
, fromdate
, &tr
,
1814 0 /*spare */ , &cookie
, &results
);
1819 goto fail_UV_ReleaseVolume
;
1821 for (m
= 0; m
< volcount
; m
++) {
1822 if (results
.manyResults_val
[m
]) {
1827 AFSVolSetIdsTypes(toconns
[m
], replicas
[m
].trans
, vname
,
1828 ROVOL
, entry
.volumeId
[RWVOL
], 0, 0);
1833 /* have to clear dest. flags to ensure new vol goes online:
1834 * because the restore (forwarded) operation copied
1835 * the V_inService(=0) flag over to the destination.
1837 tst
= AFSVolSetFlags(toconns
[m
], replicas
[m
].trans
, 0);
1842 entry
.serverFlags
[times
[m
].vldbEntryIndex
] |= VLSF_NEWREPSITE
;
1843 entry
.serverFlags
[times
[m
].vldbEntryIndex
] &= ~VLSF_DONTUSE
;
1844 entry
.flags
|= VLF_ROEXISTS
;
1849 /* End the transactions and destroy the connections */
1850 for (s
= 0; s
< volcount
; s
++) {
1851 if (replicas
[s
].trans
)
1852 tst
= AFSVolEndTrans(toconns
[s
], replicas
[s
].trans
, &rcode
);
1853 replicas
[s
].trans
= 0;
1857 if ((s
== 0) || (tst
!= ENOENT
)) {
1859 if (times
[s
].vldbEntryIndex
< vldbindex
)
1860 vldbindex
= times
[s
].vldbEntryIndex
;
1865 rx_ReleaseCachedConnection(toconns
[s
]);
1869 if (!VLDB_ReplaceEntry(cellHandle
, afromvol
, RWVOL
, &entry
, 0, &tst
)) {
1870 goto fail_UV_ReleaseVolume
;
1872 } /* for each index in the vldb */
1874 /* End the transaction on the cloned volume */
1875 tst
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
1878 /* Figure out if any volume were not released and say so */
1879 for (failure
= 0, i
= 0; i
< entry
.nServers
; i
++) {
1880 if (!(entry
.serverFlags
[i
] & VLSF_NEWREPSITE
))
1884 if (!VLDB_ReplaceEntry
1885 (cellHandle
, afromvol
, RWVOL
, &entry
, LOCKREL_TIMESTAMP
, &tst
)) {
1886 goto fail_UV_ReleaseVolume
;
1889 tst
= VOLSERBADRELEASE
;
1890 goto fail_UV_ReleaseVolume
;
1893 /* All the ROs were release successfully. Remove the temporary clone */
1895 tst
= DelVol(fromconn
, cloneVolId
, afrompart
, ITOffline
);
1897 goto fail_UV_ReleaseVolume
;
1902 for (i
= 0; i
< entry
.nServers
; i
++)
1903 entry
.serverFlags
[i
] &= ~VLSF_NEWREPSITE
;
1905 /* Update the VLDB */
1906 if (!VLDB_ReplaceEntry
1907 (cellHandle
, afromvol
, RWVOL
, &entry
,
1908 LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
, &tst
)) {
1909 goto fail_UV_ReleaseVolume
;
1913 fail_UV_ReleaseVolume
:
1916 tst
= AFSVolEndTrans(fromconn
, clonetid
, &rcode
);
1923 tst
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
1929 for (i
= 0; i
< nservers
; i
++) {
1930 if (replicas
&& replicas
[i
].trans
) {
1931 tst
= AFSVolEndTrans(toconns
[i
], replicas
[i
].trans
, &rcode
);
1932 replicas
[i
].trans
= 0;
1937 if (toconns
&& toconns
[i
]) {
1938 rx_ReleaseCachedConnection(toconns
[i
]);
1944 ubik_VL_ReleaseLock(cellHandle
->vos
, 0, afromvol
, RWVOL
,
1945 LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
);
1952 rx_ReleaseCachedConnection(fromconn
);
1953 if (results
.manyResults_val
)
1954 free(results
.manyResults_val
);
1969 ReceiveFile(int fd
, struct rx_call
*call
,
1970 struct stat
*status
)
1972 char *buffer
= (char *)0;
1974 afs_int32 bytesread
, nbytes
, bytesleft
, w
;
1976 afs_int32 error
= 0;
1983 struct statfs tstatfs
;
1985 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the sta
1987 fstatfs(fd
, &tstatfs
);
1988 blockSize
= tstatfs
.f_bsize
;
1990 blockSize
= status
->st_blksize
;
1997 buffer
= malloc(blockSize
);
2002 while (!error
&& (bytesread
> 0)) {
2003 bytesread
= rx_Read(call
, buffer
, nbytes
);
2004 bytesleft
= bytesread
;
2005 while (!error
&& (bytesleft
> 0)) {
2008 #ifndef AFS_NT40_ENV /* NT csn't select on non-socket fd's */
2009 select(fd
+ 1, 0, &out
, 0, 0); /* don't timeout if write bl
2012 w
= write(fd
, &buffer
[bytesread
- bytesleft
], bytesleft
);
2014 error
= ADMVOSDUMPFILEWRITEFAIL
;
2030 DumpFunction(struct rx_call
*call
, const char *filename
)
2034 afs_int32 error
, code
;
2038 fd
= open(filename
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666);
2039 if (fd
< 0 || fstat(fd
, &status
) < 0) {
2040 error
= VOLSERBADOP
;
2043 code
= ReceiveFile(fd
, call
, &status
);
2061 /*dump the volume <afromvol> on <afromserver> and
2062 * <afrompart> to <afilename> starting from <fromdate>.
2063 * DumpFunction does the real work behind the scenes after
2064 * extracting parameters from the rock */
2066 UV_DumpVolume(afs_cell_handle_p cellHandle
, afs_uint32 afromvol
,
2067 afs_int32 afromserver
, afs_int32 afrompart
, afs_int32 fromdate
,
2068 const char *filename
, afs_status_p st
)
2071 afs_status_t tst
= 0;
2072 afs_status_t etst
= 0;
2073 struct rx_connection
*fromconn
;
2074 struct rx_call
*fromcall
;
2078 struct nvldbentry entry
;
2082 fromconn
= (struct rx_connection
*)0;
2084 fromcall
= (struct rx_call
*)0;
2086 if (!aVLDB_GetEntryByID(cellHandle
, afromvol
, -1, &entry
, &tst
)) {
2087 goto fail_UV_DumpVolume
;
2090 /* get connections to the servers */
2091 fromconn
= UV_Bind(cellHandle
, afromserver
, AFSCONF_VOLUMEPORT
);
2092 tst
= AFSVolTransCreate(fromconn
, afromvol
, afrompart
, ITBusy
, &fromtid
);
2094 goto fail_UV_DumpVolume
;
2096 fromcall
= rx_NewCall(fromconn
);
2097 tst
= StartAFSVolDump(fromcall
, fromtid
, fromdate
);
2099 goto fail_UV_DumpVolume
;
2101 if ((tst
= DumpFunction(fromcall
, filename
))) {
2102 goto fail_UV_DumpVolume
;
2104 tst
= rx_EndCall(fromcall
, 0);
2105 fromcall
= (struct rx_call
*)0;
2107 goto fail_UV_DumpVolume
;
2109 tst
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
2114 goto fail_UV_DumpVolume
;
2122 ubik_VL_ReleaseLock(cellHandle
->vos
, 0, afromvol
, -1,
2123 LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
);
2131 etst
= rx_EndCall(fromcall
, 0);
2139 etst
= AFSVolEndTrans(fromconn
, fromtid
, &rcode
);
2149 rx_ReleaseCachedConnection(fromconn
);
2159 SendFile(int fd
, struct rx_call
*call
,
2160 struct stat
*status
)
2162 char *buffer
= (char *)0;
2165 afs_int32 error
= 0;
2173 struct statfs tstatfs
;
2175 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the sta
2177 fstatfs(fd
, &tstatfs
);
2178 blockSize
= tstatfs
.f_bsize
;
2180 blockSize
= status
->st_blksize
;
2186 buffer
= malloc(blockSize
);
2194 #ifndef AFS_NT40_ENV /* NT csn't select on non-socket fd's */
2195 select(fd
+ 1, &in
, 0, 0, 0); /* don't timeout if read blocks */
2197 nbytes
= read(fd
, buffer
, blockSize
);
2199 error
= ADMVOSRESTOREFILEREADFAIL
;
2206 if (rx_Write(call
, buffer
, nbytes
) != nbytes
) {
2207 error
= ADMVOSRESTOREFILEWRITEFAIL
;
2217 WriteData(struct rx_call
*call
, const char *filename
)
2221 afs_int32 error
, code
;
2225 fd
= open(filename
, 0);
2226 if (fd
< 0 || fstat(fd
, &status
) < 0) {
2227 fprintf(STDERR
, "Could access file '%s'\n", filename
);
2228 error
= ADMVOSRESTOREFILEOPENFAIL
;
2229 goto fail_WriteData
;
2231 code
= SendFile(fd
, call
, &status
);
2234 goto fail_WriteData
;
2245 error
= ADMVOSRESTOREFILECLOSEFAIL
;
2251 * Restore a volume <tovolid> <tovolname> on <toserver> <topart> from
2252 * the dump file <afilename>. WriteData does all the real work
2253 * after extracting params from the rock
2256 UV_RestoreVolume(afs_cell_handle_p cellHandle
, afs_int32 toserver
,
2257 afs_int32 topart
, afs_uint32 tovolid
, char *tovolname
,
2258 int flags
, const char *dumpFile
, afs_status_p st
)
2261 afs_status_t tst
= 0;
2262 afs_status_t etst
= 0;
2263 struct rx_connection
*toconn
, *tempconn
;
2264 struct rx_call
*tocall
;
2265 afs_int32 totid
, rcode
;
2266 struct volser_status tstatus
;
2271 struct nvldbentry entry
;
2273 struct restoreCookie cookie
;
2275 afs_int32 newDate
, volflag
;
2279 memset(&cookie
, 0, sizeof(cookie
));
2282 tocall
= (struct rx_call
*)0;
2283 tempconn
= (struct rx_connection
*)0;
2288 toconn
= UV_Bind(cellHandle
, toserver
, AFSCONF_VOLUMEPORT
);
2289 if (pvolid
== 0) { /*alot a new id if needed */
2290 aVLDB_GetEntryByName(cellHandle
, tovolname
, &entry
, &tst
);
2291 if (tst
== VL_NOENT
) {
2293 ubik_VL_GetNewVolumeId(cellHandle
->vos
, 0, 1, &pvolid
);
2295 goto fail_UV_RestoreVolume
;
2299 pvolid
= entry
.volumeId
[RWVOL
];
2304 * at this point we have a volume id to use/reuse for the
2305 * volume to be restored
2307 if (strlen(tovolname
) > (VOLSER_OLDMAXVOLNAME
- 1)) {
2308 tst
= ADMVOSRESTOREVOLUMENAMETOOBIG
;
2309 goto fail_UV_RestoreVolume
;
2312 if (!vos_PartitionIdToName(topart
, partName
, &tst
)) {
2313 goto fail_UV_RestoreVolume
;
2315 /*what should the volume be restored as ? rw or ro or bk ?
2316 * right now the default is rw always */
2318 AFSVolCreateVolume(toconn
, topart
, tovolname
, volser_RW
, 0, &pvolid
,
2321 if (flags
& RV_FULLRST
) { /* full restore: delete then create anew */
2323 AFSVolTransCreate(toconn
, pvolid
, topart
, ITOffline
, &totid
);
2325 goto fail_UV_RestoreVolume
;
2328 AFSVolSetFlags(toconn
, totid
,
2329 VTDeleteOnSalvage
| VTOutOfService
);
2331 goto fail_UV_RestoreVolume
;
2333 tst
= AFSVolDeleteVolume(toconn
, totid
);
2335 goto fail_UV_RestoreVolume
;
2337 tst
= AFSVolEndTrans(toconn
, totid
, &rcode
);
2342 goto fail_UV_RestoreVolume
;
2345 AFSVolCreateVolume(toconn
, topart
, tovolname
, volser_RW
, 0,
2348 goto fail_UV_RestoreVolume
;
2352 AFSVolTransCreate(toconn
, pvolid
, topart
, ITOffline
, &totid
);
2354 goto fail_UV_RestoreVolume
;
2358 cookie
.parent
= pvolid
;
2359 cookie
.type
= RWVOL
;
2361 strncpy(cookie
.name
, tovolname
, VOLSER_OLDMAXVOLNAME
);
2363 tocall
= rx_NewCall(toconn
);
2364 tst
= StartAFSVolRestore(tocall
, totid
, 1, &cookie
);
2366 goto fail_UV_RestoreVolume
;
2368 tst
= WriteData(tocall
, dumpFile
);
2370 goto fail_UV_RestoreVolume
;
2372 tst
= rx_EndCall(tocall
, 0);
2373 tocall
= (struct rx_call
*)0;
2375 goto fail_UV_RestoreVolume
;
2377 tst
= AFSVolGetStatus(toconn
, totid
, &tstatus
);
2379 goto fail_UV_RestoreVolume
;
2381 tst
= AFSVolSetIdsTypes(toconn
, totid
, tovolname
, RWVOL
, pvolid
, 0, 0);
2383 goto fail_UV_RestoreVolume
;
2386 tst
= AFSVolSetDate(toconn
, totid
, newDate
);
2388 goto fail_UV_RestoreVolume
;
2391 volflag
= ((flags
& RV_OFFLINE
) ? VTOutOfService
: 0); /* off or on-line */
2392 tst
= AFSVolSetFlags(toconn
, totid
, volflag
);
2394 goto fail_UV_RestoreVolume
;
2397 /* It isn't handled right in fail_UV_RestoreVolume */
2398 tst
= AFSVolEndTrans(toconn
, totid
, &rcode
);
2403 goto fail_UV_RestoreVolume
;
2407 if (success
&& (!reuseID
|| (flags
& RV_FULLRST
))) {
2408 /* Volume was restored on the file server, update the
2409 * VLDB to reflect the change.
2411 aVLDB_GetEntryByID(cellHandle
, pvolid
, RWVOL
, &entry
, &tst
);
2412 if (tst
&& tst
!= VL_NOENT
&& tst
!= VL_ENTDELETED
) {
2413 goto fail_UV_RestoreVolume
;
2415 if (tst
== VL_NOENT
) { /* it doesnot exist already */
2416 /*make the vldb return this indication specifically */
2417 strcpy(entry
.name
, tovolname
);
2419 entry
.serverNumber
[0] = toserver
; /*should be indirect */
2420 entry
.serverPartition
[0] = topart
;
2421 entry
.serverFlags
[0] = VLSF_RWVOL
;
2422 entry
.flags
= VLF_RWEXISTS
;
2423 if (tstatus
.cloneID
!= 0) {
2424 entry
.volumeId
[ROVOL
] = tstatus
.cloneID
; /*this should come from status info on the volume if non zero */
2426 entry
.volumeId
[ROVOL
] = INVALID_BID
;
2427 entry
.volumeId
[RWVOL
] = pvolid
;
2429 if (tstatus
.backupID
!= 0) {
2430 entry
.volumeId
[BACKVOL
] = tstatus
.backupID
;
2431 /*this should come from status info on the volume if non zero */
2433 entry
.volumeId
[BACKVOL
] = INVALID_BID
;
2434 if (!VLDB_CreateEntry(cellHandle
, &entry
, &tst
)) {
2435 goto fail_UV_RestoreVolume
;
2438 } else { /*update the existing entry */
2440 ubik_VL_SetLock(cellHandle
->vos
, 0, pvolid
, RWVOL
,
2443 goto fail_UV_RestoreVolume
;
2446 strcpy(entry
.name
, tovolname
);
2448 /* Update the vlentry with the new information */
2449 index
= Lp_GetRwIndex(cellHandle
, &entry
, 0);
2451 /* Add the rw site for the volume being restored */
2452 entry
.serverNumber
[entry
.nServers
] = toserver
;
2453 entry
.serverPartition
[entry
.nServers
] = topart
;
2454 entry
.serverFlags
[entry
.nServers
] = VLSF_RWVOL
;
2457 /* This volume should be deleted on the old site
2458 * if its different from new site.
2460 VLDB_IsSameAddrs(cellHandle
, toserver
,
2461 entry
.serverNumber
[index
], &same
, &tst
);
2463 || (entry
.serverPartition
[index
] != topart
)) {
2465 UV_Bind(cellHandle
, entry
.serverNumber
[index
],
2466 AFSCONF_VOLUMEPORT
);
2468 AFSVolTransCreate(tempconn
, pvolid
,
2469 entry
.serverPartition
[index
],
2470 ITOffline
, &temptid
);
2473 AFSVolSetFlags(tempconn
, temptid
,
2477 goto fail_UV_RestoreVolume
;
2479 tst
= AFSVolDeleteVolume(tempconn
, temptid
);
2481 goto fail_UV_RestoreVolume
;
2483 tst
= AFSVolEndTrans(tempconn
, temptid
, &rcode
);
2488 goto fail_UV_RestoreVolume
;
2490 vos_PartitionIdToName(entry
.serverPartition
[index
],
2494 entry
.serverNumber
[index
] = toserver
;
2495 entry
.serverPartition
[index
] = topart
;
2498 entry
.flags
|= VLF_RWEXISTS
;
2499 if (!VLDB_ReplaceEntry
2500 (cellHandle
, pvolid
, RWVOL
, &entry
,
2501 LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
, &tst
)) {
2502 goto fail_UV_RestoreVolume
;
2509 fail_UV_RestoreVolume
:
2512 etst
= rx_EndCall(tocall
, 0);
2518 ubik_VL_ReleaseLock(cellHandle
->vos
, 0, pvolid
, RWVOL
,
2519 LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
);
2526 etst
= AFSVolEndTrans(toconn
, totid
, &rcode
);
2535 etst
= AFSVolEndTrans(toconn
, temptid
, &rcode
);
2545 rx_ReleaseCachedConnection(tempconn
);
2547 rx_ReleaseCachedConnection(toconn
);
2555 /*adds <server> and <part> as a readonly replication site for <volid>
2558 UV_AddSite(afs_cell_handle_p cellHandle
, afs_int32 server
, afs_int32 part
,
2559 afs_uint32 volid
, afs_status_p st
)
2562 afs_status_t tst
= 0;
2563 int j
, nro
= 0, islocked
= 0;
2564 struct nvldbentry entry
;
2568 ubik_VL_SetLock(cellHandle
->vos
, 0, volid
, RWVOL
, VLOP_ADDSITE
);
2570 goto fail_UV_AddSite
;
2574 if (!aVLDB_GetEntryByID(cellHandle
, volid
, RWVOL
, &entry
, &tst
)) {
2575 goto fail_UV_AddSite
;
2577 if (!ISNAMEVALID(entry
.name
)) {
2579 goto fail_UV_AddSite
;
2582 /* See if it's too many entries */
2583 if (entry
.nServers
>= NMAXNSERVERS
) {
2585 goto fail_UV_AddSite
;
2588 /* See if it's on the same server */
2589 for (j
= 0; j
< entry
.nServers
; j
++) {
2590 if (entry
.serverFlags
[j
] & VLSF_ROVOL
) {
2592 if (!VLDB_IsSameAddrs
2593 (cellHandle
, server
, entry
.serverNumber
[j
], &same
, &tst
)) {
2594 goto fail_UV_AddSite
;
2598 goto fail_UV_AddSite
;
2603 /* See if it's too many RO sites - leave one for the RW */
2604 if (nro
>= NMAXNSERVERS
- 1) {
2606 goto fail_UV_AddSite
;
2609 entry
.serverNumber
[entry
.nServers
] = server
;
2610 entry
.serverPartition
[entry
.nServers
] = part
;
2611 entry
.serverFlags
[entry
.nServers
] = (VLSF_ROVOL
| VLSF_DONTUSE
);
2614 if (!VLDB_ReplaceEntry
2615 (cellHandle
, volid
, RWVOL
, &entry
,
2616 LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
, &tst
)) {
2617 goto fail_UV_AddSite
;
2626 ubik_VL_ReleaseLock(cellHandle
->vos
, 0, volid
, RWVOL
,
2627 LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
);
2636 /*removes <server> <part> as read only site for <volid> from the vldb */
2638 UV_RemoveSite(afs_cell_handle_p cellHandle
, afs_int32 server
, afs_int32 part
,
2639 afs_uint32 volid
, afs_status_p st
)
2642 afs_status_t tst
= 0;
2643 struct nvldbentry entry
;
2647 ubik_VL_SetLock(cellHandle
->vos
, 0, volid
, RWVOL
, VLOP_ADDSITE
);
2649 goto fail_UV_RemoveSite
;
2653 if (!aVLDB_GetEntryByID(cellHandle
, volid
, RWVOL
, &entry
, &tst
)) {
2654 goto fail_UV_RemoveSite
;
2656 if (!Lp_ROMatch(cellHandle
, &entry
, server
, part
, &tst
)) {
2657 /*this site doesnot exist */
2658 goto fail_UV_RemoveSite
;
2659 } else { /*remove the rep site */
2660 Lp_SetROValue(cellHandle
, &entry
, server
, part
, 0, 0);
2662 if ((entry
.nServers
== 1) && (entry
.flags
& VLF_RWEXISTS
))
2663 entry
.flags
&= ~VLF_ROEXISTS
;
2664 if (entry
.nServers
< 1) { /*this is the last ref */
2665 tst
= ubik_VL_DeleteEntry(cellHandle
->vos
, 0, volid
, ROVOL
);
2667 goto fail_UV_RemoveSite
;
2670 if (!VLDB_ReplaceEntry
2671 (cellHandle
, volid
, RWVOL
, &entry
,
2672 (LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
), &tst
)) {
2673 goto fail_UV_RemoveSite
;
2682 t
= ubik_VL_ReleaseLock(cellHandle
->vos
, 0, volid
, RWVOL
,
2683 LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
);
2695 /*list all the partitions on <aserver> */
2697 UV_ListPartitions(struct rx_connection
*server
, struct partList
*ptrPartList
,
2698 afs_int32
* cntp
, afs_status_p st
)
2701 afs_status_t tst
= 0;
2702 struct pIDs partIds
;
2703 struct partEntries partEnts
;
2708 partEnts
.partEntries_len
= 0;
2709 partEnts
.partEntries_val
= NULL
;
2710 /* this is available only on new servers */
2711 tst
= AFSVolXListPartitions(server
, &partEnts
);
2713 /* next, try old interface */
2714 if (tst
== RXGEN_OPCODE
) {
2715 for (i
= 0; i
< 26; i
++)
2716 partIds
.partIds
[i
] = -1;
2717 tst
= AFSVolListPartitions(server
, &partIds
);
2719 for (i
= 0; i
< 26; i
++) {
2720 if ((partIds
.partIds
[i
]) != -1) {
2721 ptrPartList
->partId
[j
] = partIds
.partIds
[i
];
2722 ptrPartList
->partFlags
[j
] = PARTVALID
;
2725 ptrPartList
->partFlags
[i
] = 0;
2729 goto fail_UV_ListPartitions
;
2732 *cntp
= partEnts
.partEntries_len
;
2733 if (*cntp
> VOLMAXPARTS
) {
2734 *cntp
= VOLMAXPARTS
;
2736 for (i
= 0; i
< *cntp
; i
++) {
2737 ptrPartList
->partId
[i
] = partEnts
.partEntries_val
[i
];
2738 ptrPartList
->partFlags
[i
] = PARTVALID
;
2740 free(partEnts
.partEntries_val
);
2742 goto fail_UV_ListPartitions
;
2746 fail_UV_ListPartitions
:
2754 /*------------------------------------------------------------------------
2755 * EXPORTED UV_XListVolumes
2758 * List the extended information for all the volumes on a particular
2759 * File Server and partition. We may either return the volume's ID
2760 * or all of its extended information.
2763 * a_serverID : Address of the File Server for which we want
2764 * extended volume info.
2765 * a_partID : Partition for which we want the extended
2767 * a_all : If non-zero, fetch ALL the volume info,
2768 * otherwise just the volume ID.
2769 * a_resultPP : Ptr to the address of the area containing
2770 * the returned volume info.
2771 * a_numEntsInResultP : Ptr for the value we set for the number of
2776 * Otherise, the return value of AFSVolXListVolumes.
2779 * This routine is closely related to UV_ListVolumes, which returns
2780 * only the standard level of detail on AFS volumes. It is a
2781 * heavyweight operation, zipping through all the volume entries for
2782 * a given server/partition.
2786 *------------------------------------------------------------------------*/
2789 UV_XListVolumes(struct rx_connection
*server
, afs_int32 a_partID
, int a_all
,
2790 struct volintXInfo
**a_resultPP
,
2791 afs_int32
* a_numEntsInResultP
, afs_status_p st
)
2794 afs_status_t tst
= 0;
2796 volXEntries volumeXInfo
; /*Area for returned extended vol info */
2799 * Set up our error code and the area for returned extended volume info.
2800 * We set the val field to a null pointer as a hint for the stub to
2803 *a_numEntsInResultP
= 0;
2804 *a_resultPP
= (volintXInfo
*) 0;
2805 volumeXInfo
.volXEntries_val
= (volintXInfo
*) 0;
2806 volumeXInfo
.volXEntries_len
= 0;
2809 * Bind to the Volume Server port on the File Server machine in question,
2812 tst
= AFSVolXListVolumes(server
, a_partID
, a_all
, &volumeXInfo
);
2814 goto fail_UV_XListVolumes
;
2817 * We got the info; pull out the pointer to where the results lie
2818 * and how many entries are there.
2820 *a_resultPP
= volumeXInfo
.volXEntries_val
;
2821 *a_numEntsInResultP
= volumeXInfo
.volXEntries_len
;
2825 fail_UV_XListVolumes
:
2833 /*------------------------------------------------------------------------
2834 * EXPORTED UV_XListOneVolume
2837 * List the extended information for a volume on a particular File
2838 * Server and partition.
2841 * server : a handle to the server where the volume resides.
2842 * a_partID : Partition for which we want the extended
2844 * a_volID : Volume ID for which we want the info.
2845 * a_resultPP : Ptr to the address of the area containing
2846 * the returned volume info.
2850 * Otherise, the return value of AFSVolXListOneVolume.
2853 * This routine is closely related to UV_ListOneVolume, which returns
2854 * only the standard level of detail on the chosen AFS volume.
2858 *------------------------------------------------------------------------*/
2861 UV_XListOneVolume(struct rx_connection
*server
, afs_int32 a_partID
,
2862 afs_uint32 a_volID
, struct volintXInfo
**a_resultPP
,
2866 afs_status_t tst
= 0;
2867 volXEntries volumeXInfo
; /*Area for returned info */
2870 * Set the area we're in which we are returning
2871 * the info. Setting the val field to a null pointer tells the stub
2872 * to allocate space for us.
2874 *a_resultPP
= (volintXInfo
*) 0;
2875 volumeXInfo
.volXEntries_val
= (volintXInfo
*) 0;
2876 volumeXInfo
.volXEntries_len
= 0;
2878 tst
= AFSVolXListOneVolume(server
, a_partID
, a_volID
, &volumeXInfo
);
2881 goto fail_UV_XListOneVolume
;
2884 * We got the info; pull out the pointer to where the results lie.
2886 *a_resultPP
= volumeXInfo
.volXEntries_val
;
2890 fail_UV_XListOneVolume
:
2897 } /*UV_XListOneVolume */
2899 /*------------------------------------------------------------------------
2900 * EXPORTED UV_ListOneVolume
2903 * List the volume information for a volume on a particular File
2904 * Server and partition.
2907 * server : a handle to the server where the volume resides.
2908 * a_partID : Partition for which we want the extended
2910 * a_volID : Volume ID for which we want the info.
2911 * a_resultPP : Ptr to the address of the area containing
2912 * the returned volume info.
2916 * Otherise, the return value of AFSVolXListOneVolume.
2920 *------------------------------------------------------------------------*/
2922 int UV_ListOneVolume(struct rx_connection
*server
, afs_int32 a_partID
,
2923 afs_uint32 a_volID
, struct volintInfo
**a_resultPP
,
2927 afs_status_t tst
= 0;
2928 volEntries volumeInfo
; /*Area for returned info */
2931 * Set the area we're in which we are returning
2932 * the info. Setting the val field to a null pointer tells the stub
2933 * to allocate space for us.
2935 *a_resultPP
= (volintInfo
*) 0;
2936 volumeInfo
.volEntries_val
= (volintInfo
*) 0;
2937 volumeInfo
.volEntries_len
= 0;
2939 tst
= AFSVolListOneVolume(server
, a_partID
, a_volID
, &volumeInfo
);
2942 goto fail_UV_ListOneVolume
;
2945 * We got the info; pull out the pointer to where the results lie.
2947 *a_resultPP
= volumeInfo
.volEntries_val
;
2951 fail_UV_ListOneVolume
:
2957 }/*UV_ListOneVolume*/
2959 /*sync vldb with all the entries on <myQueue> on <aserver> and <apart>*/
2961 ProcessEntries(afs_cell_handle_p cellHandle
, struct qHead
*myQueue
,
2962 struct rx_connection
*server
, afs_int32 apart
, afs_int32 force
)
2968 afs_uint32 maxVolid
= 0;
2969 struct nvldbentry entry
;
2970 int noError
= 1, error
, same
;
2971 int totalC
, totalU
, totalCE
, totalUE
, totalG
;
2973 int aserver
= ntohl(rx_HostOf(rx_PeerOf(server
)));
2976 totalC
= totalU
= totalCE
= totalUE
= totalG
= 0;
2979 /* get the next available id's from the vldb server */
2980 vcode
= ubik_VL_GetNewVolumeId(cellHandle
->vos
, 0, 0, &maxVolid
);
2984 totalG
= myQueue
->count
;
2988 Lp_QEnumerate(myQueue
, &success
, &elem
, 0);
2993 if (!elem
.isValid
[RWVOL
] && !elem
.isValid
[ROVOL
] && !elem
.isValid
[BACKVOL
]) { /*something is wrong with elem */
2997 if (maxVolid
<= elem
.ids
[RWVOL
]) {
2998 temp2
= elem
.ids
[RWVOL
] - maxVolid
+ 1;
3000 vcode
= ubik_VL_GetNewVolumeId(cellHandle
->vos
, 0, temp2
,
3007 if (maxVolid
<= elem
.ids
[ROVOL
]) {
3008 temp2
= elem
.ids
[ROVOL
] - maxVolid
+ 1;
3010 vcode
= ubik_VL_GetNewVolumeId(cellHandle
->vos
, 0, temp2
,
3017 if (maxVolid
<= elem
.ids
[BACKVOL
]) {
3018 temp2
= elem
.ids
[BACKVOL
] - maxVolid
+ 1;
3020 vcode
= ubik_VL_GetNewVolumeId(cellHandle
->vos
, 0, temp2
,
3027 aVLDB_GetEntryByID(cellHandle
, elem
.ids
[RWVOL
], RWVOL
, &entry
, &tst
);
3028 if (tst
&& (tst
!= VL_NOENT
)) {
3031 } else if (tst
&& (tst
== VL_NOENT
)) { /*entry doesnot exist */
3032 /*set up a vldb entry for elem */
3033 memset(&entry
, 0, sizeof(entry
));
3034 strncpy(entry
.name
, elem
.name
, VOLSER_OLDMAXVOLNAME
);
3035 if (elem
.isValid
[RWVOL
]) { /*rw exists */
3036 entry
.flags
|= VLF_RWEXISTS
;
3037 entry
.serverFlags
[entry
.nServers
] = VLSF_RWVOL
;
3038 entry
.serverNumber
[entry
.nServers
] = aserver
;
3039 entry
.serverPartition
[entry
.nServers
] = apart
;
3040 entry
.nServers
+= 1;
3041 entry
.volumeId
[RWVOL
] = elem
.ids
[RWVOL
];
3042 entry
.volumeId
[ROVOL
] = elem
.ids
[ROVOL
];
3043 entry
.volumeId
[BACKVOL
] = elem
.ids
[BACKVOL
];
3045 if (elem
.isValid
[ROVOL
]) { /*ro volume exists */
3046 entry
.flags
|= VLF_ROEXISTS
;
3047 entry
.serverFlags
[entry
.nServers
] = VLSF_ROVOL
;
3048 entry
.serverNumber
[entry
.nServers
] = aserver
;
3049 entry
.serverPartition
[entry
.nServers
] = apart
;
3050 entry
.nServers
+= 1;
3051 entry
.volumeId
[RWVOL
] = elem
.ids
[RWVOL
];
3052 entry
.volumeId
[ROVOL
] = elem
.ids
[ROVOL
];
3055 if (elem
.isValid
[BACKVOL
]) { /*backup volume exists */
3056 entry
.flags
|= VLF_BACKEXISTS
;
3057 if (!(entry
.flags
& VLF_RWEXISTS
)) { /*this helps to check for a stray backup if parent moves */
3058 entry
.serverFlags
[entry
.nServers
] = VLSF_RWVOL
;
3059 entry
.serverNumber
[entry
.nServers
] = aserver
;
3060 entry
.serverPartition
[entry
.nServers
] = apart
;
3061 entry
.nServers
+= 1;
3064 entry
.volumeId
[RWVOL
] = elem
.ids
[RWVOL
];
3065 entry
.volumeId
[BACKVOL
] = elem
.ids
[BACKVOL
];
3068 VLDB_CreateEntry(cellHandle
, &entry
, &tst
);
3074 } else { /* Update the existing entry */
3075 strncpy(entry
.name
, elem
.name
, VOLSER_OLDMAXVOLNAME
); /*the name Could have changed */
3077 if (elem
.isValid
[RWVOL
]) { /* A RW volume */
3078 temp
= Lp_GetRwIndex(cellHandle
, &entry
, 0);
3080 /* A RW index is not found in the VLDB entry - will add it */
3082 entry
.flags
|= VLF_RWEXISTS
;
3083 entry
.serverNumber
[entry
.nServers
] = aserver
;
3084 entry
.serverPartition
[entry
.nServers
] = apart
;
3085 entry
.serverFlags
[entry
.nServers
] = VLSF_RWVOL
;
3088 /* A RW index is found in the VLDB entry.
3089 * Verify that the volume location matches the VLDB location.
3090 * Fix the VLDB entry if it is not correct.
3094 VLDB_IsSameAddrs(cellHandle
, aserver
,
3095 entry
.serverNumber
[temp
], &same
,
3100 if (!same
|| (apart
!= entry
.serverPartition
[temp
])) {
3101 /* VLDB says volume is in another place. Fix the VLDB entry */
3102 entry
.serverNumber
[temp
] = aserver
;
3103 entry
.serverPartition
[temp
] = apart
;
3106 entry
.flags
|= VLF_RWEXISTS
;
3108 if ((elem
.ids
[BACKVOL
] != 0) && elem
.isValid
[BACKVOL
])
3109 entry
.volumeId
[BACKVOL
] = elem
.ids
[BACKVOL
];
3110 if ((elem
.ids
[ROVOL
] != 0) && elem
.isValid
[ROVOL
])
3111 entry
.volumeId
[ROVOL
] = elem
.ids
[ROVOL
];
3114 if (elem
.isValid
[ROVOL
]) {
3115 /*tackle a ro volume */
3117 if (!Lp_ROMatch(cellHandle
, &entry
, aserver
, apart
, 0)) {
3119 if (elem
.ids
[ROVOL
] > entry
.volumeId
[ROVOL
]) {
3120 /*there is a conflict of ids, keep the later volume */
3121 /*delete all the ro volumes listed in vldb entry since they
3124 int j
, count
, rwsite
;
3127 count
= entry
.nServers
;
3129 for (j
= 0; j
< count
; j
++) {
3130 if (entry
.serverFlags
[j
] & VLSF_ROVOL
) {
3132 /*delete the site */
3133 entry
.serverNumber
[j
] = 0;
3134 entry
.serverPartition
[j
] = 0;
3135 entry
.serverFlags
[j
] = 0;
3137 } else if (entry
.serverFlags
[j
] & VLSF_RWVOL
)
3142 entry
.serverNumber
[entry
.nServers
] =
3143 entry
.serverNumber
[rwsite
];
3144 entry
.serverPartition
[entry
.nServers
] =
3145 entry
.serverPartition
[rwsite
];
3146 entry
.serverFlags
[entry
.nServers
] =
3147 entry
.serverFlags
[rwsite
];
3150 entry
.serverNumber
[entry
.nServers
] = aserver
;
3151 entry
.serverPartition
[entry
.nServers
] = apart
;
3152 entry
.serverFlags
[entry
.nServers
] = VLSF_ROVOL
;
3154 entry
.volumeId
[ROVOL
] = elem
.ids
[ROVOL
];
3155 entry
.flags
|= VLF_ROEXISTS
;
3157 } else if (elem
.ids
[ROVOL
] < entry
.volumeId
[ROVOL
]) {
3158 if (!(entry
.flags
& VLF_ROEXISTS
)) {
3159 entry
.volumeId
[ROVOL
] = elem
.ids
[ROVOL
];
3160 entry
.serverNumber
[entry
.nServers
] = aserver
;
3161 entry
.serverPartition
[entry
.nServers
] = apart
;
3162 entry
.serverFlags
[entry
.nServers
] = VLSF_ROVOL
;
3164 entry
.flags
|= VLF_ROEXISTS
;
3169 else if (elem
.ids
[ROVOL
] == entry
.volumeId
[ROVOL
]) {
3170 entry
.serverNumber
[entry
.nServers
] = aserver
;
3171 entry
.serverPartition
[entry
.nServers
] = apart
;
3172 entry
.serverFlags
[entry
.nServers
] = VLSF_ROVOL
;
3174 entry
.flags
|= VLF_ROEXISTS
;
3175 entry
.volumeId
[ROVOL
] = elem
.ids
[ROVOL
];
3178 if (entry
.volumeId
[ROVOL
] == INVALID_BID
)
3179 entry
.volumeId
[ROVOL
] = elem
.ids
[ROVOL
];
3182 if (elem
.isValid
[BACKVOL
]) {
3183 temp
= Lp_GetRwIndex(cellHandle
, &entry
, 0);
3184 if (temp
!= -1) { /*check if existing backup site matches with the given arguments */
3186 VLDB_IsSameAddrs(cellHandle
, aserver
,
3187 entry
.serverNumber
[temp
], &same
,
3193 /*tackle the backup volume */
3194 entry
.volumeId
[BACKVOL
] = elem
.ids
[BACKVOL
];
3195 entry
.flags
|= VLF_BACKEXISTS
;
3197 if (entry
.volumeId
[BACKVOL
] == INVALID_BID
)
3198 entry
.volumeId
[BACKVOL
] = elem
.ids
[BACKVOL
];
3201 VLDB_ReplaceEntry(cellHandle
, elem
.ids
[RWVOL
], RWVOL
, &entry
,
3202 LOCKREL_OPCODE
| LOCKREL_AFSID
|
3203 LOCKREL_TIMESTAMP
, &tst
);
3209 ubik_VL_ReleaseLock(cellHandle
->vos
, 0,
3210 elem
.ids
[RWVOL
], RWVOL
,
3211 LOCKREL_OPCODE
| LOCKREL_AFSID
|
3217 } /* else update the existing entry */
3219 } /* End of while(1) */
3227 /*synchronise vldb with the file server <aserver> and <apart>(if flags=1).
3228 *else synchronise with all the valid partitions on <aserver>
3231 UV_SyncVldb(afs_cell_handle_p cellHandle
, struct rx_connection
*server
,
3232 afs_int32 apart
, int flags
, int force
, afs_status_p st
)
3235 afs_status_t tst
= 0;
3238 volEntries volumeInfo
;
3240 struct qHead myQueue
;
3241 struct partList PartList
;
3246 /*this hints the stub to allocate space */
3247 volumeInfo
.volEntries_val
= (volintInfo
*) 0;
3248 volumeInfo
.volEntries_len
= 0;
3250 if (!flags
) { /*generate all the valid partitions */
3251 UV_ListPartitions(server
, &PartList
, &cnt
, &tst
);
3253 goto fail_UV_SyncVldb
;
3256 PartList
.partId
[0] = apart
;
3260 for (i
= 0; i
< cnt
; i
++) {
3261 apart
= PartList
.partId
[i
];
3262 /*this hints the stub to allocate space */
3263 volumeInfo
.volEntries_val
= (volintInfo
*) 0;
3264 volumeInfo
.volEntries_len
= 0;
3265 tst
= AFSVolListVolumes(server
, apart
, 1, &volumeInfo
);
3267 goto fail_UV_SyncVldb
;
3269 count
= volumeInfo
.volEntries_len
;
3270 pntr
= volumeInfo
.volEntries_val
;
3272 if (!vos_PartitionIdToName(apart
, pname
, &tst
)) {
3273 goto fail_UV_SyncVldb
;
3275 /*collect all vol entries by their parentid */
3276 tst
= GroupEntries(server
, pntr
, count
, &myQueue
, apart
);
3279 if (volumeInfo
.volEntries_val
) {
3280 /*free the space allocated by the stub */
3281 free(volumeInfo
.volEntries_val
);
3282 volumeInfo
.volEntries_val
= 0;
3286 tst
= ProcessEntries(cellHandle
, &myQueue
, server
, apart
, force
);
3288 tst
= VOLSERFAILEDOP
;
3289 if (volumeInfo
.volEntries_val
) {
3290 /*free the space allocated by the stub */
3291 free(volumeInfo
.volEntries_val
);
3292 volumeInfo
.volEntries_val
= 0;
3299 tst
= VOLSERFAILEDOP
;
3300 } /* thru all partitions */
3305 if (volumeInfo
.volEntries_val
)
3306 free(volumeInfo
.volEntries_val
);
3319 CheckVldbRWBK(afs_cell_handle_p cellHandle
, struct nvldbentry
*entry
,
3320 afs_int32
* modified
, afs_status_p st
)
3323 afs_status_t tst
= 0;
3329 idx
= Lp_GetRwIndex(cellHandle
, entry
, 0);
3331 /* Check to see if the RW volume exists and set the VLF_RWEXISTS
3334 if (idx
== -1) { /* Did not find a RW entry */
3335 if (entry
->flags
& VLF_RWEXISTS
) { /* ... yet entry says RW exists */
3336 entry
->flags
&= ~VLF_RWEXISTS
; /* ... so say RW does not exist */
3341 (cellHandle
, entry
->serverNumber
[idx
],
3342 entry
->serverPartition
[idx
], entry
->volumeId
[RWVOL
], &tst
)) {
3343 if (!(entry
->flags
& VLF_RWEXISTS
)) { /* ... yet entry says RW does no
3345 entry
->flags
|= VLF_RWEXISTS
; /* ... so say RW does exist */
3348 } else if (tst
== ENODEV
) { /* RW volume does not exist */
3349 if (entry
->flags
& VLF_RWEXISTS
) { /* ... yet entry says RW exists
3351 entry
->flags
&= ~VLF_RWEXISTS
; /* ... so say RW does not exist
3356 /* If VLDB says it didn't exist, then ignore error */
3357 if (entry
->flags
& VLF_RWEXISTS
) {
3358 goto fail_CheckVldbRWBK
;
3363 /* Check to see if the BK volume exists and set the VLF_BACKEXISTS
3364 * flag accordingly. idx already ponts to the RW entry.
3366 if (idx
== -1) { /* Did not find a RW entry */
3367 if (entry
->flags
& VLF_BACKEXISTS
) { /* ... yet entry says BK exists */
3368 entry
->flags
&= ~VLF_BACKEXISTS
; /* ... so say BK does not exist */
3371 } else { /* Found a RW entry */
3373 (cellHandle
, entry
->serverNumber
[idx
],
3374 entry
->serverPartition
[idx
], entry
->volumeId
[BACKVOL
], &tst
)) {
3375 if (!(entry
->flags
& VLF_BACKEXISTS
)) { /* ... yet entry says BK does n
3377 entry
->flags
|= VLF_BACKEXISTS
; /* ... so say BK does exist */
3380 } else if (tst
== ENODEV
) { /* BK volume does not exist */
3381 if (entry
->flags
& VLF_BACKEXISTS
) { /* ... yet entry says BK exists
3383 entry
->flags
&= ~VLF_BACKEXISTS
; /* ... so say BK does not exist
3388 /* If VLDB says it didn't exist, then ignore error */
3389 if (entry
->flags
& VLF_BACKEXISTS
) {
3390 goto fail_CheckVldbRWBK
;
3395 /* If there is an idx but the BK and RW volumes no
3396 * longer exist, then remove the RW entry.
3398 if ((idx
!= -1) && !(entry
->flags
& VLF_RWEXISTS
)
3399 && !(entry
->flags
& VLF_BACKEXISTS
)) {
3400 Lp_SetRWValue(cellHandle
, entry
, entry
->serverNumber
[idx
],
3401 entry
->serverPartition
[idx
], 0L, 0L);
3410 *modified
= modentry
;
3420 CheckVldbRO(afs_cell_handle_p cellHandle
, struct nvldbentry
*entry
,
3421 afs_int32
* modified
, afs_status_p st
)
3424 afs_status_t tst
= 0;
3426 int foundro
= 0, modentry
= 0;
3431 /* Check to see if the RO volumes exist and set the VLF_ROEXISTS
3434 for (idx
= 0; idx
< entry
->nServers
; idx
++) {
3435 if (!(entry
->serverFlags
[idx
] & VLSF_ROVOL
)) {
3436 continue; /* not a RO */
3440 (cellHandle
, entry
->serverNumber
[idx
],
3441 entry
->serverPartition
[idx
], entry
->volumeId
[ROVOL
], &tst
)) {
3443 } else if (tst
== ENODEV
) { /* RW volume does not exist */
3444 Lp_SetROValue(cellHandle
, entry
, entry
->serverNumber
[idx
],
3445 entry
->serverPartition
[idx
], 0L, 0L);
3450 goto fail_CheckVldbRO
;
3454 if (foundro
) { /* A RO volume exists */
3455 if (!(entry
->flags
& VLF_ROEXISTS
)) { /* ... yet entry says RW does not e
3457 entry
->flags
|= VLF_ROEXISTS
; /* ... so say RW does exist */
3460 } else { /* A RO volume does not exist */
3461 if (entry
->flags
& VLF_ROEXISTS
) { /* ... yet entry says RO exists */
3462 entry
->flags
&= ~VLF_ROEXISTS
; /* ... so say RO does not exist */
3471 *modified
= modentry
;
3479 /*ensure that <entry> matches with the info on file servers */
3481 CheckVldb(afs_cell_handle_p cellHandle
, struct nvldbentry
*entry
,
3482 afs_int32
* modified
, afs_status_p st
)
3485 afs_status_t tst
= 0;
3489 afs_int32 modentry
= 0;
3495 if (strlen(entry
->name
) > (VOLSER_OLDMAXVOLNAME
- 10)) {
3497 goto fail_CheckVldb
;
3502 /* Check to see if the VLDB is ok without locking it (pass 1).
3503 * If it will change, then lock the VLDB entry, read it again,
3504 * then make the changes to it (pass 2).
3508 ubik_VL_SetLock(cellHandle
->vos
, 0, entry
->volumeId
[RWVOL
],
3509 RWVOL
, VLOP_DELETE
);
3511 goto fail_CheckVldb
;
3515 if (!aVLDB_GetEntryByID
3516 (cellHandle
, entry
->volumeId
[RWVOL
], RWVOL
, entry
, &tst
)) {
3517 goto fail_CheckVldb
;
3523 /* Check if the RW and BK entries are ok */
3524 if (!CheckVldbRWBK(cellHandle
, entry
, &modentry
, &tst
)) {
3525 goto fail_CheckVldb
;
3527 if (modentry
&& (pass
== 1))
3530 /* Check if the RO volumes entries are ok */
3531 if (!CheckVldbRO(cellHandle
, entry
, &modentry
, &tst
)) {
3532 goto fail_CheckVldb
;
3534 if (modentry
&& (pass
== 1))
3537 /* The VLDB entry has been updated. If it as been modified, then
3538 * write the entry back out the the VLDB.
3544 if (!(entry
->flags
& VLF_RWEXISTS
) && !(entry
->flags
& VLF_BACKEXISTS
)
3545 && !(entry
->flags
& VLF_ROEXISTS
)) {
3546 /* The RW, BK, nor RO volumes do not exist. Delete the VLDB entry */
3548 ubik_VL_DeleteEntry(cellHandle
->vos
, 0,
3549 entry
->volumeId
[RWVOL
], RWVOL
);
3551 goto fail_CheckVldb
;
3554 /* Replace old entry with our new one */
3555 if (!VLDB_ReplaceEntry
3556 (cellHandle
, entry
->volumeId
[RWVOL
], RWVOL
, entry
,
3557 (LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
),
3559 goto fail_CheckVldb
;
3572 ubik_VL_ReleaseLock(cellHandle
->vos
, 0,
3573 entry
->volumeId
[RWVOL
], RWVOL
,
3574 (LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
));
3587 /*synchronise <aserver> <apart>(if flags = 1) with the vldb .
3588 *if flags = 0, synchronise all the valid partitions on <aserver>*/
3590 UV_SyncServer(afs_cell_handle_p cellHandle
, struct rx_connection
*server
,
3591 afs_int32 apart
, int flags
, afs_status_p st
)
3594 afs_status_t tst
= 0;
3596 afs_int32 nentries
, tentries
= 0;
3597 struct VldbListByAttributes attributes
;
3598 nbulkentries arrayEntries
;
3600 struct nvldbentry
*vllist
;
3603 afs_int32 modified
= 0;
3606 arrayEntries
.nbulkentries_val
= 0;
3607 memset(&attributes
, 0, sizeof(attributes
));
3609 /* Set up attributes to search VLDB */
3610 attributes
.server
= ntohl(rx_HostOf(rx_PeerOf(server
)));
3611 attributes
.Mask
= VLLIST_SERVER
;
3613 attributes
.partition
= apart
;
3614 attributes
.Mask
|= VLLIST_PARTITION
;
3617 for (si
= 0; si
!= -1; si
= nsi
) {
3618 /*initialize to hint the stub to alloc space */
3619 memset(&arrayEntries
, 0, sizeof(arrayEntries
));
3620 if (!VLDB_ListAttributes
3621 (cellHandle
, &attributes
, &nentries
, &arrayEntries
, &tst
)) {
3622 goto fail_UV_SyncServer
;
3625 tentries
+= nentries
;
3627 for (j
= 0; j
< nentries
; j
++) { /* process each entry */
3628 vllist
= &arrayEntries
.nbulkentries_val
[j
];
3629 if (!CheckVldb(cellHandle
, vllist
, &modified
, &tst
)) {
3634 if (arrayEntries
.nbulkentries_val
) {
3635 free(arrayEntries
.nbulkentries_val
);
3636 arrayEntries
.nbulkentries_val
= 0;
3643 if (arrayEntries
.nbulkentries_val
) {
3644 free(arrayEntries
.nbulkentries_val
);
3647 tst
= VOLSERFAILEDOP
;
3654 /* rename volume <oldname> to <newname>, changing the names of the related
3655 * readonly and backup volumes. This operation is also idempotent.
3656 * salvager is capable of recovering from rename operation stopping halfway.
3657 * to recover run syncserver on the affected machines,it will force
3658 * renaming to completion. name clashes should have been detected before
3662 UV_RenameVolume(afs_cell_handle_p cellHandle
, struct nvldbentry
*entry
,
3663 char *newname
, afs_status_p st
)
3666 afs_status_t tst
= 0;
3667 afs_status_t etst
= 0;
3670 char nameBuffer
[256];
3672 struct rx_connection
*aconn
;
3675 aconn
= (struct rx_connection
*)0;
3679 tst
= ubik_VL_SetLock(cellHandle
->vos
, 0, entry
->volumeId
[RWVOL
], RWVOL
, VLOP_ADDSITE
); /*last param is dummy */
3681 goto fail_UV_RenameVolume
;
3685 strncpy(entry
->name
, newname
, VOLSER_OLDMAXVOLNAME
);
3687 if (!VLDB_ReplaceEntry
3688 (cellHandle
, entry
->volumeId
[RWVOL
], RWVOL
, entry
, 0, &tst
)) {
3689 goto fail_UV_RenameVolume
;
3691 /*at this stage the intent to rename is recorded in the vldb, as far
3693 * is concerned, oldname is lost */
3694 if (entry
->flags
& VLF_RWEXISTS
) {
3695 index
= Lp_GetRwIndex(cellHandle
, entry
, 0);
3696 if (index
== -1) { /* there is a serious discrepancy */
3697 tst
= VOLSERVLDB_ERROR
;
3698 goto fail_UV_RenameVolume
;
3701 UV_Bind(cellHandle
, entry
->serverNumber
[index
],
3702 AFSCONF_VOLUMEPORT
);
3704 AFSVolTransCreate(aconn
, entry
->volumeId
[RWVOL
],
3705 entry
->serverPartition
[index
], ITOffline
, &tid
);
3706 if (tst
) { /*volume doesnot exist */
3707 goto fail_UV_RenameVolume
;
3708 } else { /*volume exists, process it */
3711 AFSVolSetIdsTypes(aconn
, tid
, newname
, RWVOL
,
3712 entry
->volumeId
[RWVOL
],
3713 entry
->volumeId
[ROVOL
],
3714 entry
->volumeId
[BACKVOL
]);
3716 tst
= AFSVolEndTrans(aconn
, tid
, &rcode
);
3719 goto fail_UV_RenameVolume
;
3722 goto fail_UV_RenameVolume
;
3726 rx_ReleaseCachedConnection(aconn
);
3727 aconn
= (struct rx_connection
*)0;
3729 /*end rw volume processing */
3730 if (entry
->flags
& VLF_BACKEXISTS
) { /*process the backup volume */
3731 index
= Lp_GetRwIndex(cellHandle
, entry
, 0);
3732 if (index
== -1) { /* there is a serious discrepancy */
3733 tst
= VOLSERVLDB_ERROR
;
3734 goto fail_UV_RenameVolume
;
3737 UV_Bind(cellHandle
, entry
->serverNumber
[index
],
3738 AFSCONF_VOLUMEPORT
);
3740 AFSVolTransCreate(aconn
, entry
->volumeId
[BACKVOL
],
3741 entry
->serverPartition
[index
], ITOffline
, &tid
);
3742 if (tst
) { /*volume doesnot exist */
3743 goto fail_UV_RenameVolume
;
3744 } else { /*volume exists, process it */
3745 if (strlen(newname
) > (VOLSER_OLDMAXVOLNAME
- 8)) {
3746 goto fail_UV_RenameVolume
;
3748 strcpy(nameBuffer
, newname
);
3749 strcat(nameBuffer
, ".backup");
3752 AFSVolSetIdsTypes(aconn
, tid
, nameBuffer
, BACKVOL
,
3753 entry
->volumeId
[RWVOL
], 0, 0);
3755 tst
= AFSVolEndTrans(aconn
, tid
, &rcode
);
3758 goto fail_UV_RenameVolume
;
3761 goto fail_UV_RenameVolume
;
3764 } /* end backup processing */
3766 rx_ReleaseCachedConnection(aconn
);
3767 aconn
= (struct rx_connection
*)0;
3768 if (entry
->flags
& VLF_ROEXISTS
) { /*process the ro volumes */
3769 for (i
= 0; i
< entry
->nServers
; i
++) {
3770 if (entry
->serverFlags
[i
] & VLSF_ROVOL
) {
3772 UV_Bind(cellHandle
, entry
->serverNumber
[i
],
3773 AFSCONF_VOLUMEPORT
);
3775 AFSVolTransCreate(aconn
, entry
->volumeId
[ROVOL
],
3776 entry
->serverPartition
[i
], ITOffline
,
3778 if (tst
) { /*volume doesnot exist */
3779 goto fail_UV_RenameVolume
;
3780 } else { /*volume exists, process it */
3781 strcpy(nameBuffer
, newname
);
3782 strcat(nameBuffer
, ".readonly");
3783 if (strlen(nameBuffer
) > (VOLSER_OLDMAXVOLNAME
- 1)) {
3784 goto fail_UV_RenameVolume
;
3787 AFSVolSetIdsTypes(aconn
, tid
, nameBuffer
, ROVOL
,
3788 entry
->volumeId
[RWVOL
], 0, 0);
3790 tst
= AFSVolEndTrans(aconn
, tid
, &rcode
);
3793 goto fail_UV_RenameVolume
;
3796 goto fail_UV_RenameVolume
;
3800 rx_ReleaseCachedConnection(aconn
);
3801 aconn
= (struct rx_connection
*)0;
3807 fail_UV_RenameVolume
:
3811 ubik_VL_ReleaseLock(cellHandle
->vos
, 0,
3812 entry
->volumeId
[RWVOL
], RWVOL
,
3813 LOCKREL_OPCODE
| LOCKREL_AFSID
| LOCKREL_TIMESTAMP
);
3820 etst
= AFSVolEndTrans(aconn
, tid
, &rcode
);
3827 rx_ReleaseCachedConnection(aconn
);
3835 /*group all the volume entries on< apart >by their parentid or by their ids'
3836 *if the volume is rw. <count> is the number of entries to be processesd.
3837 *<pntr> points to the first entry.< myQueue> is the queue with entries
3840 GroupEntries(struct rx_connection
*server
, volintInfo
* pntr
, afs_int32 count
,
3841 struct qHead
*myQueue
, afs_int32 apart
)
3843 struct aqueue
*qPtr
;
3845 afs_int32 curId
, code
;
3847 afs_int32 error
= 0;
3853 for (i
= 0; i
< count
; i
++) { /*process each entry */
3854 if (pntr
->status
) { /* entry is valid */
3855 if (pntr
->type
== RWVOL
)
3856 curId
= pntr
->volid
;
3858 curId
= pntr
->parentID
;
3859 Lp_QScan(myQueue
, curId
, &success
, &qPtr
, 0);
3860 if (success
) { /*entry exists in the queue */
3861 if (pntr
->type
== RWVOL
) {
3862 /*check if the rw exists already, if so hang on the
3863 * later version if the present version is ok */
3864 if (qPtr
->isValid
[RWVOL
]) {
3865 /*this should not happen, there is a serious error here */
3867 error
= VOLSERMULTIRWVOL
;
3869 qPtr
->isValid
[RWVOL
] = 1;
3870 qPtr
->copyDate
[RWVOL
] = pntr
->copyDate
;
3871 if (!qPtr
->isValid
[BACKVOL
])
3872 qPtr
->ids
[BACKVOL
] = pntr
->backupID
;
3873 if (!qPtr
->isValid
[ROVOL
])
3874 qPtr
->ids
[ROVOL
] = pntr
->cloneID
;
3876 } else if (pntr
->type
== BACKVOL
) {
3877 if (qPtr
->isValid
[BACKVOL
]) {
3878 /*do different checks, delete superflous volume */
3879 if (qPtr
->copyDate
[BACKVOL
] > pntr
->copyDate
) {
3880 /*delete the present volume . */
3882 CheckAndDeleteVolume(server
, apart
, 0,
3890 /*delete the older volume after making sure, current one is ok */
3892 CheckAndDeleteVolume(server
, apart
,
3894 qPtr
->ids
[BACKVOL
]);
3900 qPtr
->copyDate
[BACKVOL
] = pntr
->copyDate
;
3901 qPtr
->ids
[BACKVOL
] = pntr
->volid
;
3905 qPtr
->isValid
[BACKVOL
] = 1;
3906 qPtr
->ids
[BACKVOL
] = pntr
->volid
;
3907 qPtr
->copyDate
[BACKVOL
] = pntr
->copyDate
;
3909 } else if (pntr
->type
== ROVOL
) {
3910 if (qPtr
->isValid
[ROVOL
]) {
3911 /*do different checks, delete superflous volume */
3912 if (qPtr
->copyDate
[ROVOL
] > pntr
->copyDate
) {
3913 /*delete the present volume . */
3916 CheckAndDeleteVolume(server
, apart
, 0,
3923 /*delete the older volume after making sure, current one is ok */
3925 CheckAndDeleteVolume(server
, apart
,
3933 qPtr
->copyDate
[ROVOL
] = pntr
->copyDate
;
3934 qPtr
->ids
[ROVOL
] = pntr
->volid
;
3938 qPtr
->isValid
[ROVOL
] = 1;
3939 qPtr
->ids
[ROVOL
] = pntr
->volid
;
3940 qPtr
->copyDate
[ROVOL
] = pntr
->copyDate
;
3944 error
= VOLSERBADOP
;
3946 } else { /*create a fresh entry */
3947 qPtr
= malloc(sizeof(struct aqueue
));
3948 if (pntr
->type
== RWVOL
) {
3949 qPtr
->isValid
[RWVOL
] = 1;
3950 qPtr
->isValid
[BACKVOL
] = 0;
3951 qPtr
->isValid
[ROVOL
] = 0;
3952 qPtr
->ids
[RWVOL
] = pntr
->volid
;
3953 qPtr
->ids
[BACKVOL
] = pntr
->backupID
;
3954 qPtr
->ids
[ROVOL
] = pntr
->cloneID
;
3955 qPtr
->copyDate
[RWVOL
] = pntr
->copyDate
;
3956 strncpy(qPtr
->name
, pntr
->name
, VOLSER_OLDMAXVOLNAME
);
3958 } else if (pntr
->type
== BACKVOL
) {
3959 qPtr
->isValid
[RWVOL
] = 0;
3960 qPtr
->isValid
[BACKVOL
] = 1;
3961 qPtr
->isValid
[ROVOL
] = 0;
3962 qPtr
->ids
[RWVOL
] = pntr
->parentID
;
3963 qPtr
->ids
[BACKVOL
] = pntr
->volid
;
3964 qPtr
->ids
[ROVOL
] = 0;
3965 qPtr
->copyDate
[BACKVOL
] = pntr
->copyDate
;
3966 vsu_ExtractName(qPtr
->name
, pntr
->name
);
3968 } else if (pntr
->type
== ROVOL
) {
3969 qPtr
->isValid
[RWVOL
] = 0;
3970 qPtr
->isValid
[BACKVOL
] = 0;
3971 qPtr
->isValid
[ROVOL
] = 1;
3972 qPtr
->ids
[RWVOL
] = pntr
->parentID
;
3973 qPtr
->ids
[BACKVOL
] = 0;
3974 qPtr
->ids
[ROVOL
] = pntr
->volid
;
3975 qPtr
->copyDate
[ROVOL
] = pntr
->copyDate
;
3976 vsu_ExtractName(qPtr
->name
, pntr
->name
);
3980 Lp_QAdd(myQueue
, qPtr
);
3982 pntr
++; /*get next entry */
3992 /*report on all the active transactions on volser */
3994 UV_VolserStatus(struct rx_connection
*server
, transDebugInfo
** rpntr
,
3995 afs_int32
* rcount
, afs_status_p st
)
3998 afs_status_t tst
= 0;
3999 transDebugEntries transInfo
;
4001 transInfo
.transDebugEntries_val
= (transDebugInfo
*) 0;
4002 transInfo
.transDebugEntries_len
= 0;
4003 tst
= AFSVolMonitor(server
, &transInfo
);
4005 goto fail_UV_VolserStatus
;
4008 *rcount
= transInfo
.transDebugEntries_len
;
4009 *rpntr
= transInfo
.transDebugEntries_val
;
4012 fail_UV_VolserStatus
:
4015 if (transInfo
.transDebugEntries_val
) {
4016 free(transInfo
.transDebugEntries_val
);
4026 /*delete the volume without interacting with the vldb */
4028 UV_VolumeZap(afs_cell_handle_p cellHandle
, struct rx_connection
*server
,
4029 unsigned int partition
, afs_uint32 volumeId
, afs_status_p st
)
4031 afs_int32 rcode
, ttid
;
4033 afs_status_t tst
= 0;
4037 tst
= AFSVolTransCreate(server
, volumeId
, partition
, ITOffline
, &ttid
);
4039 tst
= AFSVolDeleteVolume(server
, ttid
);
4041 tst
= AFSVolEndTrans(server
, ttid
, &rcode
);
4049 * We failed to delete the volume, but we still need
4050 * to end the transaction.
4052 AFSVolEndTrans(server
, ttid
, &rcode
);
4064 UV_SetVolume(struct rx_connection
*server
, afs_int32 partition
,
4065 afs_uint32 volid
, afs_int32 transflag
, afs_int32 setflag
,
4066 unsigned int sleepTime
, afs_status_p st
)
4069 afs_status_t tst
= 0;
4070 afs_status_t etst
= 0;
4074 tst
= AFSVolTransCreate(server
, volid
, partition
, transflag
, &tid
);
4076 goto fail_UV_SetVolume
;
4079 tst
= AFSVolSetFlags(server
, tid
, setflag
);
4081 goto fail_UV_SetVolume
;
4092 etst
= AFSVolEndTrans(server
, tid
, &rcode
);
4093 /* FIXME: this looks like a typo */
4096 tst
= (etst
? etst
: rcode
);