/* getting rid of this */
-#define ERROR_EXIT(code) {error=(code); goto error_exit;}
+#define ERROR_EXIT(code) do { \
+ error = (code); \
+ goto error_exit; \
+} while (0)
/* Protos for static routines */
}
int
-yesprompt(char *str)
-{
- int response, c;
- int code;
-
- fprintf(STDERR, "Do you want to %s? [yn](n): ", str);
- response = c = getchar();
- while (!(c == EOF || c == '\n'))
- c = getchar(); /*skip to end of line */
- code = (response == 'y' || response == 'Y');
- return code;
-}
-
-
-int
PrintError(char *msg, afs_int32 errcode)
{
fprintf(STDERR, "%s", msg);
return acode;
}
-#define ONERROR(ec, ep, es) if (ec) { fprintf(STDERR, (es), (ep)); error = (ec); goto rfail; }
-#define ONERROR0(ec, es) if (ec) { fprintf(STDERR, (es)); error = (ec); goto rfail; }
-#define ERROREXIT(ec) { error = (ec); goto rfail; }
+#define ONERROR(ec, ep, es) do { \
+ if (ec) { \
+ fprintf(STDERR, (es), (ep)); \
+ error = (ec); \
+ goto rfail; \
+ } \
+} while (0)
+#define ONERROR0(ec, es) do { \
+ if (ec) { \
+ fprintf(STDERR, (es)); \
+ error = (ec); \
+ goto rfail; \
+ } \
+} while (0)
+#define ERROREXIT(ec) do { \
+ error = (ec); \
+ goto rfail; \
+} while (0)
/* Get a "transaction" on this replica. Create the volume
* if necessary. Return the time from which a dump should
return 0;
}
+/**
+ * Check if a trans has timed out, and recreate it if necessary.
+ *
+ * @param[in] aconn RX connection to the relevant server
+ * @param[inout] atid Transaction ID to check; if we recreated the trans,
+ * contains the new trans ID on success
+ * @param[in] apart Partition for the transaction
+ * @param[in] astat The status of the original transaction
+ *
+ * @return operation status
+ * @retval 0 existing transaction is still valid, or we managed to recreate
+ * the trans successfully
+ * @retval nonzero Fatal error; bail out
+ */
+static int
+CheckTrans(struct rx_connection *aconn, afs_int32 *atid, afs_int32 apart,
+ struct volser_status *astat)
+{
+ struct volser_status new_status;
+ afs_int32 code;
+
+ memset(&new_status, 0, sizeof(new_status));
+ code = AFSVolGetStatus(aconn, *atid, &new_status);
+ if (code) {
+ if (code == ENOENT) {
+ *atid = 0;
+ VPRINT1("Old transaction on cloned volume %lu timed out, "
+ "restarting transaction\n", (long unsigned) astat->volID);
+ code = AFSVolTransCreate_retry(aconn, astat->volID, apart,
+ ITBusy, atid);
+ if (code) {
+ PrintError("Failed to recreate cloned RO volume transaction\n",
+ code);
+ return 1;
+ }
+
+ memset(&new_status, 0, sizeof(new_status));
+ code = AFSVolGetStatus(aconn, *atid, &new_status);
+ if (code) {
+ PrintError("Failed to get status on recreated transaction\n",
+ code);
+ return 1;
+ }
+
+ if (memcmp(&new_status, astat, sizeof(new_status)) != 0) {
+ PrintError("Recreated transaction on cloned RO volume, but "
+ "the volume has changed!\n", 0);
+ return 1;
+ }
+ } else {
+ PrintError("Unable to get status of current cloned RO transaction\n",
+ code);
+ return 1;
+ }
+ } else {
+ if (memcmp(&new_status, astat, sizeof(new_status)) != 0) {
+ /* sanity check */
+ PrintError("Internal error: current GetStatus does not match "
+ "original GetStatus?\n", 0);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/* UV_ReleaseVolume()
* Release volume <afromvol> on <afromserver> <afrompart> to all
struct volser_status volstatus;
char hoststr[16];
afs_int32 origflags[NMAXNSERVERS];
+ struct volser_status orig_status;
memset(remembertime, 0, sizeof(remembertime));
memset(&results, 0, sizeof(results));
VPRINT1("Starting transaction on cloned volume %u...", cloneVolId);
code =
AFSVolTransCreate_retry(fromconn, cloneVolId, afrompart, ITBusy, &fromtid);
+ if (!code) {
+ memset(&orig_status, 0, sizeof(orig_status));
+ code = AFSVolGetStatus(fromconn, fromtid, &orig_status);
+ }
if (!fullrelease && code)
ONERROR(VOLSERNOVOL, afromvol,
"Old clone is inaccessible. Try vos release -f %u.\n");
if (!volcount)
continue;
+ code = CheckTrans(fromconn, &fromtid, afrompart, &orig_status);
+ if (code) {
+ code = ENOENT;
+ goto rfail;
+ }
+
if (verbose) {
fprintf(STDOUT, "Starting ForwardMulti from %lu to %u on %s",
(unsigned long)cloneVolId, entry.volumeId[ROVOL],