dafs-salvage-deal-with-clones-20071101
authorTom Keiser <tkeiser@gmail.com>
Thu, 1 Nov 2007 14:59:38 +0000 (14:59 +0000)
committerDerrick Brashear <shadow@dementia.org>
Thu, 1 Nov 2007 14:59:38 +0000 (14:59 +0000)
FIXES 75591

cope with trying to salvage a clone correctly

12 files changed:
src/vol/daemon_com.c
src/vol/daemon_com.h
src/vol/fssync-client.c
src/vol/fssync-server.c
src/vol/salvaged.c
src/vol/salvsync-client.c
src/vol/salvsync-server.c
src/vol/salvsync.h
src/vol/vol-salvage.c
src/vol/vol-salvage.h
src/vol/voldefs.h
src/vol/volume.c

index 49a69dc..ceff6c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006, Sine Nomine Associates and others.
+ * Copyright 2006-2007, Sine Nomine Associates and others.
  * All Rights Reserved.
  * 
  * This software has been released under the terms of the IBM Public
@@ -109,7 +109,8 @@ SYNC_connect(SYNC_client_state * state)
        if (!*timeout)
            break;
        if (!(*timeout & 1))
-           Log("SYNC_connect temporary failure (will retry)\n");
+           Log("SYNC_connect: temporary failure on circuit '%s' (will retry)\n",
+               state->proto_name);
        SYNC_disconnect(state);
        sleep(*timeout++);
     }
@@ -148,26 +149,16 @@ SYNC_closeChannel(SYNC_client_state * state)
 
     com.hdr.command = SYNC_COM_CHANNEL_CLOSE;
     com.hdr.command_len = sizeof(SYNC_command_hdr);
+    com.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
 
     /* in case the other end dropped, don't do any retries */
     state->retry_limit = 0;
     state->hard_timeout = 0;
 
-    code = SYNC_ask(state, &com, &res);
-
-    if (code == SYNC_OK) {
-       if (res.hdr.response != SYNC_OK) {
-           Log("SYNC_closeChannel:  channel shutdown request denied; closing socket anyway\n");
-       } else if (!(res.hdr.flags & SYNC_FLAG_CHANNEL_SHUTDOWN)) {
-           Log("SYNC_closeChannel:  channel shutdown request mishandled by server\n");
-       }
-    } else {
-       Log("SYNC_closeChannel: channel communications problem");
-    }
-
+    SYNC_ask(state, &com, &res);
     SYNC_disconnect(state);
 
-    return code;
+    return SYNC_OK;
 }
 
 int
@@ -242,21 +233,28 @@ SYNC_ask(SYNC_client_state * state, SYNC_command * com, SYNC_response * res)
        if (code == SYNC_OK) {
            break;
        } else if (code == SYNC_BAD_COMMAND) {
-           Log("SYNC_ask: protocol mismatch; make sure fileserver, volserver, salvageserver and salvager are same version\n");
+           Log("SYNC_ask: protocol mismatch on circuit '%s'; make sure "
+               "fileserver, volserver, salvageserver and salvager are same "
+               "version\n", state->proto_name);
            break;
-       } else if (code == SYNC_COM_ERROR) {
-           Log("SYNC_ask: protocol communications failure; attempting reconnect to server\n");
+       } else if ((code == SYNC_COM_ERROR) && (tries < state->retry_limit)) {
+           Log("SYNC_ask: protocol communications failure on circuit '%s'; "
+               "attempting reconnect to server\n", state->proto_name);
            SYNC_reconnect(state);
            /* try again */
        } else {
-           /* unknown (probably protocol-specific) response code, pass it up to the caller, and let them deal with it */
+           /* 
+            * unknown (probably protocol-specific) response code, pass it up to 
+            * the caller, and let them deal with it 
+            */
            break;
        }
     }
 
     if (code == SYNC_COM_ERROR) {
-       Log("SYNC_ask: fatal protocol error; disabling sync protocol to server running on port %d until next server restart\n", 
-           state->port);
+       Log("SYNC_ask: fatal protocol error on circuit '%s'; disabling sync "
+           "protocol to server running on port %d until next server restart\n", 
+           state->proto_name, state->port);
        state->fatal_error = 1;
     }
 
