volid-unsigned-int32-20090323
[openafs.git] / src / libadmin / vos / vsprocs.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
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.
16  *
17  * Other changes were made to provide thread safe functions and
18  * eliminate the practice of reporting errors to STDOUT.
19  */
20
21 #include <afsconfig.h>
22 #include <afs/param.h>
23
24 RCSID
25     ("$Header$");
26
27 #include "vsprocs.h"
28 #include "vosutils.h"
29 #include "lockprocs.h"
30 #include "../adminutil/afs_AdminInternal.h"
31 #include <afs/afs_AdminErrors.h>
32 #include "afs_vosAdmin.h"
33 #include <string.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #ifdef AFS_NT40_ENV
38 #include <io.h>
39 #endif
40
41 static afs_int32 GroupEntries();
42
43 struct release {
44     afs_int32 time;
45     afs_int32 vldbEntryIndex;
46 };
47
48 static struct rx_connection *
49 UV_Bind(afs_cell_handle_p cellHandle, afs_int32 aserver, afs_int32 port)
50 {
51     return rx_GetCachedConnection(htonl(aserver), htons(port), VOLSERVICE_ID,
52                                   cellHandle->tokens->afs_sc[cellHandle->
53                                                              tokens->
54                                                              sc_index],
55                                   cellHandle->tokens->sc_index);
56 }
57
58
59 /* if <okvol> is allright(indicated by beibg able to
60  * start a transaction, delete the <delvol> */
61 static afs_int32
62 CheckAndDeleteVolume(struct rx_connection *aconn, afs_int32 apart,
63                      afs_uint32 okvol, afs_uint32 delvol)
64 {
65     afs_int32 error, code, tid, rcode;
66
67     error = 0;
68     code = 0;
69
70     if (okvol == 0) {
71         code = AFSVolTransCreate(aconn, delvol, apart, ITOffline, &tid);
72         if (!error && code)
73             error = code;
74         code = AFSVolDeleteVolume(aconn, tid);
75         if (!error && code)
76             error = code;
77         code = AFSVolEndTrans(aconn, tid, &rcode);
78         if (!code)
79             code = rcode;
80         if (!error && code)
81             error = code;
82         return error;
83     } else {
84         code = AFSVolTransCreate(aconn, okvol, apart, ITOffline, &tid);
85         if (!code) {
86             code = AFSVolEndTrans(aconn, tid, &rcode);
87             if (!code)
88                 code = rcode;
89             if (!error && code)
90                 error = code;
91             code = AFSVolTransCreate(aconn, delvol, apart, ITOffline, &tid);
92             if (!error && code)
93                 error = code;
94             code = AFSVolDeleteVolume(aconn, tid);
95             if (!error && code)
96                 error = code;
97             code = AFSVolEndTrans(aconn, tid, &rcode);
98             if (!code)
99                 code = rcode;
100             if (!error && code)
101                 error = code;
102         } else
103             error = code;
104         return error;
105     }
106 }
107
108 /* forcibly remove a volume.  Very dangerous call */
109 int
110 UV_NukeVolume(afs_cell_handle_p cellHandle, struct rx_connection *server,
111               unsigned int partition, afs_uint32 volumeId, afs_status_p st)
112 {
113     int rc = 0;
114     afs_status_t tst = 0;
115
116     tst = AFSVolNukeVolume(server, partition, volumeId);
117
118     if (!tst) {
119         rc = 1;
120     }
121
122     if (st != NULL) {
123         *st = tst;
124     }
125     return rc;
126 }
127
128 /* create a volume, given a server, partition number, volume name --> sends
129 * back new vol id in <anewid>*/
130 int
131 UV_CreateVolume(afs_cell_handle_p cellHandle, struct rx_connection *server,
132                 unsigned int partition, const char *volumeName,
133                 unsigned int quota, afs_uint32 *volumeId, afs_status_p st)
134 {
135     int rc = 0;
136     afs_status_t tst = 0;
137     afs_int32 tid = 0;
138     afs_int32 rcode;
139     struct nvldbentry entry;
140     struct volintInfo tstatus;
141
142     memset(&tstatus, 0, sizeof(tstatus));
143     tstatus.dayUse = -1;
144     tstatus.maxquota = quota;
145
146     /* next the next 3 available ids from the VLDB */
147     tst = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 3, volumeId);
148     if (tst) {
149         goto fail_UV_CreateVolume;
150     }
151
152     tst =
153         AFSVolCreateVolume(server, partition, volumeName, volser_RW, 0,
154                            volumeId, &tid);
155     if (tst) {
156         goto fail_UV_CreateVolume;
157     }
158
159     AFSVolSetInfo(server, tid, &tstatus);
160
161     tst = AFSVolSetFlags(server, tid, 0);
162     if (tst) {
163         goto fail_UV_CreateVolume;
164     }
165
166     /* set up the vldb entry for this volume */
167     strncpy(entry.name, volumeName, VOLSER_OLDMAXVOLNAME);
168     entry.nServers = 1;
169     entry.serverNumber[0] = ntohl(rx_HostOf(rx_PeerOf(server)));
170     entry.serverPartition[0] = partition;
171     entry.flags = RW_EXISTS;
172     entry.serverFlags[0] = ITSRWVOL;
173     entry.volumeId[RWVOL] = *volumeId;
174     entry.volumeId[ROVOL] = *volumeId + 1;
175     entry.volumeId[BACKVOL] = *volumeId + 2;
176     entry.cloneId = 0;
177
178     if (!VLDB_CreateEntry(cellHandle, &entry, &tst)) {
179         AFSVolDeleteVolume(server, tid);
180         goto fail_UV_CreateVolume;
181     }
182
183     tst = AFSVolEndTrans(server, tid, &rcode);
184     tid = 0;
185     if (tst) {
186         goto fail_UV_CreateVolume;
187     }
188     rc = 1;
189
190   fail_UV_CreateVolume:
191
192     if (tid != 0) {
193         AFSVolEndTrans(server, tid, &rcode);
194     }
195
196     if (st != NULL) {
197         *st = tst;
198     }
199     return rc;
200 }
201
202
203 /* Delete the volume <volid>on <aserver> <apart>
204  * the physical entry gets removed from the vldb only if the ref count 
205  * becomes zero
206  */
207 int
208 UV_DeleteVolume(afs_cell_handle_p cellHandle, struct rx_connection *server,
209                 unsigned int partition, afs_uint32 volumeId,
210                 afs_status_p st)
211 {
212     int rc = 0;
213     afs_status_t tst = 0;
214     afs_status_t temp = 0;
215     int serverAddr = ntohl(rx_HostOf(rx_PeerOf(server)));
216
217     afs_int32 ttid = 0;
218     afs_int32 rcode;
219     struct nvldbentry entry;
220     int islocked = 0;
221     afs_int32 avoltype = -1, vtype;
222     int notondisk = 0, notinvldb = 0;
223
224     /* Find and read the VLDB entry for this volume */
225     tst =
226         ubik_VL_SetLock(cellHandle->vos, 0, volumeId, avoltype,
227                   VLOP_DELETE);
228     if (tst) {
229         if (tst != VL_NOENT) {
230             goto fail_UV_DeleteVolume;
231         }
232         notinvldb = 1;
233     } else {
234         islocked = 1;
235
236         if (!aVLDB_GetEntryByID(cellHandle, volumeId, avoltype, &entry, &tst)) {
237             goto fail_UV_DeleteVolume;
238         }
239
240     }
241
242     /* Whether volume is in the VLDB or not. Delete the volume on disk */
243     tst = AFSVolTransCreate(server, volumeId, partition, ITOffline, &ttid);
244     if (tst) {
245         if (tst == VNOVOL) {
246             notondisk = 1;
247         } else {
248             goto fail_UV_DeleteVolume;
249         }
250     } else {
251         tst = AFSVolDeleteVolume(server, ttid);
252         if (tst) {
253             goto fail_UV_DeleteVolume;
254         }
255         tst = AFSVolEndTrans(server, ttid, &rcode);
256         tst = (tst ? tst : rcode);
257         ttid = 0;
258         if (tst) {
259             goto fail_UV_DeleteVolume;
260         }
261     }
262
263     if (notinvldb) {
264         goto fail_UV_DeleteVolume;
265     }
266
267     if (volumeId == entry.volumeId[BACKVOL]) {
268         if (!(entry.flags & BACK_EXISTS)
269             || !Lp_Match(cellHandle, &entry, serverAddr, partition, &tst)) {
270             notinvldb = 2;
271             goto fail_UV_DeleteVolume;
272         }
273
274         entry.flags &= ~BACK_EXISTS;
275         vtype = BACKVOL;
276     }
277
278     else if (volumeId == entry.volumeId[ROVOL]) {
279         if (!Lp_ROMatch(cellHandle, &entry, serverAddr, partition, &tst)) {
280             notinvldb = 2;
281             goto fail_UV_DeleteVolume;
282         }
283
284         Lp_SetROValue(cellHandle, &entry, serverAddr, partition, 0, 0);
285         entry.nServers--;
286         if (!Lp_ROMatch(cellHandle, &entry, 0, 0, &tst)) {
287             entry.flags &= ~RO_EXISTS;
288         }
289         vtype = ROVOL;
290     }
291
292     else if (volumeId == entry.volumeId[RWVOL]) {
293         if (!(entry.flags & RW_EXISTS)
294             || !Lp_Match(cellHandle, &entry, serverAddr, partition, &tst)) {
295             notinvldb = 2;
296             goto fail_UV_DeleteVolume;
297         }
298
299         /* Delete backup if it exists */
300         tst =
301             AFSVolTransCreate(server, entry.volumeId[BACKVOL], partition,
302                               ITOffline, &ttid);
303         if (!tst) {
304             tst = AFSVolDeleteVolume(server, ttid);
305             if (tst) {
306                 goto fail_UV_DeleteVolume;
307             }
308             tst = AFSVolEndTrans(server, ttid, &rcode);
309             ttid = 0;
310             tst = (tst ? tst : rcode);
311             if (tst) {
312                 goto fail_UV_DeleteVolume;
313             }
314         }
315
316         Lp_SetRWValue(cellHandle, &entry, serverAddr, partition, 0L, 0L);
317         entry.nServers--;
318         entry.flags &= ~(BACK_EXISTS | RW_EXISTS);
319         vtype = RWVOL;
320
321     }
322
323     else {
324         notinvldb = 2;          /* Not found on this server and partition */
325         goto fail_UV_DeleteVolume;
326     }
327
328     if ((entry.nServers <= 0) || !(entry.flags & (RO_EXISTS | RW_EXISTS))) {
329         tst = ubik_VL_DeleteEntry(cellHandle->vos, 0, volumeId, vtype);
330         if (tst) {
331             goto fail_UV_DeleteVolume;
332         }
333     } else {
334         if (!VLDB_ReplaceEntry
335             (cellHandle, volumeId, vtype, &entry,
336              (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP), &tst)) {
337             goto fail_UV_DeleteVolume;
338         }
339     }
340     islocked = 0;
341     rc = 1;
342
343   fail_UV_DeleteVolume:
344
345     if (notondisk && notinvldb) {
346         if (!tst)
347             tst = ADMVOSVOLUMENOEXIST;
348     }
349
350     if (ttid) {
351         temp = AFSVolEndTrans(server, ttid, &rcode);
352         temp = (temp ? temp : rcode);
353         if (temp) {
354             if (!tst)
355                 tst = temp;
356         }
357     }
358
359     if (islocked) {
360         temp =
361             ubik_VL_ReleaseLock(cellHandle->vos, 0, volumeId, -1,
362                       (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
363         if (temp) {
364             if (!tst)
365                 tst = temp;
366         }
367     }
368
369     if (st != NULL) {
370         *st = tst;
371     }
372     return rc;
373 }
374
375 #define ONERR(ec, es, ep) if (ec) { fprintf(STDERR, (es), (ep)); error = (ec); goto mfail; }
376
377 /* Move volume <afromvol> on <afromserver> <afrompart> to <atoserver>
378  * <atopart>. The operation is almost idempotent 
379  */
380
381 int
382 UV_MoveVolume(afs_cell_handle_p cellHandle, afs_uint32 afromvol,
383               afs_int32 afromserver, afs_int32 afrompart, afs_int32 atoserver,
384               afs_int32 atopart, afs_status_p st)
385 {
386     int rc = 0;
387     afs_status_t tst = 0;
388     afs_status_t etst = 0;
389     struct rx_connection *toconn, *fromconn;
390     afs_int32 fromtid, totid, clonetid;
391     char vname[64];
392     char *volName = 0;
393     char tmpName[VOLSER_MAXVOLNAME + 1];
394     afs_int32 rcode;
395     afs_int32 fromDate;
396     struct restoreCookie cookie;
397     afs_uint32 newVol, volid, backupId;
398     struct volser_status tstatus;
399     struct destServer destination;
400
401     struct nvldbentry entry;
402     int islocked, pntg;
403     afs_int32 error;
404     int same;
405     afs_int32 store_flags;
406
407 #ifdef  ENABLE_BUGFIX_1165
408     volEntries volumeInfo;
409     struct volintInfo *infop = 0;
410 #endif
411
412     islocked = 0;
413     fromconn = (struct rx_connection *)0;
414     toconn = (struct rx_connection *)0;
415     fromtid = 0;
416     totid = 0;
417     clonetid = 0;
418     error = 0;
419     volid = 0;
420     pntg = 0;
421     backupId = 0;
422     newVol = 0;
423
424     if (!aVLDB_GetEntryByID(cellHandle, afromvol, -1, &entry, &tst)) {
425         goto fail_UV_MoveVolume;
426     }
427
428     if (entry.volumeId[RWVOL] != afromvol) {
429         tst = ADMVOSVOLUMEMOVERWONLY;
430         goto fail_UV_MoveVolume;
431     }
432
433     tst =
434         ubik_VL_SetLock(cellHandle->vos, 0, afromvol, RWVOL, VLOP_MOVE);
435     if (tst) {
436         goto fail_UV_MoveVolume;
437     }
438     islocked = 1;
439
440     if (!aVLDB_GetEntryByID(cellHandle, afromvol, RWVOL, &entry, &tst)) {
441         goto fail_UV_MoveVolume;
442     }
443
444     backupId = entry.volumeId[BACKVOL];
445
446     if (!Lp_Match(cellHandle, &entry, afromserver, afrompart, &tst)) {
447         /* the from server and partition do not exist in the vldb entry corresponding to volid */
448         if (!Lp_Match(cellHandle, &entry, atoserver, atopart, &tst)) {
449             /* the to server and partition do not exist in the vldb entry corresponding to volid */
450             tst =
451                 ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, -1,
452                           (LOCKREL_OPCODE | LOCKREL_AFSID |
453                            LOCKREL_TIMESTAMP));
454             if (tst) {
455                 goto fail_UV_MoveVolume;
456             }
457             tst = VOLSERVOLMOVED;
458             goto fail_UV_MoveVolume;
459         }
460
461         /* delete the volume afromvol on src_server */
462         /* from-info does not exist but to-info does =>
463          * we have already done the move, but the volume
464          * may still be existing physically on from fileserver
465          */
466         fromconn = UV_Bind(cellHandle, afromserver, AFSCONF_VOLUMEPORT);
467         fromtid = 0;
468         pntg = 1;
469
470         tst =
471             AFSVolTransCreate(fromconn, afromvol, afrompart, ITOffline,
472                               &fromtid);
473         if (!tst) {             /* volume exists - delete it */
474             tst =
475                 AFSVolSetFlags(fromconn, fromtid,
476                                VTDeleteOnSalvage | VTOutOfService);
477             if (tst) {
478                 goto fail_UV_MoveVolume;
479             }
480
481             tst = AFSVolDeleteVolume(fromconn, fromtid);
482             if (tst) {
483                 goto fail_UV_MoveVolume;
484             }
485
486             tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
487             fromtid = 0;
488             if (!tst)
489                 tst = rcode;
490             if (tst) {
491                 goto fail_UV_MoveVolume;
492             }
493         }
494
495         /*delete the backup volume now */
496         fromtid = 0;
497         tst =
498             AFSVolTransCreate(fromconn, backupId, afrompart, ITOffline,
499                               &fromtid);
500         if (!tst) {             /* backup volume exists - delete it */
501             tst =
502                 AFSVolSetFlags(fromconn, fromtid,
503                                VTDeleteOnSalvage | VTOutOfService);
504             if (tst) {
505                 goto fail_UV_MoveVolume;
506             }
507
508             tst = AFSVolDeleteVolume(fromconn, fromtid);
509             if (tst) {
510                 goto fail_UV_MoveVolume;
511             }
512
513             tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
514             fromtid = 0;
515             if (!tst)
516                 tst = rcode;
517             if (tst) {
518                 goto fail_UV_MoveVolume;
519             }
520         }
521
522         fromtid = 0;
523         error = 0;
524         goto fail_UV_MoveVolume;
525     }
526
527     /* From-info matches the vldb info about volid,
528      * its ok start the move operation, the backup volume 
529      * on the old site is deleted in the process 
530      */
531     if (afrompart == atopart) {
532         if (!VLDB_IsSameAddrs
533             (cellHandle, afromserver, atoserver, &same, &tst)) {
534             goto fail_UV_MoveVolume;
535         }
536         if (same) {
537             tst = VOLSERVOLMOVED;
538             goto fail_UV_MoveVolume;
539         }
540     }
541
542     pntg = 1;
543     toconn = UV_Bind(cellHandle, atoserver, AFSCONF_VOLUMEPORT);        /* get connections to the servers */
544     fromconn = UV_Bind(cellHandle, afromserver, AFSCONF_VOLUMEPORT);
545     fromtid = totid = 0;        /* initialize to uncreated */
546
547     /* ***
548      * clone the read/write volume locally.
549      * ***/
550
551     tst = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
552     if (tst) {
553         goto fail_UV_MoveVolume;
554     }
555
556     /* Get a clone id */
557     newVol = 0;
558     tst = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 1, &newVol);
559     if (tst) {
560         goto fail_UV_MoveVolume;
561     }
562
563     /* Do the clone. Default flags on clone are set to delete on salvage and out of service */
564     strcpy(vname, "move-clone-temp");
565     tst = AFSVolClone(fromconn, fromtid, 0, readonlyVolume, vname, &newVol);
566     if (tst) {
567         goto fail_UV_MoveVolume;
568     }
569
570     /* lookup the name of the volume we just cloned */
571     volid = afromvol;
572     tst = AFSVolGetName(fromconn, fromtid, &volName);
573     if (tst) {
574         goto fail_UV_MoveVolume;
575     }
576
577     rcode = 0;
578     tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
579     fromtid = 0;
580     if (!tst)
581         tst = rcode;
582     if (tst) {
583         goto fail_UV_MoveVolume;
584     }
585
586     /* ***
587      * Create the destination volume
588      * ***/
589
590     tst =
591         AFSVolTransCreate(fromconn, newVol, afrompart, ITOffline, &clonetid);
592     if (tst) {
593         goto fail_UV_MoveVolume;
594     }
595     tst = AFSVolSetFlags(fromconn, clonetid, VTDeleteOnSalvage | VTOutOfService);       /*redundant */
596     if (tst) {
597         goto fail_UV_MoveVolume;
598     }
599
600     /* remember time from which we've dumped the volume */
601     tst = AFSVolGetStatus(fromconn, clonetid, &tstatus);
602     if (tst) {
603         goto fail_UV_MoveVolume;
604     }
605
606     fromDate = tstatus.creationDate - CLOCKSKEW;
607
608 #ifdef  ENABLE_BUGFIX_1165
609     /*
610      * Get the internal volume state from the source volume. We'll use such info (i.e. dayUse)
611      * to copy it to the new volume (via AFSSetInfo later on) so that when we move volumes we
612      * don't use this information...
613      */
614     volumeInfo.volEntries_val = (volintInfo *) 0;       /*this hints the stub to allocate space */
615     volumeInfo.volEntries_len = 0;
616     tst = AFSVolListOneVolume(fromconn, afrompart, afromvol, &volumeInfo);
617     if (tst) {
618         goto fail_UV_MoveVolume;
619     }
620
621     infop = (volintInfo *) volumeInfo.volEntries_val;
622     infop->maxquota = -1;       /* Else it will replace the default quota */
623 #endif
624
625     /* create a volume on the target machine */
626     volid = afromvol;
627     tst = AFSVolTransCreate(toconn, volid, atopart, ITOffline, &totid);
628     if (!tst) {                 /*delete the existing volume */
629
630         tst = AFSVolDeleteVolume(toconn, totid);
631         if (tst) {
632             goto fail_UV_MoveVolume;
633         }
634
635         tst = AFSVolEndTrans(toconn, totid, &rcode);
636         totid = 0;
637         if (!tst)
638             tst = rcode;
639         if (tst) {
640             goto fail_UV_MoveVolume;
641         }
642
643     }
644
645     tst =
646         AFSVolCreateVolume(toconn, atopart, volName, volser_RW, volid, &volid,
647                            &totid);
648     if (tst) {
649         goto fail_UV_MoveVolume;
650     }
651
652     strncpy(tmpName, volName, VOLSER_OLDMAXVOLNAME);
653     free(volName);
654     volName = NULL;
655
656     tst = AFSVolSetFlags(toconn, totid, (VTDeleteOnSalvage | VTOutOfService));
657     if (tst) {
658         goto fail_UV_MoveVolume;
659     }
660
661     /***
662      * Now dump the clone to the new volume
663      ***/
664
665     destination.destHost = atoserver;
666     destination.destPort = AFSCONF_VOLUMEPORT;
667     destination.destSSID = 1;
668
669     /* Copy the clone to the new volume */
670     strncpy(cookie.name, tmpName, VOLSER_OLDMAXVOLNAME);
671     cookie.type = RWVOL;
672     cookie.parent = entry.volumeId[RWVOL];
673     cookie.clone = 0;
674     tst = AFSVolForward(fromconn, clonetid, 0, &destination, totid, &cookie);
675     if (tst) {
676         goto fail_UV_MoveVolume;
677     }
678
679     tst = AFSVolEndTrans(fromconn, clonetid, &rcode);
680     if (!tst)
681         tst = rcode;
682     clonetid = 0;
683     if (tst) {
684         goto fail_UV_MoveVolume;
685     }
686
687     /* ***
688      * reattach to the main-line volume, and incrementally dump it.
689      * ***/
690
691     tst = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
692     if (tst) {
693         goto fail_UV_MoveVolume;
694     }
695
696     /* now do the incremental */
697     tst =
698         AFSVolForward(fromconn, fromtid, fromDate, &destination, totid,
699                       &cookie);
700     if (tst) {
701         goto fail_UV_MoveVolume;
702     }
703
704     /* now adjust the flags so that the new volume becomes official */
705     tst = AFSVolSetFlags(fromconn, fromtid, VTOutOfService);
706     if (tst) {
707         goto fail_UV_MoveVolume;
708     }
709
710     tst = AFSVolSetFlags(toconn, totid, 0);
711     if (tst) {
712         goto fail_UV_MoveVolume;
713     }
714 #ifdef  ENABLE_BUGFIX_1165
715     tst = AFSVolSetInfo(toconn, totid, infop);
716     if (tst) {
717         goto fail_UV_MoveVolume;
718     }
719 #endif
720
721     /* put new volume online */
722     tst = AFSVolEndTrans(toconn, totid, &rcode);
723     totid = 0;
724     if (!tst)
725         tst = rcode;
726     if (tst) {
727         goto fail_UV_MoveVolume;
728     }
729
730     Lp_SetRWValue(cellHandle, &entry, afromserver, afrompart, atoserver,
731                   atopart);
732     store_flags = entry.flags;
733     entry.flags &= ~BACK_EXISTS;
734
735     if (!VLDB_ReplaceEntry
736         (cellHandle, afromvol, -1, &entry,
737          (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP), &tst)) {
738         goto fail_UV_MoveVolume;
739     }
740     entry.flags = store_flags;
741     islocked = 0;
742
743     if (atoserver != afromserver) {
744         /* set forwarding pointer for moved volumes */
745         tst = AFSVolSetForwarding(fromconn, fromtid, htonl(atoserver));
746         if (tst) {
747             goto fail_UV_MoveVolume;
748         }
749     }
750
751     tst = AFSVolDeleteVolume(fromconn, fromtid);        /* zap original volume */
752     if (tst) {
753         goto fail_UV_MoveVolume;
754     }
755
756     tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
757     fromtid = 0;
758     if (!tst)
759         tst = rcode;
760     if (tst) {
761         goto fail_UV_MoveVolume;
762     }
763
764     /* Delete the backup volume on the original site */
765     tst =
766         AFSVolTransCreate(fromconn, backupId, afrompart, ITOffline, &fromtid);
767     if (!tst) {
768         tst =
769             AFSVolSetFlags(fromconn, fromtid,
770                            VTDeleteOnSalvage | VTOutOfService);
771         if (tst) {
772             goto fail_UV_MoveVolume;
773         }
774
775         tst = AFSVolDeleteVolume(fromconn, fromtid);
776         if (tst) {
777             goto fail_UV_MoveVolume;
778         }
779
780         tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
781         fromtid = 0;
782         if (!tst)
783             tst = rcode;
784         if (tst) {
785             goto fail_UV_MoveVolume;
786         }
787
788     } else
789         tst = 0;                /* no backup volume? that's okay */
790
791     fromtid = 0;
792
793     tst =
794         AFSVolTransCreate(fromconn, newVol, afrompart, ITOffline, &clonetid);
795     if (tst) {
796         goto fail_UV_MoveVolume;
797     }
798
799     /* now delete the clone */
800
801     tst = AFSVolDeleteVolume(fromconn, clonetid);
802     if (tst) {
803         goto fail_UV_MoveVolume;
804     }
805
806     tst = AFSVolEndTrans(fromconn, clonetid, &rcode);
807     if (!tst)
808         tst = rcode;
809     clonetid = 0;
810     if (tst) {
811         goto fail_UV_MoveVolume;
812     }
813
814     /* fall through */
815     /* END OF MOVE */
816
817     /* normal cleanup code */
818
819     if (islocked) {
820         etst =
821             ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, -1,
822                       (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
823         if (etst) {
824             if (!tst)
825                 tst = etst;
826         }
827     }
828
829     if (fromtid) {
830         etst = AFSVolEndTrans(fromconn, fromtid, &rcode);
831         if (etst || rcode) {
832             if (!tst)
833                 tst = (etst ? etst : rcode);
834         }
835     }
836
837     if (clonetid) {
838         etst = AFSVolEndTrans(fromconn, clonetid, &rcode);
839         if (etst || rcode) {
840             if (!tst)
841                 tst = (etst ? etst : rcode);
842         }
843     }
844
845     if (totid) {
846         etst = AFSVolEndTrans(toconn, totid, &rcode);
847         if (etst) {
848             if (!tst)
849                 tst = (etst ? etst : rcode);
850         }
851     }
852     if (volName)
853         free(volName);
854 #ifdef  ENABLE_BUGFIX_1165
855     if (infop)
856         free(infop);
857 #endif
858     if (fromconn)
859         rx_ReleaseCachedConnection(fromconn);
860     if (toconn)
861         rx_ReleaseCachedConnection(toconn);
862
863     rc = 1;
864     if (st != NULL) {
865         *st = tst;
866     }
867     return rc;
868
869     /* come here only when the sky falls */
870
871   fail_UV_MoveVolume:
872
873     /* unlock VLDB entry */
874     if (islocked)
875         ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, -1,
876                   (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
877
878     if (clonetid)
879         AFSVolEndTrans(fromconn, clonetid, &rcode);
880     if (totid)
881         AFSVolEndTrans(toconn, totid, &rcode);
882     if (fromtid) {              /* put it on-line */
883         AFSVolSetFlags(fromconn, fromtid, 0);
884         AFSVolEndTrans(fromconn, fromtid, &rcode);
885     }
886
887     if (!aVLDB_GetEntryByID(cellHandle, afromvol, -1, &entry, &tst)) {
888         goto done;
889     }
890
891     /* Delete either the volume on the source location or the target location. 
892      * If the vldb entry still points to the source location, then we know the
893      * volume move didn't finish so we remove the volume from the target 
894      * location. Otherwise, we remove the volume from the source location.
895      */
896     if (Lp_Match(cellHandle, &entry, afromserver, afrompart, &tst)) {   /* didn't move - delete target volume */
897
898         if (volid && toconn) {
899             tst =
900                 AFSVolTransCreate(toconn, volid, atopart, ITOffline, &totid);
901             if (!tst) {
902                 AFSVolSetFlags(toconn, totid,
903                                VTDeleteOnSalvage | VTOutOfService);
904                 AFSVolDeleteVolume(toconn, totid);
905                 AFSVolEndTrans(toconn, totid, &rcode);
906             }
907         }
908
909         /* put source volume on-line */
910         if (fromconn) {
911             tst =
912                 AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy,
913                                   &fromtid);
914             if (!tst) {
915                 AFSVolSetFlags(fromconn, fromtid, 0);
916                 AFSVolEndTrans(fromconn, fromtid, &rcode);
917             }
918         }
919     } else {                    /* yep, move complete */
920         /* delete backup volume */
921         if (fromconn) {
922             tst =
923                 AFSVolTransCreate(fromconn, backupId, afrompart, ITOffline,
924                                   &fromtid);
925             if (!tst) {
926                 AFSVolSetFlags(fromconn, fromtid,
927                                VTDeleteOnSalvage | VTOutOfService);
928                 AFSVolDeleteVolume(fromconn, fromtid);
929                 AFSVolEndTrans(fromconn, fromtid, &rcode);
930             }
931
932             /* delete source volume */
933             tst =
934                 AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy,
935                                   &fromtid);
936             if (!tst) {
937                 AFSVolSetFlags(fromconn, fromtid,
938                                VTDeleteOnSalvage | VTOutOfService);
939                 if (atoserver != afromserver)
940                     AFSVolSetForwarding(fromconn, fromtid, htonl(atoserver));
941                 AFSVolDeleteVolume(fromconn, fromtid);
942                 AFSVolEndTrans(fromconn, fromtid, &rcode);
943             }
944         }
945     }
946
947     /* common cleanup - delete local clone */
948     if (newVol) {
949         tst =
950             AFSVolTransCreate(fromconn, newVol, afrompart, ITOffline,
951                               &clonetid);
952         if (!tst) {
953             AFSVolDeleteVolume(fromconn, clonetid);
954             AFSVolEndTrans(fromconn, clonetid, &rcode);
955         }
956     }
957
958     /* unlock VLDB entry */
959     ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, -1,
960               (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP));
961
962   done:                 /* routine cleanup */
963     if (volName)
964         free(volName);
965 #ifdef  ENABLE_BUGFIX_1165
966     if (infop)
967         free(infop);
968 #endif
969     if (fromconn)
970         rx_ReleaseCachedConnection(fromconn);
971     if (toconn)
972         rx_ReleaseCachedConnection(toconn);
973
974     if (st != NULL) {
975         *st = tst;
976     }
977     return rc;
978 }
979
980 /* Make a new backup of volume <avolid> on <aserver> and <apart> 
981  * if one already exists, update it 
982  */
983
984 int
985 UV_BackupVolume(afs_cell_handle_p cellHandle, afs_int32 aserver,
986                 afs_int32 apart, afs_uint32 avolid, afs_status_p st)
987 {
988     int rc = 0;
989     afs_status_t tst = 0, temp = 0;
990     afs_int32 ttid = 0, btid = 0;
991     afs_int32 backupID;
992     afs_int32 rcode = 0;
993     char vname[VOLSER_MAXVOLNAME + 1];
994     struct nvldbentry entry;
995     int vldblocked = 0, vldbmod = 0, backexists = 1;
996     struct rx_connection *aconn = UV_Bind(cellHandle, aserver,
997                                           AFSCONF_VOLUMEPORT);
998
999
1000     /* the calls to VLDB will succeed only if avolid is a RW volume,
1001      * since we are following the RW hash chain for searching */
1002     if (!aVLDB_GetEntryByID(cellHandle, avolid, RWVOL, &entry, &tst)) {
1003         goto fail_UV_BackupVolume;
1004     }
1005
1006     /* These operations require the VLDB be locked since it means the VLDB
1007      * will change or the vldb is already locked.
1008      */
1009     if (!(entry.flags & BACK_EXISTS) || /* backup volume doesnt exist */
1010         (entry.flags & VLOP_ALLOPERS) ||        /* vldb lock already held */
1011         (entry.volumeId[BACKVOL] == INVALID_BID)) {
1012         /* no assigned backup volume id */
1013
1014         tst =
1015             ubik_VL_SetLock(cellHandle->vos, 0, avolid, RWVOL,
1016                       VLOP_BACKUP);
1017         if (tst) {
1018             goto fail_UV_BackupVolume;
1019         }
1020         vldblocked = 1;
1021
1022         /* Reread the vldb entry */
1023         if (!aVLDB_GetEntryByID(cellHandle, avolid, RWVOL, &entry, &tst)) {
1024             goto fail_UV_BackupVolume;
1025         }
1026     }
1027
1028     if (!ISNAMEVALID(entry.name)) {
1029         tst = VOLSERBADNAME;
1030         goto fail_UV_BackupVolume;
1031     }
1032
1033     backupID = entry.volumeId[BACKVOL];
1034     if (backupID == INVALID_BID) {
1035         /* Get a backup volume id from the VLDB and update the vldb
1036          * entry with it. 
1037          */
1038         tst = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 1, &backupID);
1039         if (tst) {
1040             goto fail_UV_BackupVolume;
1041         }
1042         entry.volumeId[BACKVOL] = backupID;
1043         vldbmod = 1;
1044     }
1045
1046     /* Test to see if the backup volume exists by trying to create
1047      * a transaction on the backup volume. We've assumed the backup exists.
1048      */
1049     tst = AFSVolTransCreate(aconn, backupID, apart, ITOffline, &btid);
1050     if (tst) {
1051         if (tst != VNOVOL) {
1052             goto fail_UV_BackupVolume;
1053         }
1054         backexists = 0;         /* backup volume does not exist */
1055     }
1056     if (btid) {
1057         tst = AFSVolEndTrans(aconn, btid, &rcode);
1058         btid = 0;
1059         if (tst || rcode) {
1060             tst = (tst ? tst : rcode);
1061             goto fail_UV_BackupVolume;
1062         }
1063     }
1064
1065     /* Now go ahead and try to clone the RW volume.
1066      * First start a transaction on the RW volume 
1067      */
1068     tst = AFSVolTransCreate(aconn, avolid, apart, ITBusy, &ttid);
1069     if (tst) {
1070         goto fail_UV_BackupVolume;
1071     }
1072
1073     /* Clone or reclone the volume, depending on whether the backup 
1074      * volume exists or not
1075      */
1076     if (backexists) {
1077         tst = AFSVolReClone(aconn, ttid, backupID);
1078         if (tst) {
1079             goto fail_UV_BackupVolume;
1080         }
1081     } else {
1082         strcpy(vname, entry.name);
1083         strcat(vname, ".backup");
1084
1085         tst = AFSVolClone(aconn, ttid, 0, backupVolume, vname, &backupID);
1086         if (tst) {
1087             goto fail_UV_BackupVolume;
1088         }
1089     }
1090
1091     /* End transaction on the RW volume */
1092     tst = AFSVolEndTrans(aconn, ttid, &rcode);
1093     ttid = 0;
1094     if (tst || rcode) {
1095         tst = (tst ? tst : rcode);
1096         goto fail_UV_BackupVolume;
1097     }
1098
1099     /* Mork vldb as backup exists */
1100     if (!(entry.flags & BACK_EXISTS)) {
1101         entry.flags |= BACK_EXISTS;
1102         vldbmod = 1;
1103     }
1104
1105     /* Now go back to the backup volume and bring it on line */
1106     tst = AFSVolTransCreate(aconn, backupID, apart, ITOffline, &btid);
1107     if (tst) {
1108         goto fail_UV_BackupVolume;
1109     }
1110
1111     tst = AFSVolSetFlags(aconn, btid, 0);
1112     if (tst) {
1113         goto fail_UV_BackupVolume;
1114     }
1115
1116     tst = AFSVolEndTrans(aconn, btid, &rcode);
1117     btid = 0;
1118     if (tst || rcode) {
1119         tst = (tst ? tst : rcode);
1120         goto fail_UV_BackupVolume;
1121     }
1122     rc = 1;
1123
1124     /* Will update the vldb below */
1125
1126   fail_UV_BackupVolume:
1127
1128     if (ttid) {
1129         temp = AFSVolEndTrans(aconn, ttid, &rcode);
1130         if (temp || rcode) {
1131             if (!tst)
1132                 tst = (temp ? temp : rcode);
1133         }
1134     }
1135
1136     if (btid) {
1137         temp = AFSVolEndTrans(aconn, btid, &rcode);
1138         if (temp || rcode) {
1139             if (!tst)
1140                 tst = (temp ? temp : rcode);
1141         }
1142     }
1143
1144     /* Now update the vldb - if modified */
1145     if (vldblocked) {
1146         if (vldbmod) {
1147             if (!VLDB_ReplaceEntry
1148                 (cellHandle, avolid, RWVOL, &entry,
1149                  (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP),
1150                  &temp)) {
1151                 if (!tst) {
1152                     tst = temp;
1153                 }
1154             }
1155         } else {
1156             temp =
1157                 ubik_VL_ReleaseLock(cellHandle->vos, 0, avolid, RWVOL,
1158                           (LOCKREL_OPCODE | LOCKREL_AFSID |
1159                            LOCKREL_TIMESTAMP));
1160             if (temp) {
1161                 if (!tst) {
1162                     tst = temp;
1163                 }
1164             }
1165         }
1166     }
1167
1168     if (aconn) {
1169         rx_ReleaseCachedConnection(aconn);
1170     }
1171
1172     if (st != NULL) {
1173         *st = tst;
1174     }
1175     return rc;
1176 }
1177
1178 static int
1179 DelVol(struct rx_connection *conn, afs_uint32 vid, afs_int32 part,
1180        afs_int32 flags)
1181 {
1182     afs_int32 acode, ccode, rcode, tid;
1183     ccode = rcode = tid = 0;
1184
1185     acode = AFSVolTransCreate(conn, vid, part, flags, &tid);
1186     if (!acode) {               /* It really was there */
1187         acode = AFSVolDeleteVolume(conn, tid);
1188         ccode = AFSVolEndTrans(conn, tid, &rcode);
1189         if (!ccode)
1190             ccode = rcode;
1191     }
1192
1193     return acode;
1194 }
1195
1196 #define ONERROR(ec, ep, es) if (ec) { fprintf(STDERR, (es), (ep)); error = (ec); goto rfail; }
1197 #define ERROREXIT(ec) { error = (ec); goto rfail; }
1198
1199 #if 0                           /* doesn't appear to be used, why compile it */
1200 static int
1201 CloneVol(afs_cell_handle_p cellHandle, struct rx_connection *conn,
1202          afs_uint32 rwvid, afs_int32 part, afs_uint32 * rovidp, int nottemp,
1203          struct nvldbentry *entry, afs_int32 * vidCreateDate, afs_status_p st)
1204 {
1205     int rc = 0;
1206     afs_status_t tst = 0, etst = 0;
1207     afs_int32 rcode = 0, tid = 0;
1208     struct volser_status volstatus;
1209     char vname[64];
1210
1211     /* Begin transaction on RW volume marking it busy (clients will wait) */
1212     tst = AFSVolTransCreate(conn, rwvid, part, ITBusy, &tid);
1213     if (tst) {
1214         goto fail_CloneVol;
1215     }
1216
1217     /* Get the RO volume id. Allocate a new one if need to */
1218     *rovidp = entry->volumeId[ROVOL];
1219     if (*rovidp == INVALID_BID) {
1220         tst = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 1, rovidp);
1221         if (tst) {
1222             goto fail_CloneVol;
1223         }
1224
1225         entry->volumeId[ROVOL] = *rovidp;
1226     }
1227
1228     /* If we are creating the ro clone, what are we calling it.
1229      * Depends on whether its a temporary clone or not.
1230      */
1231     if (nottemp) {
1232         strcpy(vname, entry->name);
1233         strcat(vname, ".readonly");
1234     } else {
1235         strcpy(vname, "readonly-clone-temp");   /* Should be unique? */
1236     }
1237
1238     /* Create the new clone. If it exists, then reclone it */
1239     tst = AFSVolClone(conn, tid, 0, readonlyVolume, vname, rovidp);
1240     if (tst == VVOLEXISTS) {
1241         tst = AFSVolReClone(conn, tid, *rovidp);
1242         if (tst) {
1243             goto fail_CloneVol;
1244         }
1245     }
1246     if (tst) {
1247         goto fail_CloneVol;
1248     }
1249
1250     /* Bring the volume back on-line as soon as possible */
1251     if (nottemp) {
1252         afs_int32 fromtid = 0;
1253
1254         /* Now bring the RO clone on-line */
1255         tst = AFSVolTransCreate(conn, *rovidp, part, ITOffline, &fromtid);
1256         if (tst) {
1257             goto fail_CloneVol;
1258         }
1259
1260         tst = AFSVolSetFlags(conn, fromtid, 0);
1261         if (tst) {
1262             goto fail_CloneVol;
1263         }
1264
1265         tst = AFSVolEndTrans(conn, fromtid, &rcode);
1266         fromtid = 0;
1267         if (!tst)
1268             tst = rcode;
1269         if (tst) {
1270             goto fail_CloneVol;
1271         }
1272     }
1273
1274     /* Get the time the RW was created for return information */
1275     tst = AFSVolGetStatus(conn, tid, &volstatus);
1276     if (tst) {
1277         goto fail_CloneVol;
1278     }
1279     *vidCreateDate = volstatus.creationDate;
1280     rc = 1;
1281
1282   fail_CloneVol:
1283
1284     if (tid) {
1285         tst = AFSVolEndTrans(conn, tid, &rcode);
1286         tid = 0;
1287         if (!tst)
1288             tst = rcode;
1289         if (tst) {
1290             rc = 0;
1291             goto fail_CloneVol;
1292         }
1293     }
1294
1295     if (st != NULL) {
1296         *st = tst;
1297     }
1298     return rc;
1299 }
1300 #endif
1301
1302 /* Get a "transaction" on this replica.  Create the volume 
1303  * if necessary.  Return the time from which a dump should
1304  * be made (0 if it's a new volume)
1305  */
1306 static int
1307 GetTrans(afs_cell_handle_p cellHandle, struct nvldbentry *vldbEntryPtr,
1308          afs_int32 index, struct rx_connection **connPtr,
1309          afs_int32 * transPtr, afs_int32 * timePtr, afs_status_p st)
1310 {
1311     int rc = 0;
1312     afs_status_t tst = 0, etst = 0;
1313     afs_uint32 volid;
1314     struct volser_status tstatus;
1315     int rcode;
1316
1317     *connPtr = (struct rx_connection *)0;
1318     *timePtr = 0;
1319     *transPtr = 0;
1320
1321     /* get connection to the replication site */
1322     *connPtr =
1323         UV_Bind(cellHandle, vldbEntryPtr->serverNumber[index],
1324                 AFSCONF_VOLUMEPORT);
1325     if (!*connPtr) {
1326         /* server is down */
1327         tst = -1;
1328         goto fail_GetTrans;
1329     }
1330
1331     volid = vldbEntryPtr->volumeId[ROVOL];
1332     if (volid) {
1333         tst =
1334             AFSVolTransCreate(*connPtr, volid,
1335                               vldbEntryPtr->serverPartition[index], ITOffline,
1336                               transPtr);
1337     }
1338
1339     /* If the volume does not exist, create it */
1340     if (!volid || tst) {
1341         char volname[64];
1342
1343         if (volid && (tst != VNOVOL)) {
1344             goto fail_GetTrans;
1345         }
1346
1347         strcpy(volname, vldbEntryPtr->name);
1348         strcat(volname, ".readonly");
1349
1350         tst =
1351             AFSVolCreateVolume(*connPtr, vldbEntryPtr->serverPartition[index],
1352                                volname, volser_RO,
1353                                vldbEntryPtr->volumeId[RWVOL], &volid,
1354                                transPtr);
1355         if (tst) {
1356             goto fail_GetTrans;
1357         }
1358         vldbEntryPtr->volumeId[ROVOL] = volid;
1359
1360         /* The following is a bit redundant, since create sets these flags by default */
1361         tst =
1362             AFSVolSetFlags(*connPtr, *transPtr,
1363                            VTDeleteOnSalvage | VTOutOfService);
1364         if (tst) {
1365             goto fail_GetTrans;
1366         }
1367     }
1368
1369     /* Otherwise, the transaction did succeed, so get the creation date of the
1370      * latest RO volume on the replication site 
1371      */
1372     else {
1373         tst = AFSVolGetStatus(*connPtr, *transPtr, &tstatus);
1374         if (tst) {
1375             goto fail_GetTrans;
1376         }
1377         *timePtr = tstatus.creationDate - CLOCKSKEW;
1378     }
1379     rc = 1;
1380
1381   fail_GetTrans:
1382
1383     if ((rc == 0) && (*transPtr)) {
1384         etst = AFSVolEndTrans(*connPtr, *transPtr, &rcode);
1385         *transPtr = 0;
1386         if (!etst)
1387             etst = rcode;
1388     }
1389
1390     if (st != NULL) {
1391         *st = tst;
1392     }
1393     return rc;
1394 }
1395
1396 static int
1397 SimulateForwardMultiple(struct rx_connection *fromconn, afs_int32 fromtid,
1398                         afs_int32 fromdate, manyDests * tr, afs_int32 flags,
1399                         void *cookie, manyResults * results)
1400 {
1401     int i;
1402
1403     for (i = 0; i < tr->manyDests_len; i++) {
1404         results->manyResults_val[i] =
1405             AFSVolForward(fromconn, fromtid, fromdate,
1406                           &(tr->manyDests_val[i].server),
1407                           tr->manyDests_val[i].trans, cookie);
1408     }
1409     return 0;
1410 }
1411
1412
1413 /* VolumeExists()
1414  *      Determine if a volume exists on a server and partition.
1415  *      Try creating a transaction on the volume. If we can,
1416  *      the volume exists, if not, then return the error code.
1417  *      Some error codes mean the volume is unavailable but
1418  *      still exists - so we catch these error codes.
1419  */
1420 static afs_int32
1421 VolumeExists(afs_cell_handle_p cellHandle, afs_int32 server,
1422              afs_int32 partition, afs_int32 volumeid, afs_status_p st)
1423 {
1424     int rc = 0;
1425     afs_status_t tst = 0;
1426     struct rx_connection *conn = (struct rx_connection *)0;
1427     volEntries volumeInfo;
1428
1429     conn = UV_Bind(cellHandle, server, AFSCONF_VOLUMEPORT);
1430     if (conn) {
1431         volumeInfo.volEntries_val = (volintInfo *) 0;
1432         volumeInfo.volEntries_len = 0;
1433         tst = AFSVolListOneVolume(conn, partition, volumeid, &volumeInfo);
1434         if (volumeInfo.volEntries_val)
1435             free(volumeInfo.volEntries_val);
1436         if (tst == VOLSERILLEGAL_PARTITION) {
1437             tst = ENODEV;
1438         }
1439         rx_ReleaseCachedConnection(conn);
1440     }
1441     rc = 1;
1442
1443     if (st != NULL) {
1444         *st = tst;
1445     }
1446     return rc;
1447 }
1448
1449 /* release volume <afromvol> on <afromserver> <afrompart> to all the
1450  * sites if forceflag is 1.If its 0 complete the release if the previous
1451  * release aborted else start a new release */
1452 int
1453 UV_ReleaseVolume(afs_cell_handle_p cellHandle, afs_uint32 afromvol,
1454                  afs_int32 afromserver, afs_int32 afrompart, int forceflag,
1455                  afs_status_p st)
1456 {
1457     int rc = 0;
1458     afs_status_t tst = 0, etst = 0;
1459
1460     char vname[64];
1461     afs_int32 rcode;
1462     afs_uint32 cloneVolId, roVolId;
1463     struct replica *replicas = 0;
1464     struct nvldbentry entry;
1465     int i, volcount, m, fullrelease, vldbindex;
1466     int failure;
1467     struct restoreCookie cookie;
1468     struct rx_connection **toconns = 0;
1469     struct release *times = 0;
1470     int nservers = 0;
1471     struct rx_connection *fromconn = (struct rx_connection *)0;
1472     int islocked = 0;
1473     afs_int32 clonetid = 0, onlinetid;
1474     afs_int32 fromtid = 0;
1475     afs_uint32 fromdate = 0, thisdate;
1476     int s;
1477     manyDests tr;
1478     manyResults results;
1479     int rwindex, roindex, roclone, roexists;
1480     afs_int32 rwcrdate = 0;
1481     struct rtime {
1482         int validtime;
1483         afs_uint32 time;
1484     } remembertime[NMAXNSERVERS];
1485     int releasecount = 0;
1486     struct volser_status volstatus;
1487
1488     memset((char *)remembertime, 0, sizeof(remembertime));
1489     memset((char *)&results, 0, sizeof(results));
1490
1491     tst =
1492         ubik_VL_SetLock(cellHandle->vos, 0, afromvol, RWVOL,
1493                   VLOP_RELEASE);
1494     if ((tst) && (tst != VL_RERELEASE)) {
1495         goto fail_UV_ReleaseVolume;
1496     }
1497     islocked = 1;
1498
1499     /* Get the vldb entry in readable format */
1500     if (!aVLDB_GetEntryByID(cellHandle, afromvol, RWVOL, &entry, &tst)) {
1501         goto fail_UV_ReleaseVolume;
1502     }
1503
1504     if (!ISNAMEVALID(entry.name)) {
1505         tst = VOLSERBADNAME;
1506         goto fail_UV_ReleaseVolume;
1507     }
1508
1509     if (entry.volumeId[RWVOL] != afromvol) {
1510         tst = ADMVOSVOLUMERELEASERWONLY;
1511         goto fail_UV_ReleaseVolume;
1512     }
1513
1514     if (entry.nServers <= 1) {
1515         tst = ADMVOSVOLUMENOREPLICAS;
1516         goto fail_UV_ReleaseVolume;
1517     }
1518
1519     if (strlen(entry.name) > (VOLSER_OLDMAXVOLNAME - 10)) {
1520         tst = VOLSERBADNAME;
1521         goto fail_UV_ReleaseVolume;
1522     }
1523
1524     /* roclone is true if one of the RO volumes is on the same
1525      * partition as the RW volume. In this case, we make the RO volume
1526      * on the same partition a clone instead of a complete copy.
1527      */
1528
1529     roindex =
1530         Lp_ROMatch(cellHandle, &entry, afromserver, afrompart, &tst) - 1;
1531     roclone = ((roindex == -1) ? 0 : 1);
1532     rwindex = Lp_GetRwIndex(cellHandle, &entry, 0);
1533     if (rwindex < 0) {
1534         tst = VOLSERNOVOL;
1535         goto fail_UV_ReleaseVolume;
1536     }
1537
1538     /* Make sure we have a RO volume id to work with */
1539     if (entry.volumeId[ROVOL] == INVALID_BID) {
1540         /* need to get a new RO volume id */
1541         tst = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 1, &roVolId);
1542         if (tst) {
1543             goto fail_UV_ReleaseVolume;
1544         }
1545
1546         entry.volumeId[ROVOL] = roVolId;
1547         if (!VLDB_ReplaceEntry(cellHandle, afromvol, RWVOL, &entry, 0, &tst)) {
1548             goto fail_UV_ReleaseVolume;
1549         }
1550     }
1551
1552     /* Will we be completing a previously unfinished release. -force overrides */
1553     for (fullrelease = 1, i = 0; (fullrelease && (i < entry.nServers)); i++) {
1554         if (entry.serverFlags[i] & NEW_REPSITE)
1555             fullrelease = 0;
1556     }
1557     if (forceflag && !fullrelease)
1558         fullrelease = 1;
1559
1560     /* Determine which volume id to use and see if it exists */
1561     cloneVolId =
1562         ((fullrelease
1563           || (entry.cloneId == 0)) ? entry.volumeId[ROVOL] : entry.cloneId);
1564     VolumeExists(cellHandle, afromserver, afrompart, cloneVolId, &tst);
1565     roexists = ((tst == ENODEV) ? 0 : 1);
1566     if (!roexists && !fullrelease)
1567         fullrelease = 1;        /* Do a full release if RO clone does not exist */
1568
1569     fromconn = UV_Bind(cellHandle, afromserver, AFSCONF_VOLUMEPORT);
1570     if (!fromconn) {
1571         tst = -1;
1572         goto fail_UV_ReleaseVolume;
1573     }
1574
1575     if (fullrelease) {
1576         /* If the RO clone exists, then if the clone is a temporary
1577          * clone, delete it. Or if the RO clone is marked RO_DONTUSE
1578          * (it was recently added), then also delete it. We do not
1579          * want to "reclone" a temporary RO clone.
1580          */
1581         if (roexists
1582             && (!roclone || (entry.serverFlags[roindex] & RO_DONTUSE))) {
1583             tst = DelVol(fromconn, cloneVolId, afrompart, ITOffline);
1584             if (tst && (tst != VNOVOL)) {
1585                 goto fail_UV_ReleaseVolume;
1586             }
1587             roexists = 0;
1588         }
1589
1590         /* Mark all the ROs in the VLDB entry as RO_DONTUSE. We don't
1591          * write this entry out to the vlserver until after the first
1592          * RO volume is released (temp RO clones don't count).
1593          */
1594         for (i = 0; i < entry.nServers; i++) {
1595             entry.serverFlags[i] &= ~NEW_REPSITE;
1596             entry.serverFlags[i] |= RO_DONTUSE;
1597         }
1598         entry.serverFlags[rwindex] |= NEW_REPSITE;
1599         entry.serverFlags[rwindex] &= ~RO_DONTUSE;
1600
1601         /* Begin transaction on RW and mark it busy while we clone it */
1602         tst =
1603             AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy,
1604                               &clonetid);
1605         if (tst) {
1606             goto fail_UV_ReleaseVolume;
1607         }
1608
1609         /* Clone or reclone the volume */
1610         if (roexists) {
1611             tst = AFSVolReClone(fromconn, clonetid, cloneVolId);
1612             if (tst) {
1613                 goto fail_UV_ReleaseVolume;
1614             }
1615         } else {
1616             if (roclone) {
1617                 strcpy(vname, entry.name);
1618                 strcat(vname, ".readonly");
1619             } else {
1620                 strcpy(vname, "readonly-clone-temp");
1621             }
1622             tst =
1623                 AFSVolClone(fromconn, clonetid, 0, readonlyVolume, vname,
1624                             &cloneVolId);
1625             if (tst) {
1626                 goto fail_UV_ReleaseVolume;
1627             }
1628         }
1629
1630         /* Get the time the RW was created for future information */
1631         tst = AFSVolGetStatus(fromconn, clonetid, &volstatus);
1632         if (tst) {
1633             goto fail_UV_ReleaseVolume;
1634         }
1635         rwcrdate = volstatus.creationDate;
1636
1637         /* End the transaction on the RW volume */
1638         tst = AFSVolEndTrans(fromconn, clonetid, &rcode);
1639         clonetid = 0;
1640         tst = (tst ? tst : rcode);
1641         if (tst) {
1642             goto fail_UV_ReleaseVolume;
1643         }
1644
1645         /* Remember clone volume ID in case we fail or are interrupted */
1646         entry.cloneId = cloneVolId;
1647
1648         if (roclone) {
1649             /* Bring the RO clone online - though not if it's a temporary clone */
1650             tst =
1651                 AFSVolTransCreate(fromconn, cloneVolId, afrompart, ITOffline,
1652                                   &onlinetid);
1653             if (tst) {
1654                 goto fail_UV_ReleaseVolume;
1655             }
1656
1657             etst = AFSVolSetFlags(fromconn, onlinetid, 0);
1658
1659             tst = AFSVolEndTrans(fromconn, onlinetid, &rcode);
1660             tst = (tst ? tst : rcode);
1661             if (tst) {
1662                 goto fail_UV_ReleaseVolume;
1663             }
1664             if (etst) {
1665                 tst = etst;
1666                 goto fail_UV_ReleaseVolume;
1667             }
1668
1669             /* Sleep so that a client searching for an online volume won't
1670              * find the clone offline and then the next RO offline while the 
1671              * release brings the clone online and the next RO offline (race).
1672              * There is a fix in the 3.4 client that does not need this sleep
1673              * anymore, but we don't know what clients we have.
1674              */
1675             if (entry.nServers > 2)
1676                 sleep(5);
1677
1678             /* Mark the RO clone in the VLDB as a good site (already released) */
1679             entry.serverFlags[roindex] |= NEW_REPSITE;
1680             entry.serverFlags[roindex] &= ~RO_DONTUSE;
1681             entry.flags |= RO_EXISTS;
1682
1683             releasecount++;
1684
1685             /* Write out the VLDB entry only if the clone is not a temporary
1686              * clone. If we did this to a temporary clone then we would end
1687              * up marking all the ROs as "old release" making the ROs
1688              * temporarily unavailable.
1689              */
1690             if (!VLDB_ReplaceEntry
1691                 (cellHandle, afromvol, RWVOL, &entry, 0, &tst)) {
1692                 goto fail_UV_ReleaseVolume;
1693             }
1694         }
1695     }
1696
1697     /* Now we will release from the clone to the remaining RO replicas.
1698      * The first 2 ROs (counting the non-temporary RO clone) are released
1699      * individually: releasecount. This is to reduce the race condition
1700      * of clients trying to find an on-line RO volume. The remaining ROs
1701      * are released in parallel but no more than half the number of ROs
1702      * (rounded up) at a time: nservers.
1703      */
1704
1705     strcpy(vname, entry.name);
1706     strcat(vname, ".readonly");
1707     memset(&cookie, 0, sizeof(cookie));
1708     strncpy(cookie.name, vname, VOLSER_OLDMAXVOLNAME);
1709     cookie.type = ROVOL;
1710     cookie.parent = entry.volumeId[RWVOL];
1711     cookie.clone = 0;
1712
1713     nservers = entry.nServers / 2;      /* how many to do at once, excluding clone */
1714     replicas =
1715         (struct replica *)malloc(sizeof(struct replica) * nservers + 1);
1716     times = (struct release *)malloc(sizeof(struct release) * nservers + 1);
1717     toconns =
1718         (struct rx_connection **)malloc(sizeof(struct rx_connection *) *
1719                                         nservers + 1);
1720     results.manyResults_val =
1721         (afs_int32 *) malloc(sizeof(afs_int32) * nservers + 1);
1722     if (!replicas || !times || !!!results.manyResults_val || !toconns) {
1723         tst = ADMNOMEM;
1724         goto fail_UV_ReleaseVolume;
1725     }
1726
1727     memset(replicas, 0, (sizeof(struct replica) * nservers + 1));
1728     memset(times, 0, (sizeof(struct release) * nservers + 1));
1729     memset(toconns, 0, (sizeof(struct rx_connection *) * nservers + 1));
1730     memset(results.manyResults_val, 0, (sizeof(afs_int32) * nservers + 1));
1731
1732     /* Create a transaction on the cloned volume */
1733     tst =
1734         AFSVolTransCreate(fromconn, cloneVolId, afrompart, ITBusy, &fromtid);
1735     if (tst) {
1736         goto fail_UV_ReleaseVolume;
1737     }
1738
1739     /* For each index in the VLDB */
1740     for (vldbindex = 0; vldbindex < entry.nServers;) {
1741
1742         /* Get a transaction on the replicas. Pick replacas which have an old release. */
1743         for (volcount = 0;
1744              ((volcount < nservers) && (vldbindex < entry.nServers));
1745              vldbindex++) {
1746             /* The first two RO volumes will be released individually.
1747              * The rest are then released in parallel. This is a hack
1748              * for clients not recognizing right away when a RO volume
1749              * comes back on-line.
1750              */
1751             if ((volcount == 1) && (releasecount < 2))
1752                 break;
1753
1754             if (vldbindex == roindex)
1755                 continue;       /* the clone    */
1756             if ((entry.serverFlags[vldbindex] & NEW_REPSITE)
1757                 && !(entry.serverFlags[vldbindex] & RO_DONTUSE))
1758                 continue;
1759             if (!(entry.serverFlags[vldbindex] & ITSROVOL))
1760                 continue;       /* not a RO vol */
1761
1762
1763             /* Get a Transaction on this replica. Get a new connection if
1764              * necessary.  Create the volume if necessary.  Return the
1765              * time from which the dump should be made (0 if it's a new
1766              * volume).  Each volume might have a different time. 
1767              */
1768             replicas[volcount].server.destHost =
1769                 entry.serverNumber[vldbindex];
1770             replicas[volcount].server.destPort = AFSCONF_VOLUMEPORT;
1771             replicas[volcount].server.destSSID = 1;
1772             times[volcount].vldbEntryIndex = vldbindex;
1773
1774             if (!GetTrans
1775                 (cellHandle, &entry, vldbindex, &(toconns[volcount]),
1776                  &(replicas[volcount].trans), &(times[volcount].time),
1777                  &tst)) {
1778                 continue;
1779             }
1780
1781             /* Thisdate is the date from which we want to pick up all changes */
1782             if (forceflag || !fullrelease
1783                 || (rwcrdate > times[volcount].time)) {
1784                 /* If the forceflag is set, then we want to do a full dump.
1785                  * If it's not a full release, we can't be sure that the creation
1786                  *  date is good (so we also do a full dump).
1787                  * If the RW volume was replaced (its creation date is newer than
1788                  *  the last release), then we can't be sure what has changed (so
1789                  *  we do a full dump).
1790                  */
1791                 thisdate = 0;
1792             } else if (remembertime[vldbindex].validtime) {
1793                 /* Trans was prev ended. Use the time from the prev trans
1794                  * because, prev trans may have created the volume. In which
1795                  * case time[volcount].time would be now instead of 0.
1796                  */
1797                 thisdate =
1798                     (remembertime[vldbindex].time <
1799                      times[volcount].time) ? remembertime[vldbindex].
1800                     time : times[volcount].time;
1801             } else {
1802                 thisdate = times[volcount].time;
1803             }
1804             remembertime[vldbindex].validtime = 1;
1805             remembertime[vldbindex].time = thisdate;
1806
1807             if (volcount == 0) {
1808                 fromdate = thisdate;
1809             } else {
1810                 /* Include this volume if it is within 15 minutes of the earliest */
1811                 if (((fromdate >
1812                       thisdate) ? (fromdate - thisdate) : (thisdate -
1813                                                            fromdate)) > 900) {
1814                     AFSVolEndTrans(toconns[volcount],
1815                                    replicas[volcount].trans, &rcode);
1816                     replicas[volcount].trans = 0;
1817                     break;
1818                 }
1819                 if (thisdate < fromdate)
1820                     fromdate = thisdate;
1821             }
1822             volcount++;
1823         }
1824         if (!volcount)
1825             continue;
1826
1827         /* Release the ones we have collected */
1828         tr.manyDests_val = &(replicas[0]);
1829         tr.manyDests_len = results.manyResults_len = volcount;
1830         tst =
1831             AFSVolForwardMultiple(fromconn, fromtid, fromdate, &tr,
1832                                   0 /*spare */ , &cookie, &results);
1833         if (tst == RXGEN_OPCODE) {      /* RPC Interface Mismatch */
1834             tst =
1835                 SimulateForwardMultiple(fromconn, fromtid, fromdate, &tr,
1836                                         0 /*spare */ , &cookie, &results);
1837             nservers = 1;
1838         }
1839
1840         if (tst) {
1841             goto fail_UV_ReleaseVolume;
1842         } else {
1843             for (m = 0; m < volcount; m++) {
1844                 if (results.manyResults_val[m]) {
1845                     continue;
1846                 }
1847
1848                 tst =
1849                     AFSVolSetIdsTypes(toconns[m], replicas[m].trans, vname,
1850                                       ROVOL, entry.volumeId[RWVOL], 0, 0);
1851                 if (tst) {
1852                     continue;
1853                 }
1854
1855                 /* have to clear dest. flags to ensure new vol goes online:
1856                  * because the restore (forwarded) operation copied
1857                  * the V_inService(=0) flag over to the destination. 
1858                  */
1859                 tst = AFSVolSetFlags(toconns[m], replicas[m].trans, 0);
1860                 if (tst) {
1861                     continue;
1862                 }
1863
1864                 entry.serverFlags[times[m].vldbEntryIndex] |= NEW_REPSITE;
1865                 entry.serverFlags[times[m].vldbEntryIndex] &= ~RO_DONTUSE;
1866                 entry.flags |= RO_EXISTS;
1867                 releasecount++;
1868             }
1869         }
1870
1871         /* End the transactions and destroy the connections */
1872         for (s = 0; s < volcount; s++) {
1873             if (replicas[s].trans)
1874                 tst = AFSVolEndTrans(toconns[s], replicas[s].trans, &rcode);
1875             replicas[s].trans = 0;
1876             if (!tst)
1877                 tst = rcode;
1878             if (tst) {
1879                 if ((s == 0) || (tst != ENOENT)) {
1880                 } else {
1881                     if (times[s].vldbEntryIndex < vldbindex)
1882                         vldbindex = times[s].vldbEntryIndex;
1883                 }
1884             }
1885
1886             if (toconns[s])
1887                 rx_ReleaseCachedConnection(toconns[s]);
1888             toconns[s] = 0;
1889         }
1890
1891         if (!VLDB_ReplaceEntry(cellHandle, afromvol, RWVOL, &entry, 0, &tst)) {
1892             goto fail_UV_ReleaseVolume;
1893         }
1894     }                           /* for each index in the vldb */
1895
1896     /* End the transaction on the cloned volume */
1897     tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
1898     fromtid = 0;
1899
1900     /* Figure out if any volume were not released and say so */
1901     for (failure = 0, i = 0; i < entry.nServers; i++) {
1902         if (!(entry.serverFlags[i] & NEW_REPSITE))
1903             failure++;
1904     }
1905     if (failure) {
1906         if (!VLDB_ReplaceEntry
1907             (cellHandle, afromvol, RWVOL, &entry, LOCKREL_TIMESTAMP, &tst)) {
1908             goto fail_UV_ReleaseVolume;
1909         }
1910
1911         tst = VOLSERBADRELEASE;
1912         goto fail_UV_ReleaseVolume;
1913     }
1914
1915     /* All the ROs were release successfully. Remove the temporary clone */
1916     if (!roclone) {
1917         tst = DelVol(fromconn, cloneVolId, afrompart, ITOffline);
1918         if (tst) {
1919             goto fail_UV_ReleaseVolume;
1920         }
1921     }
1922     entry.cloneId = 0;
1923
1924     for (i = 0; i < entry.nServers; i++)
1925         entry.serverFlags[i] &= ~NEW_REPSITE;
1926
1927     /* Update the VLDB */
1928     if (!VLDB_ReplaceEntry
1929         (cellHandle, afromvol, RWVOL, &entry,
1930          LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP, &tst)) {
1931         goto fail_UV_ReleaseVolume;
1932     }
1933     rc = 1;
1934
1935   fail_UV_ReleaseVolume:
1936
1937     if (clonetid) {
1938         tst = AFSVolEndTrans(fromconn, clonetid, &rcode);
1939         clonetid = 0;
1940         if (tst) {
1941             rc = 0;
1942         }
1943     }
1944     if (fromtid) {
1945         tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
1946         fromtid = 0;
1947         if (tst) {
1948             rc = 0;
1949         }
1950     }
1951     for (i = 0; i < nservers; i++) {
1952         if (replicas && replicas[i].trans) {
1953             tst = AFSVolEndTrans(toconns[i], replicas[i].trans, &rcode);
1954             replicas[i].trans = 0;
1955             if (tst) {
1956                 rc = 0;
1957             }
1958         }
1959         if (toconns && toconns[i]) {
1960             rx_ReleaseCachedConnection(toconns[i]);
1961             toconns[i] = 0;
1962         }
1963     }
1964     if (islocked) {
1965         tst =
1966             ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, RWVOL,
1967                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
1968         if (tst) {
1969             rc = 0;
1970         }
1971     }
1972
1973     if (fromconn)
1974         rx_ReleaseCachedConnection(fromconn);
1975     if (results.manyResults_val)
1976         free(results.manyResults_val);
1977     if (replicas)
1978         free(replicas);
1979     if (toconns)
1980         free(toconns);
1981     if (times)
1982         free(times);
1983
1984     if (st != NULL) {
1985         *st = tst;
1986     }
1987     return rc;
1988 }
1989
1990 static int
1991 ReceiveFile(register int fd, register struct rx_call *call,
1992             register struct stat *status)
1993 {
1994     register char *buffer = (char *)0;
1995     register int blockSize;
1996     afs_int32 bytesread, nbytes, bytesleft, w;
1997     fd_set out;
1998     afs_int32 error = 0;
1999
2000 #ifdef AFS_NT40_ENV
2001     blockSize = 4096;
2002 #else
2003     if (fd != 1) {
2004 #ifdef  AFS_AIX_ENV
2005         struct statfs tstatfs;
2006
2007 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the sta
2008 t structure!! */
2009         fstatfs(fd, &tstatfs);
2010         blockSize = tstatfs.f_bsize;
2011 #else
2012         blockSize = status->st_blksize;
2013 #endif
2014     } else {
2015         blockSize = 4096;
2016     }
2017 #endif
2018     nbytes = blockSize;
2019     buffer = (char *)malloc(blockSize);
2020     if (!buffer) {
2021         return ADMNOMEM;
2022     }
2023     bytesread = 1;
2024     while (!error && (bytesread > 0)) {
2025         bytesread = rx_Read(call, buffer, nbytes);
2026         bytesleft = bytesread;
2027         while (!error && (bytesleft > 0)) {
2028             FD_ZERO(&out);
2029             FD_SET(fd, &out);
2030 #ifndef AFS_NT40_ENV            /* NT csn't select on non-socket fd's */
2031             select(fd + 1, 0, &out, 0, 0);      /* don't timeout if write bl
2032                                                  * ocks */
2033 #endif
2034             w = write(fd, &buffer[bytesread - bytesleft], bytesleft);
2035             if (w < 0) {
2036                 error = ADMVOSDUMPFILEWRITEFAIL;
2037             } else {
2038                 bytesleft -= w;
2039             }
2040         }
2041     }
2042     if (buffer)
2043         free(buffer);
2044     if (fd != 1)
2045         if (!error)
2046             fstat(fd, status);
2047     return error;
2048 }
2049
2050
2051 static afs_int32
2052 DumpFunction(struct rx_call *call, const char *filename)
2053 {
2054     int fd;
2055     struct stat status;
2056     afs_int32 error, code;
2057
2058     error = 0;
2059     fd = -1;
2060
2061     fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0666);
2062     if (fd < 0 || fstat(fd, &status) < 0) {
2063         error = VOLSERBADOP;
2064         goto dffail;
2065     }
2066     code = ReceiveFile(fd, call, &status);
2067     if (code) {
2068         error = code;
2069         goto dffail;
2070     }
2071   dffail:
2072     if (fd >= 0)
2073         code = close(fd);
2074     else
2075         code = 0;
2076     if (code) {
2077         if (!error)
2078             error = code;
2079     }
2080     return error;
2081 }
2082
2083
2084 /*dump the volume <afromvol> on <afromserver> and
2085 * <afrompart> to <afilename> starting from <fromdate>.
2086 * DumpFunction does the real work behind the scenes after
2087 * extracting parameters from the rock  */
2088 int
2089 UV_DumpVolume(afs_cell_handle_p cellHandle, afs_uint32 afromvol,
2090               afs_int32 afromserver, afs_int32 afrompart, afs_int32 fromdate,
2091               const char *filename, afs_status_p st)
2092 {
2093     int rc = 0;
2094     afs_status_t tst = 0;
2095     afs_status_t etst = 0;
2096     struct rx_connection *fromconn;
2097     struct rx_call *fromcall;
2098     afs_int32 fromtid;
2099     afs_int32 rxError;
2100     afs_int32 rcode;
2101
2102     struct nvldbentry entry;
2103     afs_int32 error;
2104     int islocked;
2105
2106     islocked = 0;
2107     error = 0;
2108     rxError = 0;
2109     fromcall = (struct rx_call *)0;
2110     fromconn = (struct rx_connection *)0;
2111     fromtid = 0;
2112     fromcall = (struct rx_call *)0;
2113
2114     islocked = 0;
2115     if (!aVLDB_GetEntryByID(cellHandle, afromvol, -1, &entry, &tst)) {
2116         goto fail_UV_DumpVolume;
2117     }
2118
2119     /* get connections to the servers */
2120     fromconn = UV_Bind(cellHandle, afromserver, AFSCONF_VOLUMEPORT);
2121     tst = AFSVolTransCreate(fromconn, afromvol, afrompart, ITBusy, &fromtid);
2122     if (tst) {
2123         goto fail_UV_DumpVolume;
2124     }
2125     fromcall = rx_NewCall(fromconn);
2126     tst = StartAFSVolDump(fromcall, fromtid, fromdate);
2127     if (tst) {
2128         goto fail_UV_DumpVolume;
2129     }
2130     if ((tst = DumpFunction(fromcall, filename))) {
2131         goto fail_UV_DumpVolume;
2132     }
2133     tst = rx_EndCall(fromcall, rxError);
2134     fromcall = (struct rx_call *)0;
2135     if (tst) {
2136         goto fail_UV_DumpVolume;
2137     }
2138     tst = AFSVolEndTrans(fromconn, fromtid, &rcode);
2139     fromtid = 0;
2140     if (!tst)
2141         tst = rcode;
2142     if (tst) {
2143         goto fail_UV_DumpVolume;
2144     }
2145     rc = 1;
2146
2147   fail_UV_DumpVolume:
2148
2149     if (islocked) {
2150         etst =
2151             ubik_VL_ReleaseLock(cellHandle->vos, 0, afromvol, -1,
2152                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2153         if (etst) {
2154             if (!tst)
2155                 tst = etst;
2156         }
2157     }
2158
2159     if (fromcall) {
2160         etst = rx_EndCall(fromcall, rxError);
2161         if (etst) {
2162             if (!tst)
2163                 tst = etst;
2164         }
2165     }
2166
2167     if (fromtid) {
2168         etst = AFSVolEndTrans(fromconn, fromtid, &rcode);
2169         if (!tst)
2170             tst = etst;
2171         if (rcode) {
2172             if (!tst)
2173                 tst = rcode;
2174         }
2175     }
2176
2177     if (fromconn) {
2178         rx_ReleaseCachedConnection(fromconn);
2179     }
2180
2181     if (st != NULL) {
2182         *st = tst;
2183     }
2184     return rc;
2185 }
2186
2187 int
2188 SendFile(register int fd, register struct rx_call *call,
2189          register struct stat *status)
2190 {
2191     char *buffer = (char *)0;
2192     int blockSize;
2193     fd_set in;
2194     afs_int32 error = 0;
2195     int done = 0;
2196     int nbytes;
2197
2198 #ifdef AFS_NT40_ENV
2199     blockSize = 4096;
2200 #else
2201     if (fd != 0) {
2202 #ifdef  AFS_AIX_ENV
2203         struct statfs tstatfs;
2204
2205 /* Unfortunately in AIX valuable fields such as st_blksize are gone from the sta
2206 t structure!! */
2207         fstatfs(fd, &tstatfs);
2208         blockSize = tstatfs.f_bsize;
2209 #else
2210         blockSize = status->st_blksize;
2211 #endif
2212     } else {
2213         blockSize = 4096;
2214     }
2215 #endif
2216     buffer = (char *)malloc(blockSize);
2217     if (!buffer) {
2218         return ADMNOMEM;
2219     }
2220
2221     while (!error && !done) {
2222         FD_ZERO(&in);
2223         FD_SET(fd, &in);
2224 #ifndef AFS_NT40_ENV            /* NT csn't select on non-socket fd's */
2225         select(fd + 1, &in, 0, 0, 0);   /* don't timeout if read blocks */
2226 #endif
2227         nbytes = read(fd, buffer, blockSize);
2228         if (nbytes < 0) {
2229             error = ADMVOSRESTOREFILEREADFAIL;
2230             break;
2231         }
2232         if (nbytes == 0) {
2233             done = 1;
2234             break;
2235         }
2236         if (rx_Write(call, buffer, nbytes) != nbytes) {
2237             error = ADMVOSRESTOREFILEWRITEFAIL;
2238             break;
2239         }
2240     }
2241     if (buffer)
2242         free(buffer);
2243     return error;
2244 }
2245
2246 static afs_int32
2247 WriteData(struct rx_call *call, const char *filename)
2248 {
2249     int fd;
2250     struct stat status;
2251     afs_int32 error, code;
2252
2253     error = 0;
2254     fd = -1;
2255
2256     fd = open(filename, 0);
2257     if (fd < 0 || fstat(fd, &status) < 0) {
2258         fprintf(STDERR, "Could access file '%s'\n", filename);
2259         error = ADMVOSRESTOREFILEOPENFAIL;
2260         goto fail_WriteData;
2261     }
2262     code = SendFile(fd, call, &status);
2263     if (code) {
2264         error = code;
2265         goto fail_WriteData;
2266     }
2267
2268   fail_WriteData:
2269
2270     if (fd >= 0)
2271         code = close(fd);
2272     else
2273         code = 0;
2274     if (code) {
2275         if (!error)
2276             error = ADMVOSRESTOREFILECLOSEFAIL;
2277     }
2278     return error;
2279 }
2280
2281 /*
2282  * Restore a volume <tovolid> <tovolname> on <toserver> <topart> from
2283  * the dump file <afilename>. WriteData does all the real work
2284  * after extracting params from the rock 
2285  */
2286 int
2287 UV_RestoreVolume(afs_cell_handle_p cellHandle, afs_int32 toserver,
2288                  afs_int32 topart, afs_uint32 tovolid, const char *tovolname,
2289                  int flags, const char *dumpFile, afs_status_p st)
2290 {
2291     int rc = 0;
2292     afs_status_t tst = 0;
2293     afs_status_t etst = 0;
2294     struct rx_connection *toconn, *tempconn;
2295     struct rx_call *tocall;
2296     afs_int32 totid, rcode;
2297     afs_int32 rxError = 0;
2298     struct volser_status tstatus;
2299     char partName[10];
2300     afs_uint32 pvolid;
2301     afs_int32 temptid;
2302     int success;
2303     struct nvldbentry entry;
2304     afs_int32 error;
2305     int islocked;
2306     struct restoreCookie cookie;
2307     int reuseID;
2308     afs_int32 newDate, volflag;
2309     int index, same;
2310
2311
2312     memset(&cookie, 0, sizeof(cookie));
2313     islocked = 0;
2314     success = 0;
2315     error = 0;
2316     reuseID = 1;
2317     tocall = (struct rx_call *)0;
2318     toconn = (struct rx_connection *)0;
2319     tempconn = (struct rx_connection *)0;
2320     totid = 0;
2321     temptid = 0;
2322
2323     pvolid = tovolid;
2324     toconn = UV_Bind(cellHandle, toserver, AFSCONF_VOLUMEPORT);
2325     if (pvolid == 0) {          /*alot a new id if needed */
2326         aVLDB_GetEntryByName(cellHandle, tovolname, &entry, &tst);
2327         if (tst == VL_NOENT) {
2328             tst =
2329                 ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 1, &pvolid);
2330             if (tst) {
2331                 goto fail_UV_RestoreVolume;
2332             }
2333             reuseID = 0;
2334         } else {
2335             pvolid = entry.volumeId[RWVOL];
2336         }
2337     }
2338
2339     /* 
2340      * at this point we have a volume id to use/reuse for the
2341      * volume to be restored
2342      */
2343     if (strlen(tovolname) > (VOLSER_OLDMAXVOLNAME - 1)) {
2344         tst = ADMVOSRESTOREVOLUMENAMETOOBIG;
2345         goto fail_UV_RestoreVolume;
2346     }
2347
2348     if (!vos_PartitionIdToName(topart, partName, &tst)) {
2349         goto fail_UV_RestoreVolume;
2350     }
2351     /*what should the volume be restored as ? rw or ro or bk ?
2352      * right now the default is rw always */
2353     tst =
2354         AFSVolCreateVolume(toconn, topart, tovolname, volser_RW, 0, &pvolid,
2355                            &totid);
2356     if (tst) {
2357         if (flags & RV_FULLRST) {       /* full restore: delete then create anew */
2358             tst =
2359                 AFSVolTransCreate(toconn, pvolid, topart, ITOffline, &totid);
2360             if (tst) {
2361                 goto fail_UV_RestoreVolume;
2362             }
2363             tst =
2364                 AFSVolSetFlags(toconn, totid,
2365                                VTDeleteOnSalvage | VTOutOfService);
2366             if (tst) {
2367                 goto fail_UV_RestoreVolume;
2368             }
2369             tst = AFSVolDeleteVolume(toconn, totid);
2370             if (tst) {
2371                 goto fail_UV_RestoreVolume;
2372             }
2373             tst = AFSVolEndTrans(toconn, totid, &rcode);
2374             totid = 0;
2375             if (!tst)
2376                 tst = rcode;
2377             if (tst) {
2378                 goto fail_UV_RestoreVolume;
2379             }
2380             tst =
2381                 AFSVolCreateVolume(toconn, topart, tovolname, volser_RW, 0,
2382                                    &pvolid, &totid);
2383             if (tst) {
2384                 goto fail_UV_RestoreVolume;
2385             }
2386         } else {
2387             tst =
2388                 AFSVolTransCreate(toconn, pvolid, topart, ITOffline, &totid);
2389             if (tst) {
2390                 goto fail_UV_RestoreVolume;
2391             }
2392         }
2393     }
2394     cookie.parent = pvolid;
2395     cookie.type = RWVOL;
2396     cookie.clone = 0;
2397     strncpy(cookie.name, tovolname, VOLSER_OLDMAXVOLNAME);
2398
2399     tocall = rx_NewCall(toconn);
2400     tst = StartAFSVolRestore(tocall, totid, 1, &cookie);
2401     if (tst) {
2402         goto fail_UV_RestoreVolume;
2403     }
2404     tst = WriteData(tocall, dumpFile);
2405     if (tst) {
2406         goto fail_UV_RestoreVolume;
2407     }
2408     tst = rx_EndCall(tocall, rxError);
2409     tocall = (struct rx_call *)0;
2410     if (tst) {
2411         goto fail_UV_RestoreVolume;
2412     }
2413     tst = AFSVolGetStatus(toconn, totid, &tstatus);
2414     if (tst) {
2415         goto fail_UV_RestoreVolume;
2416     }
2417     tst = AFSVolSetIdsTypes(toconn, totid, tovolname, RWVOL, pvolid, 0, 0);
2418     if (tst) {
2419         goto fail_UV_RestoreVolume;
2420     }
2421     newDate = time(0);
2422     tst = AFSVolSetDate(toconn, totid, newDate);
2423     if (tst) {
2424         goto fail_UV_RestoreVolume;
2425     }
2426
2427     volflag = ((flags & RV_OFFLINE) ? VTOutOfService : 0);      /* off or on-line */
2428     tst = AFSVolSetFlags(toconn, totid, volflag);
2429     if (tst) {
2430         goto fail_UV_RestoreVolume;
2431     }
2432
2433 /* It isn't handled right in fail_UV_RestoreVolume */
2434     tst = AFSVolEndTrans(toconn, totid, &rcode);
2435     totid = 0;
2436     if (!tst)
2437         tst = rcode;
2438     if (tst) {
2439         goto fail_UV_RestoreVolume;
2440     }
2441
2442     success = 1;
2443     if (success && (!reuseID || (flags & RV_FULLRST))) {
2444         /* Volume was restored on the file server, update the 
2445          * VLDB to reflect the change.
2446          */
2447         aVLDB_GetEntryByID(cellHandle, pvolid, RWVOL, &entry, &tst);
2448         if (tst && tst != VL_NOENT && tst != VL_ENTDELETED) {
2449             goto fail_UV_RestoreVolume;
2450         }
2451         if (tst == VL_NOENT) {  /* it doesnot exist already */
2452             /*make the vldb return this indication specifically */
2453             strcpy(entry.name, tovolname);
2454             entry.nServers = 1;
2455             entry.serverNumber[0] = toserver;   /*should be indirect */
2456             entry.serverPartition[0] = topart;
2457             entry.serverFlags[0] = ITSRWVOL;
2458             entry.flags = RW_EXISTS;
2459             if (tstatus.cloneID != 0) {
2460                 entry.volumeId[ROVOL] = tstatus.cloneID;        /*this should come from status info on the volume if non zero */
2461             } else
2462                 entry.volumeId[ROVOL] = INVALID_BID;
2463             entry.volumeId[RWVOL] = pvolid;
2464             entry.cloneId = 0;
2465             if (tstatus.backupID != 0) {
2466                 entry.volumeId[BACKVOL] = tstatus.backupID;
2467                 /*this should come from status info on the volume if non zero */
2468             } else
2469                 entry.volumeId[BACKVOL] = INVALID_BID;
2470             if (!VLDB_CreateEntry(cellHandle, &entry, &tst)) {
2471                 goto fail_UV_RestoreVolume;
2472             }
2473             islocked = 0;
2474         } else {                /*update the existing entry */
2475             tst =
2476                 ubik_VL_SetLock(cellHandle->vos, 0, pvolid, RWVOL,
2477                           VLOP_RESTORE);
2478             if (tst) {
2479                 goto fail_UV_RestoreVolume;
2480             }
2481             islocked = 1;
2482             strcpy(entry.name, tovolname);
2483
2484             /* Update the vlentry with the new information */
2485             index = Lp_GetRwIndex(cellHandle, &entry, 0);
2486             if (index == -1) {
2487                 /* Add the rw site for the volume being restored */
2488                 entry.serverNumber[entry.nServers] = toserver;
2489                 entry.serverPartition[entry.nServers] = topart;
2490                 entry.serverFlags[entry.nServers] = ITSRWVOL;
2491                 entry.nServers++;
2492             } else {
2493                 /* This volume should be deleted on the old site
2494                  * if its different from new site.
2495                  */
2496                 VLDB_IsSameAddrs(cellHandle, toserver,
2497                                  entry.serverNumber[index], &same, &tst);
2498                 if ((!tst && !same)
2499                     || (entry.serverPartition[index] != topart)) {
2500                     tempconn =
2501                         UV_Bind(cellHandle, entry.serverNumber[index],
2502                                 AFSCONF_VOLUMEPORT);
2503                     tst =
2504                         AFSVolTransCreate(tempconn, pvolid,
2505                                           entry.serverPartition[index],
2506                                           ITOffline, &temptid);
2507                     if (!tst) {
2508                         tst =
2509                             AFSVolSetFlags(tempconn, temptid,
2510                                            VTDeleteOnSalvage |
2511                                            VTOutOfService);
2512                         if (tst) {
2513                             goto fail_UV_RestoreVolume;
2514                         }
2515                         tst = AFSVolDeleteVolume(tempconn, temptid);
2516                         if (tst) {
2517                             goto fail_UV_RestoreVolume;
2518                         }
2519                         tst = AFSVolEndTrans(tempconn, temptid, &rcode);
2520                         temptid = 0;
2521                         if (!tst)
2522                             tst = rcode;
2523                         if (tst) {
2524                             goto fail_UV_RestoreVolume;
2525                         }
2526                         vos_PartitionIdToName(entry.serverPartition[index],
2527                                               partName, &tst);
2528                     }
2529                 }
2530                 entry.serverNumber[index] = toserver;
2531                 entry.serverPartition[index] = topart;
2532             }
2533
2534             entry.flags |= RW_EXISTS;
2535             if (!VLDB_ReplaceEntry
2536                 (cellHandle, pvolid, RWVOL, &entry,
2537                  LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP, &tst)) {
2538                 goto fail_UV_RestoreVolume;
2539             }
2540             islocked = 0;
2541         }
2542     }
2543     rc = 1;
2544
2545   fail_UV_RestoreVolume:
2546
2547     if (tocall) {
2548         etst = rx_EndCall(tocall, rxError);
2549         if (!tst)
2550             tst = etst;
2551     }
2552     if (islocked) {
2553         etst =
2554             ubik_VL_ReleaseLock(cellHandle->vos, 0, pvolid, RWVOL,
2555                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2556         if (etst) {
2557             if (!tst)
2558                 tst = etst;
2559         }
2560     }
2561     if (totid) {
2562         etst = AFSVolEndTrans(toconn, totid, &rcode);
2563         if (!etst)
2564             etst = rcode;
2565         if (etst) {
2566             if (!tst)
2567                 tst = etst;
2568         }
2569     }
2570     if (temptid) {
2571         etst = AFSVolEndTrans(toconn, temptid, &rcode);
2572         if (!etst)
2573             etst = rcode;
2574         if (etst) {
2575             if (!tst)
2576                 tst = etst;
2577         }
2578     }
2579
2580     if (tempconn)
2581         rx_ReleaseCachedConnection(tempconn);
2582     if (toconn)
2583         rx_ReleaseCachedConnection(toconn);
2584
2585     if (st != NULL) {
2586         *st = tst;
2587     }
2588     return rc;
2589 }
2590
2591 /*adds <server> and <part> as a readonly replication site for <volid>
2592 *in vldb */
2593 int
2594 UV_AddSite(afs_cell_handle_p cellHandle, afs_int32 server, afs_int32 part,
2595            afs_uint32 volid, afs_status_p st)
2596 {
2597     int rc = 0;
2598     afs_status_t tst = 0;
2599     int j, nro = 0, islocked = 0;
2600     struct nvldbentry entry;
2601     int same = 0;
2602
2603     tst =
2604         ubik_VL_SetLock(cellHandle->vos, 0, volid, RWVOL, VLOP_ADDSITE);
2605     if (tst) {
2606         goto fail_UV_AddSite;
2607     }
2608     islocked = 1;
2609
2610     if (!aVLDB_GetEntryByID(cellHandle, volid, RWVOL, &entry, &tst)) {
2611         goto fail_UV_AddSite;
2612     }
2613     if (!ISNAMEVALID(entry.name)) {
2614         tst = VOLSERBADOP;
2615         goto fail_UV_AddSite;
2616     }
2617
2618     /* See if it's too many entries */
2619     if (entry.nServers >= NMAXNSERVERS) {
2620         tst = VOLSERBADOP;
2621         goto fail_UV_AddSite;
2622     }
2623
2624     /* See if it's on the same server */
2625     for (j = 0; j < entry.nServers; j++) {
2626         if (entry.serverFlags[j] & ITSROVOL) {
2627             nro++;
2628             if (!VLDB_IsSameAddrs
2629                 (cellHandle, server, entry.serverNumber[j], &same, &tst)) {
2630                 goto fail_UV_AddSite;
2631             }
2632             if (same) {
2633                 tst = VOLSERBADOP;
2634                 goto fail_UV_AddSite;
2635             }
2636         }
2637     }
2638
2639     /* See if it's too many RO sites - leave one for the RW */
2640     if (nro >= NMAXNSERVERS - 1) {
2641         tst = VOLSERBADOP;
2642         goto fail_UV_AddSite;
2643     }
2644
2645     entry.serverNumber[entry.nServers] = server;
2646     entry.serverPartition[entry.nServers] = part;
2647     entry.serverFlags[entry.nServers] = (ITSROVOL | RO_DONTUSE);
2648     entry.nServers++;
2649
2650     if (!VLDB_ReplaceEntry
2651         (cellHandle, volid, RWVOL, &entry,
2652          LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP, &tst)) {
2653         goto fail_UV_AddSite;
2654     }
2655     islocked = 0;
2656     rc = 1;
2657
2658   fail_UV_AddSite:
2659
2660     if (islocked) {
2661         tst =
2662             ubik_VL_ReleaseLock(cellHandle->vos, 0, volid, RWVOL,
2663                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2664     }
2665
2666     if (st != NULL) {
2667         *st = tst;
2668     }
2669     return rc;
2670 }
2671
2672 /*removes <server> <part> as read only site for <volid> from the vldb */
2673 int
2674 UV_RemoveSite(afs_cell_handle_p cellHandle, afs_int32 server, afs_int32 part,
2675               afs_uint32 volid, afs_status_p st)
2676 {
2677     int rc = 0;
2678     afs_status_t tst = 0;
2679     struct nvldbentry entry;
2680     int islocked = 0;
2681
2682     tst =
2683         ubik_VL_SetLock(cellHandle->vos, 0, volid, RWVOL, VLOP_ADDSITE);
2684     if (tst) {
2685         goto fail_UV_RemoveSite;
2686     }
2687     islocked = 1;
2688
2689     if (!aVLDB_GetEntryByID(cellHandle, volid, RWVOL, &entry, &tst)) {
2690         goto fail_UV_RemoveSite;
2691     }
2692     if (!Lp_ROMatch(cellHandle, &entry, server, part, &tst)) {
2693         /*this site doesnot exist  */
2694         goto fail_UV_RemoveSite;
2695     } else {                    /*remove the rep site */
2696         Lp_SetROValue(cellHandle, &entry, server, part, 0, 0);
2697         entry.nServers--;
2698         if ((entry.nServers == 1) && (entry.flags & RW_EXISTS))
2699             entry.flags &= ~RO_EXISTS;
2700         if (entry.nServers < 1) {       /*this is the last ref */
2701             tst = ubik_VL_DeleteEntry(cellHandle->vos, 0, volid, ROVOL);
2702             if (tst) {
2703                 goto fail_UV_RemoveSite;
2704             }
2705         }
2706         if (!VLDB_ReplaceEntry
2707             (cellHandle, volid, RWVOL, &entry,
2708              (LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP), &tst)) {
2709             goto fail_UV_RemoveSite;
2710         }
2711     }
2712     rc = 1;
2713
2714   fail_UV_RemoveSite:
2715
2716     if (islocked) {
2717         afs_status_t t;
2718         t = ubik_VL_ReleaseLock(cellHandle->vos, 0, volid, RWVOL,
2719                       LOCKREL_OPCODE | LOCKREL_AFSID | LOCKREL_TIMESTAMP);
2720         if (tst == 0) {
2721             tst = t;
2722         }
2723     }
2724
2725     if (st != NULL) {
2726         *st = tst;
2727     }
2728     return rc;
2729 }
2730
2731 /*list all the partitions on <aserver> */
2732 int
2733 UV_ListPartitions(struct rx_connection *server, struct partList *ptrPartList,
2734                   afs_int32 * cntp, afs_status_p st)
2735 {
2736     int rc = 0;
2737     afs_status_t tst = 0;
2738     struct pIDs partIds;
2739     struct partEntries partEnts;
2740     register int i, j = 0;
2741
2742     *cntp = 0;
2743
2744     partEnts.partEntries_len = 0;
2745     partEnts.partEntries_val = NULL;
2746     /* this is available only on new servers */
2747     tst = AFSVolXListPartitions(server, &partEnts);
2748
2749     /* next, try old interface */
2750     if (tst == RXGEN_OPCODE) {
2751         for (i = 0; i < 26; i++)
2752             partIds.partIds[i] = -1;
2753         tst = AFSVolListPartitions(server, &partIds);
2754         if (!tst) {
2755             for (i = 0; i < 26; i++) {
2756                 if ((partIds.partIds[i]) != -1) {
2757                     ptrPartList->partId[j] = partIds.partIds[i];
2758                     ptrPartList->partFlags[j] = PARTVALID;
2759                     j++;
2760                 } else
2761                     ptrPartList->partFlags[i] = 0;
2762             }
2763             *cntp = j;
2764         } else {
2765             goto fail_UV_ListPartitions;
2766         }
2767     } else if (!tst) {
2768         *cntp = partEnts.partEntries_len;
2769         if (*cntp > VOLMAXPARTS) {
2770             *cntp = VOLMAXPARTS;
2771         }
2772         for (i = 0; i < *cntp; i++) {
2773             ptrPartList->partId[i] = partEnts.partEntries_val[i];
2774             ptrPartList->partFlags[i] = PARTVALID;
2775         }
2776         free(partEnts.partEntries_val);
2777     } else {
2778         goto fail_UV_ListPartitions;
2779     }
2780     rc = 1;
2781
2782   fail_UV_ListPartitions:
2783
2784     if (st != NULL) {
2785         *st = tst;
2786     }
2787     return rc;
2788 }
2789
2790 /*------------------------------------------------------------------------
2791  * EXPORTED UV_XListVolumes
2792  *
2793  * Description:
2794  *      List the extended information for all the volumes on a particular
2795  *      File Server and partition.  We may either return the volume's ID
2796  *      or all of its extended information.
2797  *
2798  * Arguments:
2799  *      a_serverID         : Address of the File Server for which we want
2800  *                              extended volume info.
2801  *      a_partID           : Partition for which we want the extended
2802  *                              volume info.
2803  *      a_all              : If non-zero, fetch ALL the volume info,
2804  *                              otherwise just the volume ID.
2805  *      a_resultPP         : Ptr to the address of the area containing
2806  *                              the returned volume info.
2807  *      a_numEntsInResultP : Ptr for the value we set for the number of
2808  *                              entries returned.
2809  *
2810  * Returns:
2811  *      0 on success,
2812  *      Otherise, the return value of AFSVolXListVolumes.
2813  *
2814  * Environment:
2815  *      This routine is closely related to UV_ListVolumes, which returns
2816  *      only the standard level of detail on AFS volumes. It is a
2817  *      heavyweight operation, zipping through all the volume entries for
2818  *      a given server/partition.
2819  *
2820  * Side Effects:
2821  *      As advertised.
2822  *------------------------------------------------------------------------*/
2823
2824 int
2825 UV_XListVolumes(struct rx_connection *server, afs_int32 a_partID, int a_all,
2826                 struct volintXInfo **a_resultPP,
2827                 afs_int32 * a_numEntsInResultP, afs_status_p st)
2828 {
2829     int rc = 0;
2830     afs_status_t tst = 0;
2831
2832     volXEntries volumeXInfo;    /*Area for returned extended vol info */
2833
2834     /*
2835      * Set up our error code and the area for returned extended volume info.
2836      * We set the val field to a null pointer as a hint for the stub to
2837      * allocate space.
2838      */
2839     *a_numEntsInResultP = 0;
2840     *a_resultPP = (volintXInfo *) 0;
2841     volumeXInfo.volXEntries_val = (volintXInfo *) 0;
2842     volumeXInfo.volXEntries_len = 0;
2843
2844     /*
2845      * Bind to the Volume Server port on the File Server machine in question,
2846      * then go for it.
2847      */
2848     tst = AFSVolXListVolumes(server, a_partID, a_all, &volumeXInfo);
2849     if (tst) {
2850         goto fail_UV_XListVolumes;
2851     } else {
2852         /*
2853          * We got the info; pull out the pointer to where the results lie
2854          * and how many entries are there.
2855          */
2856         *a_resultPP = volumeXInfo.volXEntries_val;
2857         *a_numEntsInResultP = volumeXInfo.volXEntries_len;
2858     }
2859     rc = 1;
2860
2861   fail_UV_XListVolumes:
2862
2863     if (st != NULL) {
2864         *st = tst;
2865     }
2866     return rc;
2867 }
2868
2869 /*------------------------------------------------------------------------
2870  * EXPORTED UV_XListOneVolume
2871  *
2872  * Description:
2873  *      List the extended information for a volume on a particular File
2874  *      Server and partition.
2875  *
2876  * Arguments:
2877  *      server     : a handle to the server where the volume resides.
2878  *      a_partID           : Partition for which we want the extended
2879  *                              volume info.
2880  *      a_volID            : Volume ID for which we want the info.
2881  *      a_resultPP         : Ptr to the address of the area containing
2882  *                              the returned volume info.
2883  *
2884  * Returns:
2885  *      0 on success,
2886  *      Otherise, the return value of AFSVolXListOneVolume.
2887  *
2888  * Environment:
2889  *      This routine is closely related to UV_ListOneVolume, which returns
2890  *      only the standard level of detail on the chosen AFS volume.
2891  *
2892  * Side Effects:
2893  *      As advertised.
2894  *------------------------------------------------------------------------*/
2895
2896 int
2897 UV_XListOneVolume(struct rx_connection *server, afs_int32 a_partID,
2898                   afs_uint32 a_volID, struct volintXInfo **a_resultPP,
2899                   afs_status_p st)
2900 {
2901     int rc = 0;
2902     afs_status_t tst = 0;
2903     volXEntries volumeXInfo;    /*Area for returned info */
2904
2905     /*
2906      * Set the area we're in which we are returning
2907      * the info.  Setting the val field to a null pointer tells the stub
2908      * to allocate space for us.
2909      */
2910     *a_resultPP = (volintXInfo *) 0;
2911     volumeXInfo.volXEntries_val = (volintXInfo *) 0;
2912     volumeXInfo.volXEntries_len = 0;
2913
2914     tst = AFSVolXListOneVolume(server, a_partID, a_volID, &volumeXInfo);
2915
2916     if (tst) {
2917         goto fail_UV_XListOneVolume;
2918     } else {
2919         /*
2920          * We got the info; pull out the pointer to where the results lie.
2921          */
2922         *a_resultPP = volumeXInfo.volXEntries_val;
2923     }
2924     rc = 1;
2925
2926   fail_UV_XListOneVolume:
2927
2928     if (st != NULL) {
2929         *st = tst;
2930     }
2931     return rc;
2932
2933 }                               /*UV_XListOneVolume */
2934
2935 /*------------------------------------------------------------------------
2936  * EXPORTED UV_ListOneVolume
2937  *
2938  * Description:
2939  *      List the volume information for a volume on a particular File
2940  *      Server and partition.
2941  *
2942  * Arguments:
2943  *      server     : a handle to the server where the volume resides.
2944  *      a_partID           : Partition for which we want the extended
2945  *                              volume info.
2946  *      a_volID            : Volume ID for which we want the info.
2947  *      a_resultPP         : Ptr to the address of the area containing
2948  *                              the returned volume info.
2949  *
2950  * Returns:
2951  *      0 on success,
2952  *      Otherise, the return value of AFSVolXListOneVolume.
2953  *
2954  * Side Effects:
2955  *      As advertised.
2956  *------------------------------------------------------------------------*/
2957
2958 int UV_ListOneVolume(struct rx_connection *server, afs_int32 a_partID,
2959                   afs_uint32 a_volID, struct volintInfo **a_resultPP,
2960                   afs_status_p st)
2961 {
2962     int rc = 0;
2963     afs_status_t tst = 0;
2964     volEntries volumeInfo;      /*Area for returned info */
2965
2966     /*
2967      * Set the area we're in which we are returning
2968      * the info.  Setting the val field to a null pointer tells the stub
2969      * to allocate space for us.
2970      */
2971     *a_resultPP = (volintInfo *) 0;
2972     volumeInfo.volEntries_val = (volintInfo *) 0;
2973     volumeInfo.volEntries_len = 0;
2974
2975     tst = AFSVolListOneVolume(server, a_partID, a_volID, &volumeInfo);
2976
2977     if (tst) {
2978         goto fail_UV_ListOneVolume;
2979     } else {
2980         /*
2981          * We got the info; pull out the pointer to where the results lie.
2982          */
2983         *a_resultPP = volumeInfo.volEntries_val;
2984     }
2985     rc = 1;
2986
2987   fail_UV_ListOneVolume:
2988
2989     if (st != NULL) {
2990         *st = tst;
2991     }
2992     return rc;
2993 }/*UV_ListOneVolume*/
2994
2995 /*sync vldb with all the entries on <myQueue> on <aserver> and <apart>*/
2996 static afs_int32
2997 ProcessEntries(afs_cell_handle_p cellHandle, struct qHead *myQueue,
2998                struct rx_connection *server, afs_int32 apart, afs_int32 force)
2999 {
3000     struct aqueue elem;
3001     int success, temp;
3002     afs_uint32 temp1, temp2;
3003     afs_int32 vcode;
3004     afs_uint32 maxVolid = 0;
3005     struct nvldbentry entry;
3006     int noError = 1, error, same;
3007     int totalC, totalU, totalCE, totalUE, totalG;
3008     int counter;
3009     int aserver = ntohl(rx_HostOf(rx_PeerOf(server)));
3010     afs_status_t tst;
3011
3012     totalC = totalU = totalCE = totalUE = totalG = 0;
3013     counter = 0;
3014
3015     /* get the next  available id's from the vldb server */
3016     vcode = ubik_VL_GetNewVolumeId(cellHandle->vos, 0, 0, &maxVolid);
3017     if (vcode) {
3018         return (vcode);
3019     }
3020     totalG = myQueue->count;
3021     if (totalG == 0)
3022         return 0;
3023     while (1) {
3024         Lp_QEnumerate(myQueue, &success, &elem, 0);
3025         if (!success)
3026             break;
3027         counter++;
3028
3029         if (!elem.isValid[RWVOL] && !elem.isValid[ROVOL] && !elem.isValid[BACKVOL]) {   /*something is wrong with elem */
3030             noError = 0;
3031             continue;
3032         }
3033         if (maxVolid <= elem.ids[RWVOL]) {
3034             temp1 = maxVolid;
3035             temp2 = elem.ids[RWVOL] - maxVolid + 1;
3036             maxVolid = 0;
3037             vcode =
3038                 ubik_VL_GetNewVolumeId(cellHandle->vos, 0, temp2,
3039                           &maxVolid);
3040             maxVolid += temp2;
3041         }
3042         if (maxVolid <= elem.ids[ROVOL]) {
3043             temp1 = maxVolid;
3044             temp2 = elem.ids[ROVOL] - maxVolid + 1;
3045             maxVolid = 0;
3046             vcode =
3047                 ubik_VL_GetNewVolumeId(cellHandle->vos, 0, temp2,
3048                           &maxVolid);
3049             maxVolid += temp2;
3050         }
3051         if (maxVolid <= elem.ids[BACKVOL]) {
3052             temp1 = maxVolid;
3053             temp2 = elem.ids[BACKVOL] - temp1 + 1;
3054             maxVolid = 0;
3055             vcode =
3056                 ubik_VL_GetNewVolumeId(cellHandle->vos, 0, temp2,
3057                           &maxVolid);
3058             maxVolid += temp2;
3059         }
3060         aVLDB_GetEntryByID(cellHandle, elem.ids[RWVOL], RWVOL, &entry, &tst);
3061         if (tst && (tst != VL_NOENT)) {
3062             noError = 0;
3063             totalCE++;
3064         } else if (tst && (tst == VL_NOENT)) {  /*entry doesnot exist */
3065             /*set up a vldb entry for elem */
3066             memset(&entry, 0, sizeof(entry));
3067             strncpy(entry.name, elem.name, VOLSER_OLDMAXVOLNAME);
3068             if (elem.isValid[RWVOL]) {  /*rw exists */
3069                 entry.flags |= RW_EXISTS;
3070                 entry.serverFlags[entry.nServers] = ITSRWVOL;
3071                 entry.serverNumber[entry.nServers] = aserver;
3072                 entry.serverPartition[entry.nServers] = apart;
3073                 entry.nServers += 1;
3074                 entry.volumeId[RWVOL] = elem.ids[RWVOL];
3075                 entry.volumeId[ROVOL] = elem.ids[ROVOL];
3076                 entry.volumeId[BACKVOL] = elem.ids[BACKVOL];
3077             }
3078             if (elem.isValid[ROVOL]) {  /*ro volume exists */
3079                 entry.flags |= RO_EXISTS;
3080                 entry.serverFlags[entry.nServers] = ITSROVOL;
3081                 entry.serverNumber[entry.nServers] = aserver;
3082                 entry.serverPartition[entry.nServers] = apart;
3083                 entry.nServers += 1;
3084                 entry.volumeId[RWVOL] = elem.ids[RWVOL];
3085                 entry.volumeId[ROVOL] = elem.ids[ROVOL];
3086
3087             }
3088             if (elem.isValid[BACKVOL]) {        /*backup volume exists */
3089                 entry.flags |= BACK_EXISTS;
3090                 if (!(entry.flags & RW_EXISTS)) {       /*this helps to check for a stray backup if parent moves */
3091                     entry.serverFlags[entry.nServers] = ITSRWVOL;
3092                     entry.serverNumber[entry.nServers] = aserver;
3093                     entry.serverPartition[entry.nServers] = apart;
3094                     entry.nServers += 1;
3095                 }
3096
3097                 entry.volumeId[RWVOL] = elem.ids[RWVOL];
3098                 entry.volumeId[BACKVOL] = elem.ids[BACKVOL];
3099
3100             }
3101             VLDB_CreateEntry(cellHandle, &entry, &tst);
3102             if (tst) {
3103                 noError = 0;
3104                 totalCE++;
3105             } else
3106                 totalC++;
3107         } else {                /* Update the existing entry */
3108             strncpy(entry.name, elem.name, VOLSER_OLDMAXVOLNAME);       /*the name Could have changed */
3109
3110             if (elem.isValid[RWVOL]) {  /* A RW volume */
3111                 temp = Lp_GetRwIndex(cellHandle, &entry, 0);
3112                 if (temp == -1) {
3113                     /* A RW index is not found in the VLDB entry - will add it */
3114
3115                     entry.flags |= RW_EXISTS;
3116                     entry.serverNumber[entry.nServers] = aserver;
3117                     entry.serverPartition[entry.nServers] = apart;
3118                     entry.serverFlags[entry.nServers] = ITSRWVOL;
3119                     entry.nServers++;
3120                 } else {
3121                     /* A RW index is found in the VLDB entry.
3122                      * Verify that the volume location matches the VLDB location.
3123                      * Fix the VLDB entry if it is not correct.
3124                      */
3125
3126                     error =
3127                         VLDB_IsSameAddrs(cellHandle, aserver,
3128                                          entry.serverNumber[temp], &same,
3129                                          &tst);
3130                     if (!error) {
3131                         continue;
3132                     }
3133                     if (!same || (apart != entry.serverPartition[temp])) {
3134                         /* VLDB says volume is in another place. Fix the VLDB entry */
3135                         entry.serverNumber[temp] = aserver;
3136                         entry.serverPartition[temp] = apart;
3137
3138                     }
3139                     entry.flags |= RW_EXISTS;
3140                 }
3141                 if ((elem.ids[BACKVOL] != 0) && elem.isValid[BACKVOL])
3142                     entry.volumeId[BACKVOL] = elem.ids[BACKVOL];
3143                 if ((elem.ids[ROVOL] != 0) && elem.isValid[ROVOL])
3144                     entry.volumeId[ROVOL] = elem.ids[ROVOL];
3145             }
3146
3147             if (elem.isValid[ROVOL]) {
3148                 /*tackle a ro volume */
3149
3150                 if (!Lp_ROMatch(cellHandle, &entry, aserver, apart, 0)) {
3151                     /*add this site */
3152                     if (elem.ids[ROVOL] > entry.volumeId[ROVOL]) {
3153                         /*there is a conflict of ids, keep the later volume */
3154                         /*delete all the ro volumes listed in vldb entry since they 
3155                          * are older */
3156
3157                         int j, count, rwsite;
3158
3159
3160                         count = entry.nServers;
3161                         rwsite = -1;
3162                         for (j = 0; j < count; j++) {
3163                             if (entry.serverFlags[j] & ITSROVOL) {
3164
3165                                 /*delete the site */
3166                                 entry.serverNumber[j] = 0;
3167                                 entry.serverPartition[j] = 0;
3168                                 entry.serverFlags[j] = 0;
3169
3170                             } else if (entry.serverFlags[j] & ITSRWVOL)
3171                                 rwsite = j;
3172                         }
3173                         entry.nServers = 0;
3174                         if (rwsite != -1) {
3175                             entry.serverNumber[entry.nServers] =
3176                                 entry.serverNumber[rwsite];
3177                             entry.serverPartition[entry.nServers] =
3178                                 entry.serverPartition[rwsite];
3179                             entry.serverFlags[entry.nServers] =
3180                                 entry.serverFlags[rwsite];
3181                             entry.nServers++;
3182                         }
3183                         entry.serverNumber[entry.nServers] = aserver;
3184                         entry.serverPartition[entry.nServers] = apart;
3185                         entry.serverFlags[entry.nServers] = ITSROVOL;
3186                         entry.nServers++;
3187                         entry.volumeId[ROVOL] = elem.ids[ROVOL];
3188                         entry.flags |= RO_EXISTS;
3189
3190                     } else if (elem.ids[ROVOL] < entry.volumeId[ROVOL]) {
3191                         if (!(entry.flags & RO_EXISTS)) {
3192                             entry.volumeId[ROVOL] = elem.ids[ROVOL];
3193                             entry.serverNumber[entry.nServers] = aserver;
3194                             entry.serverPartition[entry.nServers] = apart;
3195                             entry.serverFlags[entry.nServers] = ITSROVOL;
3196                             entry.nServers++;
3197                             entry.flags |= RO_EXISTS;
3198                         }
3199
3200                     }
3201
3202                     else if (elem.ids[ROVOL] == entry.volumeId[ROVOL]) {
3203                         entry.serverNumber[entry.nServers] = aserver;
3204                         entry.serverPartition[entry.nServers] = apart;
3205                         entry.serverFlags[entry.nServers] = ITSROVOL;
3206                         entry.nServers++;
3207                         entry.flags |= RO_EXISTS;
3208                         entry.volumeId[ROVOL] = elem.ids[ROVOL];
3209                     }
3210                 }
3211                 if (entry.volumeId[ROVOL] == INVALID_BID)
3212                     entry.volumeId[ROVOL] = elem.ids[ROVOL];
3213             }
3214
3215             if (elem.isValid[BACKVOL]) {
3216                 temp = Lp_GetRwIndex(cellHandle, &entry, 0);
3217                 if (temp != -1) {       /*check if existing backup site matches with the given arguments */
3218                     error =
3219                         VLDB_IsSameAddrs(cellHandle, aserver,
3220                                          entry.serverNumber[temp], &same,
3221                                          &tst);
3222                     if (!error) {
3223                         continue;
3224                     }
3225                 } else {
3226                     /*tackle the backup volume */
3227                     entry.volumeId[BACKVOL] = elem.ids[BACKVOL];
3228                     entry.flags |= BACK_EXISTS;
3229                 }
3230                 if (entry.volumeId[BACKVOL] == INVALID_BID)
3231                     entry.volumeId[BACKVOL] = elem.ids[BACKVOL];
3232             }
3233
3234             VLDB_ReplaceEntry(cellHandle, elem.ids[RWVOL], RWVOL, &entry,
3235                               LOCKREL_OPCODE | LOCKREL_AFSID |
3236                               LOCKREL_TIMESTAMP, &tst);
3237             if (tst) {
3238                 noError = 0;
3239                 totalUE++;
3240
3241                 vcode =
3242                     ubik_VL_ReleaseLock(cellHandle->vos, 0,
3243                               elem.ids[RWVOL], RWVOL,
3244                               LOCKREL_OPCODE | LOCKREL_AFSID |
3245                               LOCKREL_TIMESTAMP);
3246                 if (vcode) {
3247                     noError = 0;
3248                 }
3249             }
3250         }                       /* else update the existing entry */
3251
3252     }                           /* End of while(1) */
3253
3254     if (noError)
3255         return 0;
3256     else
3257         return VOLSERBADOP;
3258 }
3259
3260 /*synchronise vldb with the file server <aserver> and <apart>(if flags=1).
3261 *else synchronise with all the valid partitions on <aserver>
3262 */
3263 int
3264 UV_SyncVldb(afs_cell_handle_p cellHandle, struct rx_connection *server,
3265             afs_int32 apart, int flags, int force, afs_status_p st)
3266 {
3267     int rc = 0;
3268     afs_status_t tst = 0;
3269     afs_int32 count;
3270     int i;
3271     volEntries volumeInfo;
3272     volintInfo *pntr;
3273     struct qHead myQueue;
3274     struct partList PartList;
3275     int noError = 1;
3276     afs_int32 cnt;
3277     char pname[10];
3278
3279     /*this hints the stub to allocate space */
3280     volumeInfo.volEntries_val = (volintInfo *) 0;
3281     volumeInfo.volEntries_len = 0;
3282
3283     if (!flags) {               /*generate all the valid partitions */
3284         UV_ListPartitions(server, &PartList, &cnt, &tst);
3285         if (tst) {
3286             goto fail_UV_SyncVldb;
3287         }
3288     } else {
3289         PartList.partId[0] = apart;
3290         cnt = 1;
3291     }
3292
3293     for (i = 0; i < cnt; i++) {
3294         apart = PartList.partId[i];
3295         /*this hints the stub to allocate space */
3296         volumeInfo.volEntries_val = (volintInfo *) 0;
3297         volumeInfo.volEntries_len = 0;
3298         tst = AFSVolListVolumes(server, apart, 1, &volumeInfo);
3299         if (tst) {
3300             goto fail_UV_SyncVldb;
3301         }
3302         count = volumeInfo.volEntries_len;
3303         pntr = volumeInfo.volEntries_val;
3304
3305         if (!vos_PartitionIdToName(apart, pname, &tst)) {
3306             goto fail_UV_SyncVldb;
3307         }
3308         /*collect all vol entries by their parentid */
3309         tst = GroupEntries(server, pntr, count, &myQueue, apart);
3310         if (tst) {
3311             noError = 0;
3312             if (volumeInfo.volEntries_val) {
3313                 /*free the space allocated by the stub */
3314                 free(volumeInfo.volEntries_val);
3315                 volumeInfo.volEntries_val = 0;
3316             }
3317             continue;
3318         }
3319         tst = ProcessEntries(cellHandle, &myQueue, server, apart, force);
3320         if (tst) {
3321             tst = VOLSERFAILEDOP;
3322             if (volumeInfo.volEntries_val) {
3323                 /*free the space allocated by the stub */
3324                 free(volumeInfo.volEntries_val);
3325                 volumeInfo.volEntries_val = 0;
3326             }
3327             continue;
3328         }
3329         if (noError)
3330             tst = 0;
3331         else
3332             tst = VOLSERFAILEDOP;
3333     }                           /* thru all partitions */
3334     rc = 1;
3335
3336   fail_UV_SyncVldb:
3337
3338     if (volumeInfo.volEntries_val)
3339         free(volumeInfo.volEntries_val);
3340
3341     if (tst != 0) {
3342         rc = 0;
3343     }
3344
3345     if (st != NULL) {
3346         *st = tst;
3347     }
3348     return rc;
3349 }
3350
3351 static afs_int32
3352 CheckVldbRWBK(afs_cell_handle_p cellHandle, struct nvldbentry *entry,
3353               afs_int32 * modified, afs_status_p st)
3354 {
3355     int rc = 0;
3356     afs_status_t tst = 0;
3357     int modentry = 0;
3358     int idx;
3359
3360     if (modified)
3361         *modified = 0;
3362     idx = Lp_GetRwIndex(cellHandle, entry, 0);
3363
3364     /* Check to see if the RW volume exists and set the RW_EXISTS
3365      * flag accordingly.
3366      */
3367     if (idx == -1) {            /* Did not find a RW entry */
3368         if (entry->flags & RW_EXISTS) { /* ... yet entry says RW exists */
3369             entry->flags &= ~RW_EXISTS; /* ... so say RW does not exist */
3370             modentry++;
3371         }
3372     } else {
3373         if (VolumeExists
3374             (cellHandle, entry->serverNumber[idx],
3375              entry->serverPartition[idx], entry->volumeId[RWVOL], &tst)) {
3376             if (!(entry->flags & RW_EXISTS)) {  /* ... yet entry says RW does no
3377                                                  * t exist */
3378                 entry->flags |= RW_EXISTS;      /* ... so say RW does exist */
3379                 modentry++;
3380             }
3381         } else if (tst == ENODEV) {     /* RW volume does not exist */
3382             if (entry->flags & RW_EXISTS) {     /* ... yet entry says RW exists
3383                                                  */
3384                 entry->flags &= ~RW_EXISTS;     /* ... so say RW does not exist
3385                                                  */
3386                 modentry++;
3387             }
3388         } else {
3389             /* If VLDB says it didn't exist, then ignore error */
3390             if (entry->flags & RW_EXISTS) {
3391                 goto fail_CheckVldbRWBK;
3392             }
3393         }
3394     }
3395
3396     /* Check to see if the BK volume exists and set the BACK_EXISTS
3397      * flag accordingly. idx already ponts to the RW entry.
3398      */
3399     if (idx == -1) {            /* Did not find a RW entry */
3400         if (entry->flags & BACK_EXISTS) {       /* ... yet entry says BK exists */
3401             entry->flags &= ~BACK_EXISTS;       /* ... so say BK does not exist */
3402             modentry++;
3403         }
3404     } else {                    /* Found a RW entry */
3405         if (VolumeExists
3406             (cellHandle, entry->serverNumber[idx],
3407              entry->serverPartition[idx], entry->volumeId[BACKVOL], &tst)) {
3408             if (!(entry->flags & BACK_EXISTS)) {        /* ... yet entry says BK does n
3409                                                          * ot exist */
3410                 entry->flags |= BACK_EXISTS;    /* ... so say BK does exist */
3411                 modentry++;
3412             }
3413         } else if (tst == ENODEV) {     /* BK volume does not exist */
3414             if (entry->flags & BACK_EXISTS) {   /* ... yet entry says BK exists
3415                                                  */
3416                 entry->flags &= ~BACK_EXISTS;   /* ... so say BK does not exist
3417                                                  */
3418                 modentry++;
3419             }
3420         } else {
3421             /* If VLDB says it didn't exist, then ignore error */
3422             if (entry->flags & BACK_EXISTS) {
3423                 goto fail_CheckVldbRWBK;
3424             }
3425         }
3426     }
3427
3428     /* If there is an idx but the BK and RW volumes no
3429      * longer exist, then remove the RW entry.
3430      */
3431     if ((idx != -1) && !(entry->flags & RW_EXISTS)
3432         && !(entry->flags & BACK_EXISTS)) {
3433         Lp_SetRWValue(cellHandle, entry, entry->serverNumber[idx],
3434                       entry->serverPartition[idx], 0L, 0L);
3435         entry->nServers--;
3436         modentry++;
3437     }
3438     rc = 1;
3439
3440   fail_CheckVldbRWBK:
3441
3442     if (modified)
3443         *modified = modentry;
3444
3445     if (st != NULL) {
3446         *st = tst;
3447     }
3448     return rc;
3449 }
3450
3451
3452 static int
3453 CheckVldbRO(afs_cell_handle_p cellHandle, struct nvldbentry *entry,
3454             afs_int32 * modified, afs_status_p st)
3455 {
3456     int rc = 0;
3457     afs_status_t tst = 0;
3458     int idx;
3459     int foundro = 0, modentry = 0;
3460
3461     if (modified)
3462         *modified = 0;
3463
3464     /* Check to see if the RO volumes exist and set the RO_EXISTS
3465      * flag accordingly.
3466      */
3467     for (idx = 0; idx < entry->nServers; idx++) {
3468         if (!(entry->serverFlags[idx] & ITSROVOL)) {
3469             continue;           /* not a RO */
3470         }
3471
3472         if (VolumeExists
3473             (cellHandle, entry->serverNumber[idx],
3474              entry->serverPartition[idx], entry->volumeId[ROVOL], &tst)) {
3475             foundro++;
3476         } else if (tst == ENODEV) {     /* RW volume does not exist */
3477             Lp_SetROValue(cellHandle, entry, entry->serverNumber[idx],
3478                           entry->serverPartition[idx], 0L, 0L);
3479             entry->nServers--;
3480             idx--;
3481             modentry++;
3482         } else {
3483             goto fail_CheckVldbRO;
3484         }
3485     }
3486
3487     if (foundro) {              /* A RO volume exists */
3488         if (!(entry->flags & RO_EXISTS)) {      /* ... yet entry says RW does not e
3489                                                  * xist */
3490             entry->flags |= RO_EXISTS;  /* ... so say RW does exist */
3491             modentry++;
3492         }
3493     } else {                    /* A RO volume does not exist */
3494         if (entry->flags & RO_EXISTS) { /* ... yet entry says RO exists */
3495             entry->flags &= ~RO_EXISTS; /* ... so say RO does not exist */
3496             modentry++;
3497         }
3498     }
3499     rc = 1;
3500
3501   fail_CheckVldbRO:
3502
3503     if (modified)
3504         *modified = modentry;
3505
3506     if (st != NULL) {
3507         *st = tst;
3508     }
3509     return rc;
3510 }
3511
3512 /*ensure that <entry> matches with the info on file servers */
3513 int
3514 CheckVldb(afs_cell_handle_p cellHandle, struct nvldbentry *entry,
3515           afs_int32 * modified, afs_status_p st)
3516 {
3517     int rc = 0;
3518     afs_status_t tst = 0;
3519     afs_int32 vcode;
3520     int islocked = 0;
3521     int pass = 0;
3522     afs_int32 modentry = 0;
3523     afs_int32 delentry = 0;
3524
3525     if (modified) {
3526         *modified = 0;
3527     }
3528
3529     if (strlen(entry->name) > (VOLSER_OLDMAXVOLNAME - 10)) {
3530         tst = VOLSERBADOP;
3531         goto fail_CheckVldb;
3532     }
3533
3534   retry:
3535
3536     /* Check to see if the VLDB is ok without locking it (pass 1).
3537      * If it will change, then lock the VLDB entry, read it again,
3538      * then make the changes to it (pass 2).
3539      */