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