@@ -274,13 +272,15 @@ SYNC_ask_internal(SYNC_client_state * state, SYNC_command * com, SYNC_response *
 #endif
 
     if (state->fd == -1) {
-       Log("SYNC_ask:  invalid sync file descriptor\n");
+       Log("SYNC_ask:  invalid sync file descriptor on circuit '%s'\n",
+           state->proto_name);
        res->hdr.response = SYNC_COM_ERROR;
        goto done;
     }
 
     if (com->hdr.command_len > SYNC_PROTO_MAX_LEN) {
-       Log("SYNC_ask:  internal SYNC buffer too small; please file a bug\n");
+       Log("SYNC_ask:  internal SYNC buffer too small on circuit '%s'; "
+           "please file a bug\n", state->proto_name);
        res->hdr.response = SYNC_COM_ERROR;
        goto done;
     }
@@ -296,25 +296,37 @@ SYNC_ask_internal(SYNC_client_state * state, SYNC_command * com, SYNC_response *
 #ifdef AFS_NT40_ENV
     n = send(state->fd, buf, com->hdr.command_len, 0);
     if (n != com->hdr.command_len) {
-       Log("SYNC_ask:  write failed\n");
+       Log("SYNC_ask:  write failed on circuit '%s'\n", state->proto_name);
        res->hdr.response = SYNC_COM_ERROR;
        goto done;
     }
 
+    if (com->hdr.command == SYNC_COM_CHANNEL_CLOSE) {
+       /* short circuit close channel requests */
+       res->hdr.response = SYNC_OK;
+       goto done;
+    }
+
     n = recv(state->fd, buf, SYNC_PROTO_MAX_LEN, 0);
     if (n == 0 || (n < 0 && WSAEINTR != WSAGetLastError())) {
-       Log("SYNC_ask:  No response\n");
+       Log("SYNC_ask:  No response on circuit '%s'\n", state->proto_name);
        res->hdr.response = SYNC_COM_ERROR;
        goto done;
     }
 #else /* !AFS_NT40_ENV */
     n = write(state->fd, buf, com->hdr.command_len);
     if (com->hdr.command_len != n) {
-       Log("SYNC_ask: write failed\n");
+       Log("SYNC_ask: write failed on circuit '%s'\n", state->proto_name);
        res->hdr.response = SYNC_COM_ERROR;
        goto done;
     }
 
+    if (com->hdr.command == SYNC_COM_CHANNEL_CLOSE) {
+       /* short circuit close channel requests */
+       res->hdr.response = SYNC_OK;
+       goto done;
+    }
+
     /* receive the response */
     iov[0].iov_base = (char *)&res->hdr;
     iov[0].iov_len = sizeof(res->hdr);
@@ -327,7 +339,7 @@ SYNC_ask_internal(SYNC_client_state * state, SYNC_command * com, SYNC_response *
     }
     n = readv(state->fd, iov, iovcnt);
     if (n == 0 || (n < 0 && errno != EINTR)) {
-       Log("SYNC_ask: No response\n");
+       Log("SYNC_ask: No response on circuit '%s'\n", state->proto_name);
        res->hdr.response = SYNC_COM_ERROR;
        goto done;
     }
@@ -336,7 +348,8 @@ SYNC_ask_internal(SYNC_client_state * state, SYNC_command * com, SYNC_response *
     res->recv_len = n;
 
     if (n < sizeof(res->hdr)) {
-       Log("SYNC_ask:  response too short\n");
+       Log("SYNC_ask:  response too short on circuit '%s'\n", 
+           state->proto_name);
        res->hdr.response = SYNC_COM_ERROR;
        goto done;
     }
@@ -345,7 +358,8 @@ SYNC_ask_internal(SYNC_client_state * state, SYNC_command * com, SYNC_response *
 #endif
 
     if ((n - sizeof(res->hdr)) > res->payload.len) {
-       Log("SYNC_ask:  response too long\n");
+       Log("SYNC_ask:  response too long on circuit '%s'\n", 
+           state->proto_name);
        res->hdr.response = SYNC_COM_ERROR;
        goto done;
     }
@@ -354,12 +368,13 @@ SYNC_ask_internal(SYNC_client_state * state, SYNC_command * com, SYNC_response *
 #endif
 
     if (res->hdr.response_len != n) {
-       Log("SYNC_ask:  length field in response inconsistent\n");
+       Log("SYNC_ask:  length field in response inconsistent "
+           "on circuit '%s'\n", state->proto_name);
        res->hdr.response = SYNC_COM_ERROR;
        goto done;
     }
     if (res->hdr.response == SYNC_DENIED) {
-       Log("SYNC_ask: negative response\n");
+       Log("SYNC_ask: negative response on circuit '%s'\n", state->proto_name);
     }
 
   done:
index 8464367..3c61021 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006, Sine Nomine Associates and others.
+ * Copyright 2006-2007, Sine Nomine Associates and others.
  * All Rights Reserved.
  * 
  * This software has been released under the terms of the IBM Public
@@ -53,7 +53,7 @@
 /* general reason codes */
 #define SYNC_REASON_NONE                 0
 #define SYNC_REASON_MALFORMED_PACKET     1
-
+#define SYNC_REASON_NOMEM                2
 
 /* SYNC protocol flags
  *
@@ -84,6 +84,7 @@ typedef struct SYNC_client_state {
     afs_uint32 proto_version;
     int retry_limit;            /* max number of times for SYNC_ask to retry */
     afs_int32 hard_timeout;     /* upper limit on time to keep trying */
+    char * proto_name;          /**< sync protocol associated with this conn */
     byte fatal_error;           /* fatal error on this client conn */
 } SYNC_client_state;
 
index 7715bca..d983b4c 100644 (file)
@@ -92,7 +92,14 @@ RCSID
 
 extern int LogLevel;
 
-static SYNC_client_state fssync_state = { -1, 2040, FSYNC_PROTO_VERSION, 5, 120 };
+static SYNC_client_state fssync_state = 
+    { -1,                    /* file descriptor */
+      2040,                  /* port number */
+      FSYNC_PROTO_VERSION,   /* protocol version */
+      5,                     /* connect retry limit */
+      120,                   /* hard timeout */
+      "FSSYNC",              /* protocol name string */
+    };
 
 #ifdef AFS_PTHREAD_ENV
 static pthread_mutex_t vol_fsync_mutex;
index 8aa6e00..0d135cb 100644 (file)
@@ -6,7 +6,7 @@
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  *
- * Portions Copyright (c) 2006 Sine Nomine Associates
+ * Portions Copyright (c) 2006-2007 Sine Nomine Associates
  */
 
 /*
@@ -380,6 +380,14 @@ FSYNC_com(int fd)
        return;
     }
 
+    if (com.recv_len < sizeof(com.hdr)) {
+       Log("FSSYNC_com:  invalid protocol message length (%u)\n", com.recv_len);
+       res.hdr.response = SYNC_COM_ERROR;
+       res.hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+       goto respond;
+    }
+
     if (com.hdr.proto_version != FSYNC_PROTO_VERSION) {
        Log("FSYNC_com:  invalid protocol version (%u)\n", com.hdr.proto_version);
        res.hdr.response = SYNC_COM_ERROR;
@@ -387,6 +395,13 @@ FSYNC_com(int fd)
        goto respond;
     }
 
+    if (com.hdr.command == SYNC_COM_CHANNEL_CLOSE) {
+       res.hdr.response = SYNC_OK;
+       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+       goto respond;
+    }
+
+
     VOL_LOCK;
     switch (com.hdr.command) {
     case FSYNC_VOL_ON:
@@ -408,10 +423,6 @@ FSYNC_com(int fd)
     case FSYNC_VOL_STATS_VLRU:
        res.hdr.response = FSYNC_com_StatsOp(fd, &com, &res);
        break;
-    case SYNC_COM_CHANNEL_CLOSE:
-       res.hdr.response = SYNC_OK;
-       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
-       break;
     default:
        res.hdr.response = SYNC_BAD_COMMAND;
        break;
index 1e6db8b..1388d60 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006, Sine Nomine Associates and others.
+ * Copyright 2006-2007, Sine Nomine Associates and others.
  * All Rights Reserved.
  * 
  * This software has been released under the terms of the IBM Public
@@ -529,6 +529,9 @@ SalvageServer(void)
        node = SALVSYNC_getWork();
        assert(node != NULL);
 
+       Log("dispatching child to salvage volume %u...\n",
+           node->command.sop.parent);
+
        VOL_LOCK;
        /* find a slot */
        for (slot = 0; slot < Parallel; slot++) {
@@ -572,7 +575,8 @@ DoSalvageVolume(struct SalvageQueueNode * node, int slot)
     int ret;
     struct DiskPartition * partP;
 
-    VChildProcReconnectFS();
+    /* do not allow further forking inside salvager */
+    canfork = 0;
 
     /* do not attempt to close parent's logFile handle as
      * another thread may have held the lock on the FILE
@@ -587,7 +591,7 @@ DoSalvageVolume(struct SalvageQueueNode * node, int slot)
        ShowLog = 0;
     }
 
-    if (node->command.sop.volume <= 0) {
+    if (node->command.sop.parent <= 0) {
        Log("salvageServer: invalid volume id specified; salvage aborted\n");
        return 1;
     }
@@ -600,9 +604,7 @@ DoSalvageVolume(struct SalvageQueueNode * node, int slot)
     }
 
     /* Salvage individual volume; don't notify fs */
-    SalvageFileSys1(partP, node->command.sop.volume);
-
-    VDisconnectFS();
+    SalvageFileSys1(partP, node->command.sop.parent);
 
     fclose(logFile);
     return 0;
@@ -654,7 +656,7 @@ SalvageChildReaperThread(void * args)
 
        /* ok, we've reaped a child */
        current_workers--;
-       SALVSYNC_doneWorkByPid(pid, 0);
+       SALVSYNC_doneWorkByPid(pid, WEXITSTATUS(status));
        assert(pthread_cond_broadcast(&worker_cv) == 0);
     }
 
@@ -671,7 +673,9 @@ Reap_Child(char *prog, int * pid, int * status)
        *pid = ret;
         if (WCOREDUMP(*status))
            Log("\"%s\" core dumped!\n", prog);
-       if (WIFSIGNALED(*status) != 0 || WEXITSTATUS(*status) != 0)
+       if ((WIFSIGNALED(*status) != 0) ||
+           ((WEXITSTATUS(*status) != 0) &&
+            (WEXITSTATUS(*status) != SALSRV_EXIT_VOLGROUP_LINK)))
            Log("\"%s\" (pid=%d) terminated abnormally!\n", prog, ret);
     } else {
        Log("wait returned -1\n");
index c504fe0..f725867 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006, Sine Nomine Associates and others.
+ * Copyright 2006-2007, Sine Nomine Associates and others.
  * All Rights Reserved.
  * 
  * This software has been released under the terms of the IBM Public
@@ -68,7 +68,14 @@ extern int LogLevel;
 extern int VInit;
 extern pthread_mutex_t vol_salvsync_mutex;
 
-static SYNC_client_state salvsync_client_state = { -1, 2041, SALVSYNC_PROTO_VERSION, 5, 120 };
+static SYNC_client_state salvsync_client_state = 
+    { -1,                     /* file descriptor */
+      2041,                   /* port */
+      SALVSYNC_PROTO_VERSION, /* protocol version */
+      5,                      /* connect retry limit */
+      120,                    /* hard timeout */
+      "SALVSYNC",             /* protocol name string */
+    };
 
 /*
  * client-side routines
@@ -97,6 +104,9 @@ afs_int32
 SALVSYNC_askSalv(SYNC_command * com, SYNC_response * res)
 {
     afs_int32 code;
+    SALVSYNC_command_hdr * scom = com->payload.buf;
+
+    scom->hdr_version = SALVSYNC_PROTO_VERSION;
 
     VSALVSYNC_LOCK;
     code = SYNC_ask(&salvsync_client_state, com, res);
@@ -150,6 +160,7 @@ SALVSYNC_SalvageVolume(VolumeId volume, char *partName, int command, int reason,
     com.hdr.reason = reason;
     com.hdr.command_len = sizeof(com.hdr) + sizeof(scom);
     scom.volume = volume;
+    scom.parent = volume;
     scom.prio = prio;
 
     if (partName) {
@@ -161,4 +172,46 @@ SALVSYNC_SalvageVolume(VolumeId volume, char *partName, int command, int reason,
     return SALVSYNC_askSalv(&com, res);
 }
 
+afs_int32
+SALVSYNC_LinkVolume(VolumeId parent, 
+                   VolumeId clone,
+                   char * partName,
+                   SYNC_response * res_in)
+{
+    SYNC_command com;
+    SYNC_response res_l, *res;
+    SALVSYNC_command_hdr scom;
+    SALVSYNC_response_hdr sres;
+    int n, tot;
+
+    memset(&com, 0, sizeof(com));
+    memset(&scom, 0, sizeof(scom));
+
+    if (res_in) {
+       res = res_in;
+    } else {
+       memset(&res_l, 0, sizeof(res_l));
+       memset(&sres, 0, sizeof(sres));
+       res_l.payload.buf = (void *) &sres;
+       res_l.payload.len = sizeof(sres);
+       res = &res_l;
+    }
+
+    com.payload.buf = (void *) &scom;
+    com.payload.len = sizeof(scom);
+    com.hdr.command = SALVSYNC_OP_LINK;
+    com.hdr.reason = SALVSYNC_REASON_WHATEVER;
+    com.hdr.command_len = sizeof(com.hdr) + sizeof(scom);
+    scom.volume = clone;
+    scom.parent = parent;
+
+    if (partName) {
+       strlcpy(scom.partName, partName, sizeof(scom.partName));
+    } else {
+       scom.partName[0] = '\0';
+    }
+
+    return SALVSYNC_askSalv(&com, res);
+}
+
 #endif /* AFS_DEMAND_ATTACH_FS */
index 70d2a4a..f159617 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006, Sine Nomine Associates and others.
+ * Copyright 2006-2007, Sine Nomine Associates and others.
  * All Rights Reserved.
  * 
  * This software has been released under the terms of the IBM Public
@@ -112,24 +112,34 @@ struct Lock SALVSYNC_handler_lock;
  * SALVSYNC is a feature specific to the demand attach fileserver
  */
 
+static int AllocNode(struct SalvageQueueNode ** node);
+
 static int AddToSalvageQueue(struct SalvageQueueNode * node);
 static void DeleteFromSalvageQueue(struct SalvageQueueNode * node);
 static void AddToPendingQueue(struct SalvageQueueNode * node);
 static void DeleteFromPendingQueue(struct SalvageQueueNode * node);
 static struct SalvageQueueNode * LookupPendingCommand(SALVSYNC_command_hdr * qry);
 static struct SalvageQueueNode * LookupPendingCommandByPid(int pid);
-static void RaiseCommandPrio(struct SalvageQueueNode * node, SALVSYNC_command_hdr * com);
-
-static struct SalvageQueueNode * LookupNode(VolumeId vid, char * partName);
-static struct SalvageQueueNode * LookupNodeByCommand(SALVSYNC_command_hdr * qry);
+static void UpdateCommandPrio(struct SalvageQueueNode * node);
+static void HandlePrio(struct SalvageQueueNode * clone, 
+                      struct SalvageQueueNode * parent,
+                      afs_uint32 new_prio);
+
+static int LinkNode(struct SalvageQueueNode * parent,
+                   struct SalvageQueueNode * clone);
+
+static struct SalvageQueueNode * LookupNode(VolumeId vid, char * partName, 
+                                           struct SalvageQueueNode ** parent);
+static struct SalvageQueueNode * LookupNodeByCommand(SALVSYNC_command_hdr * qry,
+                                                    struct SalvageQueueNode ** parent);
 static void AddNodeToHash(struct SalvageQueueNode * node);
 static void DeleteNodeFromHash(struct SalvageQueueNode * node);
 
 static afs_int32 SALVSYNC_com_Salvage(SALVSYNC_command * com, SALVSYNC_response * res);
 static afs_int32 SALVSYNC_com_Cancel(SALVSYNC_command * com, SALVSYNC_response * res);
-static afs_int32 SALVSYNC_com_RaisePrio(SALVSYNC_command * com, SALVSYNC_response * res);
 static afs_int32 SALVSYNC_com_Query(SALVSYNC_command * com, SALVSYNC_response * res);
 static afs_int32 SALVSYNC_com_CancelAll(SALVSYNC_command * com, SALVSYNC_response * res);
+static afs_int32 SALVSYNC_com_Link(SALVSYNC_command * com, SALVSYNC_response * res);
 
 
 extern int LogLevel;
@@ -139,21 +149,24 @@ extern pthread_mutex_t vol_salvsync_mutex;
 static int AcceptSd = -1;              /* Socket used by server for accepting connections */
 
 
-/* be careful about rearranging elements in this structure.
- * element placement has been optimized for locality of reference
- * in SALVSYNC_getWork() */
+/**
+ * queue of all volumes waiting to be salvaged.
+ */
 struct SalvageQueue {
     volatile int total_len;
-    volatile afs_int32 last_insert;    /* id of last partition to have a salvage node insert */
+    volatile afs_int32 last_insert;    /**< id of last partition to have a salvage node inserted */
     volatile int len[VOLMAXPARTS+1];
-    volatile struct rx_queue part[VOLMAXPARTS+1];
+    volatile struct rx_queue part[VOLMAXPARTS+1]; /**< per-partition queues of pending salvages */
     pthread_cond_t cv;
 };
 static struct SalvageQueue salvageQueue;  /* volumes waiting to be salvaged */
 
+/**
+ * queue of all volumes currently being salvaged.
+ */
 struct QueueHead {
-    volatile struct rx_queue q;
-    volatile int len;
+    volatile struct rx_queue q;  /**< queue of salvages in progress */
+    volatile int len;            /**< length of in-progress queue */
     pthread_cond_t queue_change_cv;
 };
 static struct QueueHead pendingQueue;  /* volumes being salvaged */
@@ -183,7 +196,8 @@ static int partition_salvaging[VOLMAXPARTS+1];
 static struct QueueHead  SalvageHashTable[VSHASH_SIZE];
 
 static struct SalvageQueueNode *
-LookupNode(afs_uint32 vid, char * partName)
+LookupNode(afs_uint32 vid, char * partName,
+          struct SalvageQueueNode ** parent)
 {
     struct rx_queue *qp, *nqp;
     struct SalvageQueueNode *vsp;
@@ -200,13 +214,24 @@ LookupNode(afs_uint32 vid, char * partName)
     if (queue_IsEnd(&SalvageHashTable[idx], qp)) {
        vsp = NULL;
     }
+
+    if (parent) {
+       if (vsp) {
+           *parent = (vsp->type == SALVSYNC_VOLGROUP_CLONE) ?
+               vsp->volgroup.parent : vsp;
+       } else {
+           *parent = NULL;
+       }
+    }
+
     return vsp;
 }
 
 static struct SalvageQueueNode *
-LookupNodeByCommand(SALVSYNC_command_hdr * qry)
+LookupNodeByCommand(SALVSYNC_command_hdr * qry,
+                   struct SalvageQueueNode ** parent)
 {
-    return LookupNode(qry->volume, qry->partName);
+    return LookupNode(qry->volume, qry->partName, parent);
 }
 
 static void
@@ -420,6 +445,14 @@ SALVSYNC_com(int fd)
        return;
     }
 
+    if (com.recv_len < sizeof(com.hdr)) {
+       Log("SALVSYNC_com:  invalid protocol message length (%u)\n", com.recv_len);
+       res.hdr.response = SYNC_COM_ERROR;
+       res.hdr.reason = SYNC_REASON_MALFORMED_PACKET;
+       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+       goto respond;
+    }
+
     if (com.hdr.proto_version != SALVSYNC_PROTO_VERSION) {
        Log("SALVSYNC_com:  invalid protocol version (%u)\n", com.hdr.proto_version);
        res.hdr.response = SYNC_COM_ERROR;
@@ -427,6 +460,12 @@ SALVSYNC_com(int fd)
        goto respond;
     }
 
+    if (com.hdr.command == SYNC_COM_CHANNEL_CLOSE) {
+       res.hdr.response = SYNC_OK;
+       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+       goto respond;
+    }
+
     if (com.recv_len != (sizeof(com.hdr) + sizeof(SALVSYNC_command_hdr))) {
        Log("SALVSYNC_com:  invalid protocol message length (%u)\n", com.recv_len);
        res.hdr.response = SYNC_COM_ERROR;
@@ -440,6 +479,7 @@ SALVSYNC_com(int fd)
     case SALVSYNC_NOP:
        break;
     case SALVSYNC_SALVAGE:
+    case SALVSYNC_RAISEPRIO:
        res.hdr.response = SALVSYNC_com_Salvage(&scom, &sres);
        break;
     case SALVSYNC_CANCEL:
@@ -450,17 +490,13 @@ SALVSYNC_com(int fd)
        /* cancel all queued salvages */
        res.hdr.response = SALVSYNC_com_CancelAll(&scom, &sres);
        break;
-    case SALVSYNC_RAISEPRIO:
-       /* raise the priority of a salvage */
-       res.hdr.response = SALVSYNC_com_RaisePrio(&scom, &sres);
-       break;
     case SALVSYNC_QUERY:
        /* query whether a volume is done salvaging */
        res.hdr.response = SALVSYNC_com_Query(&scom, &sres);
        break;
-    case SYNC_COM_CHANNEL_CLOSE:
-       res.hdr.response = SYNC_OK;
-       res.hdr.flags |= SYNC_FLAG_CHANNEL_SHUTDOWN;
+    case SALVSYNC_OP_LINK:
+       /* link a clone to its parent in the scheduler */
+       res.hdr.response = SALVSYNC_com_Link(&scom, &sres);
        break;
     default:
        res.hdr.response = SYNC_BAD_COMMAND;
@@ -482,7 +518,8 @@ static afs_int32
 SALVSYNC_com_Salvage(SALVSYNC_command * com, SALVSYNC_response * res)
 {
     afs_int32 code = SYNC_OK;
-    struct SalvageQueueNode * node;
+    struct SalvageQueueNode * node, * clone;
+    int hash = 0;
 
     if (SYNC_verifyProtocolString(com->sop->partName, sizeof(com->sop->partName))) {
        code = SYNC_FAILED;
@@ -490,41 +527,41 @@ SALVSYNC_com_Salvage(SALVSYNC_command * com, SALVSYNC_response * res)
        goto done;
     }
 
-    node = LookupNodeByCommand(com->sop);
+    clone = LookupNodeByCommand(com->sop, &node);
 
-    /* schedule a salvage for this volume */
-    if (node != NULL) {
-       switch (node->state) {
-       case SALVSYNC_STATE_ERROR:
-       case SALVSYNC_STATE_DONE:
-           memcpy(&node->command.com, com->hdr, sizeof(SYNC_command_hdr));
-           memcpy(&node->command.sop, com->sop, sizeof(SALVSYNC_command_hdr));
-           node->command.sop.prio = 0;
-           if (AddToSalvageQueue(node)) {
-               code = SYNC_DENIED;
-           }
-           break;
-       default:
-           break;
-       }
-    } else {
-       node = (struct SalvageQueueNode *) malloc(sizeof(struct SalvageQueueNode));
-       if (node == NULL) {
+    if (node == NULL) {
+       if (AllocNode(&node)) {
            code = SYNC_DENIED;
+           res->hdr->reason = SYNC_REASON_NOMEM;
            goto done;
        }
-       memset(node, 0, sizeof(struct SalvageQueueNode));
-       memcpy(&node->command.com, com->hdr, sizeof(SYNC_command_hdr));
-       memcpy(&node->command.sop, com->sop, sizeof(SALVSYNC_command_hdr));
-       AddNodeToHash(node);
+       clone = node;
+       hash = 1;
+    }
+
+    HandlePrio(clone, node, com->sop->prio);
+
+    switch (node->state) {
+    case SALVSYNC_STATE_QUEUED:
+       UpdateCommandPrio(node);
+       break;
+
+    case SALVSYNC_STATE_ERROR:
+    case SALVSYNC_STATE_DONE:
+    case SALVSYNC_STATE_UNKNOWN:
+       memcpy(&clone->command.com, com->hdr, sizeof(SYNC_command_hdr));
+       memcpy(&clone->command.sop, com->sop, sizeof(SALVSYNC_command_hdr));
        if (AddToSalvageQueue(node)) {
-           /* roll back */
-           DeleteNodeFromHash(node);
-           free(node);
-           node = NULL;
            code = SYNC_DENIED;
-           goto done;
        }
+       break;
+
+    default:
+       break;
+    }
+
+    if (hash) {
+       AddNodeToHash(node);
     }
 
     res->hdr->flags |= SALVSYNC_FLAG_VOL_STATS_VALID;
@@ -547,7 +584,7 @@ SALVSYNC_com_Cancel(SALVSYNC_command * com, SALVSYNC_response * res)
        goto done;
     }
 
-    node = LookupNodeByCommand(com->sop);
+    node = LookupNodeByCommand(com->sop, NULL);
 
     if (node == NULL) {
        res->sop->state = SALVSYNC_STATE_UNKNOWN;
@@ -556,7 +593,8 @@ SALVSYNC_com_Cancel(SALVSYNC_command * com, SALVSYNC_response * res)
        res->hdr->flags |= SALVSYNC_FLAG_VOL_STATS_VALID;
        res->sop->prio = node->command.sop.prio;
        res->sop->state = node->state;
-       if (node->state == SALVSYNC_STATE_QUEUED) {
+       if ((node->type == SALVSYNC_VOLGROUP_PARENT) && 
+           (node->state == SALVSYNC_STATE_QUEUED)) {
            DeleteFromSalvageQueue(node);
        }
     }
@@ -580,11 +618,14 @@ SALVSYNC_com_CancelAll(SALVSYNC_command * com, SALVSYNC_response * res)
     return SYNC_OK;
 }
 
+/**
+ * link a queue node for a clone to its parent volume.
+ */
 static afs_int32
-SALVSYNC_com_RaisePrio(SALVSYNC_command * com, SALVSYNC_response * res)
+SALVSYNC_com_Link(SALVSYNC_command * com, SALVSYNC_response * res)
 {
     afs_int32 code = SYNC_OK;
-    struct SalvageQueueNode * node;
+    struct SalvageQueueNode * clone, * parent;
 
     if (SYNC_verifyProtocolString(com->sop->partName, sizeof(com->sop->partName))) {
        code = SYNC_FAILED;
@@ -592,35 +633,31 @@ SALVSYNC_com_RaisePrio(SALVSYNC_command * com, SALVSYNC_response * res)
        goto done;
     }
 
-    node = LookupNodeByCommand(com->sop);
+    /* lookup clone's salvage scheduling node */
+    clone = LookupNodeByCommand(com->sop, NULL);
+    if (clone == NULL) {
+       code = SYNC_DENIED;
+       res->hdr->reason = SALVSYNC_REASON_ERROR;
+       goto done;
+    }
 
-    /* raise the priority of a salvage */
-    if (node == NULL) {
-       code = SALVSYNC_com_Salvage(com, res);
-       node = LookupNodeByCommand(com->sop);
-    } else {
-       switch (node->state) {
-       case SALVSYNC_STATE_QUEUED:
-           RaiseCommandPrio(node, com->sop);
-           break;
-       case SALVSYNC_STATE_SALVAGING:
-           break;
-       case SALVSYNC_STATE_ERROR:
-       case SALVSYNC_STATE_DONE:
-           code = SALVSYNC_com_Salvage(com, res);
-           break;
-       default:
-           break;
+    /* lookup parent's salvage scheduling node */
+    parent = LookupNode(com->sop->parent, com->sop->partName, NULL);
+    if (parent == NULL) {
+       if (AllocNode(&parent)) {
+           code = SYNC_DENIED;
+           res->hdr->reason = SYNC_REASON_NOMEM;
+           goto done;
        }
+       memcpy(&parent->command.com, com->hdr, sizeof(SYNC_command_hdr));
+       memcpy(&parent->command.sop, com->sop, sizeof(SALVSYNC_command_hdr));
+       parent->command.sop.volume = parent->command.sop.parent = com->sop->parent;
+       AddNodeToHash(parent);
     }
 
-    if (node == NULL) {
-       res->sop->prio = 0;
-       res->sop->state = SALVSYNC_STATE_UNKNOWN;
-    } else {
-       res->hdr->flags |= SALVSYNC_FLAG_VOL_STATS_VALID;
-       res->sop->prio = node->command.sop.prio;
-       res->sop->state = node->state;
+    if (LinkNode(parent, clone)) {
+       code = SYNC_DENIED;
+       goto done;
     }
 
  done:
@@ -639,7 +676,7 @@ SALVSYNC_com_Query(SALVSYNC_command * com, SALVSYNC_response * res)
        goto done;
     }
 
-    node = LookupNodeByCommand(com->sop);
+    LookupNodeByCommand(com->sop, &node);
 
     /* query whether a volume is done salvaging */
     if (node == NULL) {
@@ -791,9 +828,127 @@ GetHandler(fd_set * fdsetp, int *maxfdp)
 }
 
 static int
+AllocNode(struct SalvageQueueNode ** node_out)
+{
+    int code = 0;
+    struct SalvageQueueNode * node;
+
+    *node_out = node = (struct SalvageQueueNode *) 
+       malloc(sizeof(struct SalvageQueueNode));
+    if (node == NULL) {
+       code = 1;
+       goto done;
+    }
+
+    memset(node, 0, sizeof(struct SalvageQueueNode));
+    node->type = SALVSYNC_VOLGROUP_PARENT;
+    node->state = SALVSYNC_STATE_UNKNOWN;
+
+ done:
+    return code;
+}
+
+static int
+LinkNode(struct SalvageQueueNode * parent,
+        struct SalvageQueueNode * clone)
+{
+    int code = 0;
+    int idx;
+
+    /* check for attaching a clone to a clone */
+    if (parent->type != SALVSYNC_VOLGROUP_PARENT) {
+       code = 1;
+       goto done;
+    }
+
+    /* check for pre-existing registration and openings */
+    for (idx = 0; idx < VOLMAXTYPES; idx++) {
+       if (parent->volgroup.children[idx] == clone) {
+           goto linked;
+       }
+       if (parent->volgroup.children[idx] == NULL) {
+           break;
+       }
+    }
+    if (idx == VOLMAXTYPES) {
+       code = 1;
+       goto done;
+    }
+
+    /* link parent and child */
+    parent->volgroup.children[idx] = clone;
+    clone->type = SALVSYNC_VOLGROUP_CLONE;
+    clone->volgroup.parent = parent;
+
+
+ linked:
+    switch (clone->state) {
+    case SALVSYNC_STATE_QUEUED:
+       DeleteFromSalvageQueue(clone);
+
+    case SALVSYNC_STATE_SALVAGING:
+       switch (parent->state) {
+       case SALVSYNC_STATE_UNKNOWN:
+       case SALVSYNC_STATE_ERROR:
+       case SALVSYNC_STATE_DONE:
+           parent->command.sop.prio = clone->command.sop.prio;
+           AddToSalvageQueue(parent);
+           break;
+
+       case SALVSYNC_STATE_QUEUED:
+           if (clone->command.sop.prio) {
+               parent->command.sop.prio += clone->command.sop.prio;
+               UpdateCommandPrio(parent);
+           }
+           break;
+
+       default:
+           break;
+       }
+       break;
+
+    default:
+       break;
+    }
+
+ done:
+    return code;
+}
+
+static void
+HandlePrio(struct SalvageQueueNode * clone, 
+          struct SalvageQueueNode * node,
+          afs_uint32 new_prio)
+{
+    afs_uint32 delta;
+
+    switch (node->state) {
+    case SALVSYNC_STATE_ERROR:
+    case SALVSYNC_STATE_DONE:
+    case SALVSYNC_STATE_UNKNOWN:
+       node->command.sop.prio = 0;
+       break;
+    }
+
+    if (new_prio < clone->command.sop.prio) {
+       /* strange. let's just set our delta to 1 */
+       delta = 1;
+    } else {
+       delta = new_prio - clone->command.sop.prio;
+    }
+
+    if (clone->type == SALVSYNC_VOLGROUP_CLONE) {
+       clone->command.sop.prio = new_prio;
+    }
+
+    node->command.sop.prio += delta;
+}
+
+static int
 AddToSalvageQueue(struct SalvageQueueNode * node)
 {
     afs_int32 id;
+    struct SalvageQueueNode * last = NULL;
 
     id = volutil_GetPartitionID(node->command.sop.partName);
     if (id < 0 || id > VOLMAXPARTS) {
@@ -803,12 +958,25 @@ AddToSalvageQueue(struct SalvageQueueNode * node)
        /* don't enqueue salvage requests for unmounted partitions */
        return 1;
     }
+    if (queue_IsOnQueue(node)) {
+       return 0;
+    }
+
+    if (queue_IsNotEmpty(&salvageQueue.part[id])) {
+       last = queue_Last(&salvageQueue.part[id], SalvageQueueNode);
+    }
     queue_Append(&salvageQueue.part[id], node);
     salvageQueue.len[id]++;
     salvageQueue.total_len++;
     salvageQueue.last_insert = id;
     node->partition_id = id;
     node->state = SALVSYNC_STATE_QUEUED;
+
+    /* reorder, if necessary */
+    if (last && last->command.sop.prio < node->command.sop.prio) {
+       UpdateCommandPrio(node);
+    }
+
     assert(pthread_cond_broadcast(&salvageQueue.cv) == 0);
     return 0;
 }
@@ -880,21 +1048,22 @@ LookupPendingCommandByPid(int pid)
 
 /* raise the priority of a previously scheduled salvage */
 static void
-RaiseCommandPrio(struct SalvageQueueNode * node, SALVSYNC_command_hdr * com)
+UpdateCommandPrio(struct SalvageQueueNode * node)
 {
     struct SalvageQueueNode *np, *nnp;
     afs_int32 id;
+    afs_uint32 prio;
 
     assert(queue_IsOnQueue(node));
 
-    node->command.sop.prio = com->prio;
+    prio = node->command.sop.prio;
     id = node->partition_id;
-    if (queue_First(&salvageQueue.part[id], SalvageQueueNode)->command.sop.prio < com->prio) {
+    if (queue_First(&salvageQueue.part[id], SalvageQueueNode)->command.sop.prio < prio) {
        queue_Remove(node);
        queue_Prepend(&salvageQueue.part[id], node);
     } else {
        for (queue_ScanBackwardsFrom(&salvageQueue.part[id], node, np, nnp, SalvageQueueNode)) {
-           if (np->command.sop.prio > com->prio)
+           if (np->command.sop.prio > prio)
                break;
        }
        if (queue_IsEnd(&salvageQueue.part[id], np)) {
@@ -927,7 +1096,6 @@ SALVSYNC_getWork(void)
       assert(pthread_cond_wait(&salvageQueue.cv, &vol_glock_mutex) == 0);
     }
 
-
     /* 
      * short circuit for simple case where only one partition has
      * scheduled salvages
@@ -1004,6 +1172,8 @@ static void
 SALVSYNC_doneWork_r(struct SalvageQueueNode * node, int result)
 {
     afs_int32 partid;
+    int idx;
+
     DeleteFromPendingQueue(node);
     partid = node->partition_id;
     if (partid >=0 && partid <= VOLMAXPARTS) {
@@ -1011,9 +1181,17 @@ SALVSYNC_doneWork_r(struct SalvageQueueNode * node, int result)
     }
     if (result == 0) {
        node->state = SALVSYNC_STATE_DONE;
-    } else {
+    } else if (result != SALSRV_EXIT_VOLGROUP_LINK) {
        node->state = SALVSYNC_STATE_ERROR;
     }
+
+    if (node->type == SALVSYNC_VOLGROUP_PARENT) {
+       for (idx = 0; idx < VOLMAXTYPES; idx++) {
+           if (node->volgroup.children[idx]) {
+               node->volgroup.children[idx]->state = node->state;
+           }
+       }
+    }
 }
 
 void 
index 6611df6..9c2f8b9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006, Sine Nomine Associates and others.
+ * Copyright 2006-2007, Sine Nomine Associates and others.
  * All Rights Reserved.
  * 
  * This software has been released under the terms of the IBM Public
 #ifndef _AFS_VOL_SALVSYNC_H
 #define _AFS_VOL_SALVSYNC_H
 
+#define SALSRV_EXIT_VOLGROUP_LINK 10
+
+
 #ifdef AFS_DEMAND_ATTACH_FS
 #include "daemon_com.h"
+#include "voldefs.h"
 
 
-#define SALVSYNC_PROTO_VERSION        1
+#define SALVSYNC_PROTO_VERSION_V1     1
+#define SALVSYNC_PROTO_VERSION_V2     2
+#define SALVSYNC_PROTO_VERSION        SALVSYNC_PROTO_VERSION_V2
 
 
-/* SALVSYNC command codes */
-#define SALVSYNC_NOP            SYNC_COM_CODE_DECL(0)   /* just return stats */
-#define SALVSYNC_SALVAGE       SYNC_COM_CODE_DECL(1)   /* schedule a salvage */
-#define SALVSYNC_CANCEL         SYNC_COM_CODE_DECL(2)   /* Cancel a salvage */
-#define SALVSYNC_RAISEPRIO      SYNC_COM_CODE_DECL(3)   /* move a salvage operation to
-                                                        * the head of the work queue */
-#define SALVSYNC_QUERY          SYNC_COM_CODE_DECL(4)   /* query the status of a salvage */
-#define SALVSYNC_CANCELALL      SYNC_COM_CODE_DECL(5)   /* cancel all pending salvages */
-
-/* SALVSYNC reason codes */
-#define SALVSYNC_WHATEVER      SYNC_REASON_CODE_DECL(0)  /* XXXX */
-#define SALVSYNC_ERROR         SYNC_REASON_CODE_DECL(1)  /* volume is in error state */
-#define SALVSYNC_OPERATOR      SYNC_REASON_CODE_DECL(2)  /* operator forced salvage */
-#define SALVSYNC_SHUTDOWN       SYNC_REASON_CODE_DECL(3)  /* cancel due to shutdown */
-#define SALVSYNC_NEEDED         SYNC_REASON_CODE_DECL(4)  /* needsSalvaged flag set */
+/** 
+ * SALVSYNC protocol command codes.
+ */
+typedef enum {
+    SALVSYNC_OP_NOP           = SYNC_COM_CODE_DECL(0),     /**< just return stats */
+    SALVSYNC_OP_SALVAGE       = SYNC_COM_CODE_DECL(1),     /**< schedule a salvage */
+    SALVSYNC_OP_CANCEL        = SYNC_COM_CODE_DECL(2),     /**< cancel a salvage */
+    SALVSYNC_OP_RAISEPRIO     = SYNC_COM_CODE_DECL(3),     /**< raise salvage priority */
+    SALVSYNC_OP_QUERY         = SYNC_COM_CODE_DECL(4),     /**< query status of a salvage */
+    SALVSYNC_OP_CANCELALL     = SYNC_COM_CODE_DECL(5),     /**< cancel all pending salvages */
+    SALVSYNC_OP_LINK          = SYNC_COM_CODE_DECL(6),     /**< link a clone to its parent */
+    SALVSYNC_OP_MAX_ID /* must be at end of enum */
+} SALVSYNC_op_code_t;
+
+#define SALVSYNC_NOP         SALVSYNC_OP_NOP
+#define SALVSYNC_SALVAGE     SALVSYNC_OP_SALVAGE
+#define SALVSYNC_CANCEL      SALVSYNC_OP_CANCEL
+#define SALVSYNC_RAISEPRIO   SALVSYNC_OP_RAISEPRIO
+#define SALVSYNC_QUERY       SALVSYNC_OP_QUERY
+#define SALVSYNC_CANCELALL   SALVSYNC_OP_CANCELALL
+#define SALVSYNC_LINK        SALVSYNC_OP_LINK
+
+/**
+ * SALVSYNC protocol reason codes.
+ */
+typedef enum {
+    SALVSYNC_REASON_WHATEVER   = SYNC_REASON_CODE_DECL(0), /**< XXX */
+    SALVSYNC_REASON_ERROR      = SYNC_REASON_CODE_DECL(1), /**< volume is in error state */
+    SALVSYNC_REASON_OPERATOR   = SYNC_REASON_CODE_DECL(2), /**< operator forced salvage */
+    SALVSYNC_REASON_SHUTDOWN   = SYNC_REASON_CODE_DECL(3), /**< cancel due to shutdown */
+    SALVSYNC_REASON_NEEDED     = SYNC_REASON_CODE_DECL(4), /**< needsSalvaged flag set */
+    SALVSYNC_REASON_MAX_ID /* must be at end of enum */
+} SALVSYNC_reason_code_t;
+
+#define SALVSYNC_WHATEVER    SALVSYNC_REASON_WHATEVER
+#define SALVSYNC_ERROR       SALVSYNC_REASON_ERROR
+#define SALVSYNC_OPERATOR    SALVSYNC_REASON_OPERATOR
+#define SALVSYNC_SHUTDOWN    SALVSYNC_REASON_SHUTDOWN
+#define SALVSYNC_NEEDED      SALVSYNC_REASON_NEEDED
 
 /* SALVSYNC response codes */
 
 /* SALVSYNC flags */
 #define SALVSYNC_FLAG_VOL_STATS_VALID SYNC_FLAG_CODE_DECL(0) /* volume stats in response are valid */
 
-/* SALVSYNC command state fields */
-#define SALVSYNC_STATE_UNKNOWN        0         /* unknown state */
-#define SALVSYNC_STATE_QUEUED         1         /* salvage request on queue */
-#define SALVSYNC_STATE_SALVAGING      2         /* salvage is happening now */
-#define SALVSYNC_STATE_ERROR          3         /* salvage ended in an error */
-#define SALVSYNC_STATE_DONE           4         /* last salvage ended successfully */
+/** 
+ * SALVSYNC command state.
+ */
+typedef enum {
+    SALVSYNC_STATE_UNKNOWN = 0,       /**< unknown state */
+    SALVSYNC_STATE_QUEUED  = 1,       /**< salvage request is queued */
+    SALVSYNC_STATE_SALVAGING = 2,     /**< salvage is happening now */
+    SALVSYNC_STATE_ERROR = 3,         /**< salvage ended in an error */
+    SALVSYNC_STATE_DONE = 4           /**< last salvage ended successfully */
+} SALVSYNC_command_state_t;
 
 
+/**
+ * on-wire salvsync protocol payload.
+ */
 typedef struct SALVSYNC_command_hdr {
-    afs_uint32 prio;
-    afs_uint32 volume;
-    char partName[16];         /* partition name, e.g. /vicepa */
+    afs_uint32 hdr_version;     /**< salvsync protocol header version */
+    afs_uint32 prio;            /**< salvage priority */
+    afs_uint32 volume;          /**< volume on which to operate */
+    afs_uint32 parent;          /**< parent volume (for vol group linking command) */
+    char partName[16];         /**< partition name, e.g. /vicepa */
+    afs_uint32 reserved[6];
 } SALVSYNC_command_hdr;
 
 typedef struct SALVSYNC_response_hdr {
@@ -61,6 +101,7 @@ typedef struct SALVSYNC_response_hdr {
     afs_int32 prio;
     afs_int32 sq_len;
     afs_int32 pq_len;
+    afs_uint32 reserved[4];
 } SALVSYNC_response_hdr;
 
 typedef struct SALVSYNC_command {
@@ -80,10 +121,20 @@ typedef struct SALVSYNC_command_info {
     SALVSYNC_command_hdr sop;
 } SALVSYNC_command_info;
 
+typedef enum {
+    SALVSYNC_VOLGROUP_PARENT,
+    SALVSYNC_VOLGROUP_CLONE
+} SalvageQueueNodeType_t;
+
 struct SalvageQueueNode {
     struct rx_queue q;
     struct rx_queue hash_chain;
-    afs_uint32 state;
+    SalvageQueueNodeType_t type;
+    union {
+       struct SalvageQueueNode * parent;
+       struct SalvageQueueNode * children[VOLMAXTYPES];
+    } volgroup;
+    SALVSYNC_command_state_t state;
     struct SALVSYNC_command_info command;
     afs_int32 partition_id;
     int pid;
@@ -99,6 +150,8 @@ extern int SALVSYNC_clientReconnect(void);
 extern afs_int32 SALVSYNC_askSalv(SYNC_command * com, SYNC_response * res);
 extern afs_int32 SALVSYNC_SalvageVolume(VolumeId volume, char *partName, int com, int reason,
                                        afs_uint32 prio, SYNC_response * res);
+extern afs_int32 SALVSYNC_LinkVolume(VolumeId parent, VolumeId clone,
+                                    char * partName, SYNC_response * res_in);
 
 /* salvage server interfaces */
 extern void SALVSYNC_salvInit(void);
index 6736133..56eb2a8 100644 (file)
@@ -235,11 +235,18 @@ int ShowMounts = 0;               /* -showmounts flag */
 int orphans = ORPH_IGNORE;     /* -orphans option */
 int Showmode = 0;
 
+
 #ifndef AFS_NT40_ENV
 int useSyslog = 0;             /* -syslog flag */
 int useSyslogFacility = LOG_DAEMON;    /* -syslogfacility option */
 #endif
 
+#ifdef AFS_NT40_ENV
+int canfork = 0;
+#else
+int canfork = 1;
+#endif
+
 #define        MAXPARALLEL     32
 
 int OKToZap;                   /* -o flag */
@@ -1258,9 +1265,23 @@ GetVolumeSummary(VolumeId singleVolumeNumber)
                DiskToVolumeHeader(&vsp->header, &diskHeader);
                if (singleVolumeNumber && vsp->header.id == singleVolumeNumber
                    && vsp->header.parent != singleVolumeNumber) {
-                   Log("%u is a read-only volume; not salvaged\n",
-                       singleVolumeNumber);
-                   Exit(1);
+                   if (programType == salvageServer) {
+#ifdef SALVSYNC_BUILD_CLIENT
+                       Log("fileserver requested salvage of clone %u; scheduling salvage of volume group %u...\n",
+                           vsp->header.id, vsp->header.parent);
+                       if (SALVSYNC_LinkVolume(vsp->header.parent,
+                                               vsp->header.id,
+                                               fileSysPartition->name,
+                                               NULL) != SYNC_OK) {
+                           Log("schedule request failed\n");
+                       }
+#endif
+                       Exit(SALSRV_EXIT_VOLGROUP_LINK);
+                   } else {
+                       Log("%u is a read-only volume; not salvaged\n",
+                           singleVolumeNumber);
+                       Exit(1);
+                   }
                }
                if (!singleVolumeNumber
                    || (vsp->header.id == singleVolumeNumber
@@ -3287,7 +3308,18 @@ Fork(void)
 #else
     f = fork();
     assert(f >= 0);
+#ifdef AFS_DEMAND_ATTACH_FS
+    if ((f == 0) && (programType == salvageServer)) {
+       /* we are a salvageserver child */
+#ifdef FSSYNC_BUILD_CLIENT
+       VChildProcReconnectFS_r();
+#endif
+#ifdef SALVSYNC_BUILD_CLIENT
+       VReconnectSALV_r();
 #endif
+    }
+#endif /* AFS_DEMAND_ATTACH_FS */
+#endif /* !AFS_NT40_ENV */
     return f;
 }
 
@@ -3297,6 +3329,18 @@ Exit(code)
 {
     if (ShowLog)
        showlog();
+
+#ifdef AFS_DEMAND_ATTACH_FS
+    if (programType == salvageServer) {
+#ifdef SALVSYNC_BUILD_CLIENT
+       VDisconnectSALV();
+#endif
+#ifdef FSSYNC_BUILD_CLIENT
+       VDisconnectFS();
+#endif
+    }
+#endif /* AFS_DEMAND_ATTACH_FS */
+
 #ifdef AFS_NT40_ENV
     if (main_thread != pthread_self())
        pthread_exit((void *)code);
index 7c89220..da9fbec 100644 (file)
@@ -211,11 +211,10 @@ typedef struct {
     struct InodeSummary *svgp_inodeSummaryp;
     int svgp_count;
 } SVGParms_t;
-#define canfork 0
-#else /* AFS_NT40_ENV */
-#define canfork 1
 #endif /* AFS_NT40_ENV */
 
+extern int canfork;
+
 
 /* prototypes */
 extern void Exit(int code);
index b546be2..e83bc90 100644 (file)
@@ -25,6 +25,8 @@
 #define ROVOL                  1
 #define BACKVOL                        2
 
+#define VOLMAXTYPES             3   /* _current_ max number of types */
+
 /* maximum numbe of Vice partitions */
 #define        VOLMAXPARTS     255
 
index 938a836..4da49fe 100644 (file)
@@ -3731,8 +3731,6 @@ VConnectSALV(void)
 int
 VConnectSALV_r(void)
 {
-    assert((programType != salvageServer) &&
-          (programType != volumeUtility));
     return SALVSYNC_clientInit();
 }
 
@@ -3749,8 +3747,6 @@ VDisconnectSALV(void)
 int
 VDisconnectSALV_r(void)
 { 
-    assert((programType != salvageServer) &&
-          (programType != volumeUtility));
     return SALVSYNC_clientFinis();
 }
 
@@ -3767,8 +3763,6 @@ VReconnectSALV(void)
 int
 VReconnectSALV_r(void)
 {
-    assert((programType != salvageServer) &&
-          (programType != volumeUtility));
     return SALVSYNC_clientReconnect();
 }
 #endif /* SALVSYNC_BUILD_CLIENT */
@@ -3824,7 +3818,7 @@ VDisconnectFS(void)
     VOL_UNLOCK;
 }
 
-static int
+int
 VChildProcReconnectFS_r(void)
 {
     return FSYNC_clientChildProcReconnect();