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