add AFS_DEMAND_ATTACH_UTIL
[openafs.git] / src / vol / vol-salvage.c
index 44a3778..f747ff5 100644 (file)
@@ -274,7 +274,7 @@ struct SalvInfo {
                               *   header dealt with */
 
     int nVolumesInInodeFile; /**< Number of read-write volumes summarized */
-    int inodeFd;             /**< File descriptor for inode file */
+    FD_t inodeFd;             /**< File descriptor for inode file */
 
     struct VolumeSummary *volumeSummaryp; /**< Holds all the volumes in a part */
     int nVolumes;            /**< Number of volumes (read-write and read-only)
@@ -298,10 +298,11 @@ char *tmpdir = NULL;
 static int IsVnodeOrphaned(struct SalvInfo *salvinfo, VnodeId vnode);
 static int AskVolumeSummary(struct SalvInfo *salvinfo,
                             VolumeId singleVolumeNumber);
+static void MaybeAskOnline(struct SalvInfo *salvinfo, VolumeId volumeId);
 
-#ifdef AFS_DEMAND_ATTACH_FS
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
 static int LockVolume(struct SalvInfo *salvinfo, VolumeId volumeId);
-#endif /* AFS_DEMAND_ATTACH_FS */
+#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
 
 /* Uniquifier stored in the Inode */
 static Unique
@@ -397,7 +398,7 @@ IsPartitionMounted(char *part)
 /* Check if the given inode is the root of the filesystem. */
 #ifndef AFS_SGI_XFS_IOPS_ENV
 int
-IsRootInode(struct afs_stat *status)
+IsRootInode(struct afs_stat_st *status)
 {
     /*
      * The root inode is not a fixed value in XFS partitions. So we need to
@@ -708,7 +709,7 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
 {
     char *name, *tdir;
     char inodeListPath[256];
-    FILE *inodeFile = NULL;
+    FD_t inodeFile = INVALID_FD;
     static char tmpDevName[100];
     static char wpath[100];
     struct VolumeSummary *vsp, *esp;
@@ -722,21 +723,21 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
     memset(salvinfo, 0, sizeof(*salvinfo));
 
     tries++;
-    if (inodeFile) {
-       fclose(inodeFile);
-       inodeFile = NULL;
+    if (inodeFile != INVALID_FD) {
+       OS_CLOSE(inodeFile);
+       inodeFile = INVALID_FD;
     }
     if (tries > VOL_MAX_CHECKOUT_RETRIES) {
        Abort("Raced too many times with fileserver restarts while trying to "
              "checkout/lock volumes; Aborted\n");
     }
-#ifdef AFS_DEMAND_ATTACH_FS
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
     if (tries > 1) {
        /* unlock all previous volume locks, since we're about to lock them
         * again */
        VLockFileReinit(&partP->volLockFile);
     }
-#endif /* AFS_DEMAND_ATTACH_FS */
+#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
 
     salvinfo->fileSysPartition = partP;
     salvinfo->fileSysDevice = salvinfo->fileSysPartition->device;
@@ -755,11 +756,11 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
 #endif
 
     if (singleVolumeNumber) {
-#ifndef AFS_DEMAND_ATTACH_FS
+#if !(defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL))
        /* only non-DAFS locks the partition when salvaging a single volume;
         * DAFS will lock the individual volumes in the VG */
        VLockPartition(partP->name);
-#endif /* !AFS_DEMAND_ATTACH_FS */
+#endif /* !(AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL) */
 
        ForceSalvage = 1;
 
@@ -770,11 +771,11 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
 
        salvinfo->useFSYNC = 1;
        AskOffline(salvinfo, singleVolumeNumber);
-#ifdef AFS_DEMAND_ATTACH_FS
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
        if (LockVolume(salvinfo, singleVolumeNumber)) {
            goto retry;
        }
-#endif /* AFS_DEMAND_ATTACH_FS */
+#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
 
     } else {
        salvinfo->useFSYNC = 0;
@@ -823,8 +824,8 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
             getpid());
 #endif
 
-    inodeFile = fopen(inodeListPath, "w+b");
-    if (!inodeFile) {
+    inodeFile = OS_OPEN(inodeListPath, O_RDWR|O_TRUNC|O_CREAT, 0666);
+    if (inodeFile == INVALID_FD) {
        Abort("Error %d when creating inode description file %s; not salvaged\n", errno, inodeListPath);
     }
 #ifdef AFS_NT40_ENV
@@ -848,15 +849,28 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
     }
 
     if (GetInodeSummary(salvinfo, inodeFile, singleVolumeNumber) < 0) {
-       fclose(inodeFile);
+       OS_CLOSE(inodeFile);
+       if (singleVolumeNumber) {
+           /* the volume group -- let alone the volume -- does not exist,
+            * but we checked it out, so give it back to the fileserver */
+           AskDelete(salvinfo, singleVolumeNumber);
+       }
        return;
     }
-    salvinfo->inodeFd = fileno(inodeFile);
-    if (salvinfo->inodeFd == -1)
+    salvinfo->inodeFd = inodeFile;
+    if (salvinfo->inodeFd == INVALID_FD)
        Abort("Temporary file %s is missing...\n", inodeListPath);
-    afs_lseek(salvinfo->inodeFd, 0L, SEEK_SET);
+    OS_SEEK(salvinfo->inodeFd, 0L, SEEK_SET);
     if (ListInodeOption) {
        PrintInodeList(salvinfo);
+       if (singleVolumeNumber) {
+           /* We've checked out the volume from the fileserver, and we need
+            * to give it back. We don't know if the volume exists or not,
+            * so we don't know whether to AskOnline or not. Try to determine
+            * if the volume exists by trying to read the volume header, and
+            * AskOnline if it is readable. */
+           MaybeAskOnline(salvinfo, singleVolumeNumber);
+       }
        return;
     }
     /* enumerate volumes in the partition.
@@ -913,10 +927,10 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
 
     if (!Testing && singleVolumeNumber) {
        int foundSVN = 0;
-#ifdef AFS_DEMAND_ATTACH_FS
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
        /* unlock vol headers so the fs can attach them when we AskOnline */
        VLockFileReinit(&salvinfo->fileSysPartition->volLockFile);
-#endif /* AFS_DEMAND_ATTACH_FS */
+#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
 
        /* Step through the volumeSummary list and set all volumes on-line.
         * Most volumes were taken off-line in GetVolumeSummary.
@@ -936,9 +950,11 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
        }
 
        if (!foundSVN) {
-           /* singleVolumeNumber generally should always be in the constructed
-            * volumeSummary, but just in case it's not... */
-           AskOnline(salvinfo, singleVolumeNumber);
+           /* If singleVolumeNumber is not in our volumeSummary, it means that
+            * at least one other volume in the VG is on the partition, but the
+            * RW volume is not. We've already AskOffline'd it by now, though,
+            * so make sure we don't still have the volume checked out. */
+           AskDelete(salvinfo, singleVolumeNumber);
        }
 
        for (j = 0; j < salvinfo->nVolumes; j++) {
@@ -954,7 +970,7 @@ SalvageFileSys1(struct DiskPartition64 *partP, VolumeId singleVolumeNumber)
                salvinfo->fileSysPartition->name, (Testing ? " (READONLY mode)" : ""));
     }
 
-    fclose(inodeFile);         /* SalvageVolumeGroup was the last which needed it. */
+    OS_CLOSE(inodeFile);               /* SalvageVolumeGroup was the last which needed it. */
 }
 
 void
@@ -1130,15 +1146,14 @@ OnlyOneVolume(struct ViceInodeInfo *inodeinfo, afs_uint32 singleVolumeNumber, vo
  * be unlinked by the caller.
  */
 int
-GetInodeSummary(struct SalvInfo *salvinfo, FILE *inodeFile, VolumeId singleVolumeNumber)
+GetInodeSummary(struct SalvInfo *salvinfo, FD_t inodeFile, VolumeId singleVolumeNumber)
 {
-    struct afs_stat status;
     int forceSal, err;
     int code;
     struct ViceInodeInfo *ip, *ip_save;
     struct InodeSummary summary;
     char summaryFileName[50];
-    FILE *summaryFile;
+    FD_t summaryFile = INVALID_FD;
 #ifdef AFS_NT40_ENV
     char *dev = salvinfo->fileSysPath;
     char *wpath = salvinfo->fileSysPath;
@@ -1149,6 +1164,7 @@ GetInodeSummary(struct SalvInfo *salvinfo, FILE *inodeFile, VolumeId singleVolum
     char *part = salvinfo->fileSysPath;
     char *tdir;
     int i;
+    afs_sfsize_t st_size;
 
     /* This file used to come from vfsck; cobble it up ourselves now... */
     if ((err =
@@ -1165,9 +1181,10 @@ GetInodeSummary(struct SalvInfo *salvinfo, FILE *inodeFile, VolumeId singleVolum
        Log("***Forced salvage of all volumes on this partition***\n");
        ForceSalvage = 1;
     }
-    fseek(inodeFile, 0L, SEEK_SET);
-    salvinfo->inodeFd = fileno(inodeFile);
-    if (salvinfo->inodeFd == -1 || afs_fstat(salvinfo->inodeFd, &status) == -1) {
+    OS_SEEK(inodeFile, 0L, SEEK_SET);
+    salvinfo->inodeFd = inodeFile;
+    if (salvinfo->inodeFd == INVALID_FD ||
+        (st_size = OS_SIZE(salvinfo->inodeFd)) == -1) {
        Abort("No inode description file for \"%s\"; not salvaged\n", dev);
     }
     tdir = (tmpdir ? tmpdir : part);
@@ -1178,8 +1195,8 @@ GetInodeSummary(struct SalvInfo *salvinfo, FILE *inodeFile, VolumeId singleVolum
     (void)afs_snprintf(summaryFileName, sizeof summaryFileName,
                       "%s" OS_DIRSEP "salvage.temp.%d", tdir, getpid());
 #endif
-    summaryFile = afs_fopen(summaryFileName, "a+");
-    if (summaryFile == NULL) {
+    summaryFile = OS_OPEN(summaryFileName, O_RDWR|O_APPEND|O_CREAT, 0666);
+    if (summaryFile == INVALID_FD) {
        Abort("Unable to create inode summary file\n");
     }
 
@@ -1201,11 +1218,9 @@ GetInodeSummary(struct SalvInfo *salvinfo, FILE *inodeFile, VolumeId singleVolum
     }
 
     if (!canfork || debug || Fork() == 0) {
-       int nInodes;
-       unsigned long st_size=(unsigned long) status.st_size;
-       nInodes = st_size / sizeof(struct ViceInodeInfo);
+       int nInodes = st_size / sizeof(struct ViceInodeInfo);
        if (nInodes == 0) {
-           fclose(summaryFile);
+           OS_CLOSE(summaryFile);
            if (!singleVolumeNumber)    /* Remove the FORCESALVAGE file */
                RemoveTheForce(salvinfo->fileSysPath);
            else {
@@ -1225,28 +1240,28 @@ GetInodeSummary(struct SalvInfo *salvinfo, FILE *inodeFile, VolumeId singleVolum
        }
        ip = (struct ViceInodeInfo *)malloc(nInodes*sizeof(struct ViceInodeInfo));
        if (ip == NULL) {
-           fclose(summaryFile);
+           OS_CLOSE(summaryFile);
            Abort
                ("Unable to allocate enough space to read inode table; %s not salvaged\n",
                 dev);
        }
-       if (read(salvinfo->inodeFd, ip, st_size) != st_size) {
-           fclose(summaryFile);
+       if (OS_READ(salvinfo->inodeFd, ip, st_size) != st_size) {
+           OS_CLOSE(summaryFile);
            Abort("Unable to read inode table; %s not salvaged\n", dev);
        }
        qsort(ip, nInodes, sizeof(struct ViceInodeInfo), CompareInodes);
-       if (afs_lseek(salvinfo->inodeFd, 0, SEEK_SET) == -1
-           || write(salvinfo->inodeFd, ip, st_size) != st_size) {
-           fclose(summaryFile);
+       if (OS_SEEK(salvinfo->inodeFd, 0, SEEK_SET) == -1
+           || OS_WRITE(salvinfo->inodeFd, ip, st_size) != st_size) {
+           OS_CLOSE(summaryFile);
            Abort("Unable to rewrite inode table; %s not salvaged\n", dev);
        }
        summary.index = 0;
        ip_save = ip;
        while (nInodes) {
            CountVolumeInodes(ip, nInodes, &summary);
-           if (fwrite(&summary, sizeof(summary), 1, summaryFile) != 1) {
+           if (OS_WRITE(summaryFile, &summary, sizeof(summary)) != sizeof(summary)) {
                Log("Difficulty writing summary file (errno = %d); %s not salvaged\n", errno, dev);
-               fclose(summaryFile);
+               OS_CLOSE(summaryFile);
                return -1;
            }
            summary.index += (summary.nInodes);
@@ -1256,9 +1271,9 @@ GetInodeSummary(struct SalvInfo *salvinfo, FILE *inodeFile, VolumeId singleVolum
        free(ip_save);
        ip = ip_save = NULL;
        /* Following fflush is not fclose, because if it was debug mode would not work */
-       if (fflush(summaryFile) == EOF || fsync(fileno(summaryFile)) == -1) {
+       if (OS_SYNC(summaryFile) == -1) {
            Log("Unable to write summary file (errno = %d); %s not salvaged\n", errno, dev);
-           fclose(summaryFile);
+           OS_CLOSE(summaryFile);
            return -1;
        }
        if (canfork && !debug) {
@@ -1267,27 +1282,28 @@ GetInodeSummary(struct SalvInfo *salvinfo, FILE *inodeFile, VolumeId singleVolum
        }
     } else {
        if (Wait("Inode summary") == -1) {
-           fclose(summaryFile);
+           OS_CLOSE(summaryFile);
            Exit(1);            /* salvage of this partition aborted */
        }
     }
-    osi_Assert(afs_fstat(fileno(summaryFile), &status) != -1);
-    if (status.st_size != 0) {
+
+    st_size = OS_SIZE(summaryFile);
+    osi_Assert(st_size >= 0);
+    if (st_size != 0) {
        int ret;
-       unsigned long st_status=(unsigned long)status.st_size;
-       salvinfo->inodeSummary = (struct InodeSummary *)malloc(st_status);
+       salvinfo->inodeSummary = (struct InodeSummary *)malloc(st_size);
        osi_Assert(salvinfo->inodeSummary != NULL);
        /* For GNU we need to do lseek to get the file pointer moved. */
-       osi_Assert(afs_lseek(fileno(summaryFile), 0, SEEK_SET) == 0);
-       ret = read(fileno(summaryFile), salvinfo->inodeSummary, st_status);
-       osi_Assert(ret == st_status);
+       osi_Assert(OS_SEEK(summaryFile, 0, SEEK_SET) == 0);
+       ret = OS_READ(summaryFile, salvinfo->inodeSummary, st_size);
+       osi_Assert(ret == st_size);
     }
-    salvinfo->nVolumesInInodeFile =(unsigned long)(status.st_size) / sizeof(struct InodeSummary);
+    salvinfo->nVolumesInInodeFile = st_size / sizeof(struct InodeSummary);
     for (i = 0; i < salvinfo->nVolumesInInodeFile; i++) {
        salvinfo->inodeSummary[i].volSummary = NULL;
     }
-    Log("%d nVolumesInInodeFile %lu \n",salvinfo->nVolumesInInodeFile,(unsigned long)(status.st_size));
-    fclose(summaryFile);
+    Log("%d nVolumesInInodeFile %lu \n",salvinfo->nVolumesInInodeFile,(unsigned long)st_size);
+    OS_CLOSE(summaryFile);
     return 0;
 }
 
@@ -1583,7 +1599,7 @@ RecordHeader(struct DiskPartition64 *dp, const char *name,
 
                AskOffline(salvinfo, summary.header.id);
 
-#ifdef AFS_DEMAND_ATTACH_FS
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
                if (!badname) {
                    /* don't lock the volume if the header is bad, since we're
                     * about to delete it anyway. */
@@ -1592,7 +1608,7 @@ RecordHeader(struct DiskPartition64 *dp, const char *name,
                        return -1;
                    }
                }
-#endif /* AFS_DEMAND_ATTACH_FS */
+#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
            }
        }
        if (badname) {
@@ -1891,10 +1907,10 @@ DoSalvageVolumeGroup(struct SalvInfo *salvinfo, struct InodeSummary *isp, int nV
     allInodes = inodes - isp->index;   /* this would the base of all the inodes
                                         * for the partition, if all the inodes
                                         * had been read into memory */
-    osi_Assert(afs_lseek
+    osi_Assert(OS_SEEK
           (salvinfo->inodeFd, isp->index * sizeof(struct ViceInodeInfo),
            SEEK_SET) != -1);
-    osi_Assert(read(salvinfo->inodeFd, inodes, size) == size);
+    osi_Assert(OS_READ(salvinfo->inodeFd, inodes, size) == size);
 
     /* Don't try to salvage a read write volume if there isn't one on this
      * partition */
@@ -4219,7 +4235,7 @@ MaybeZapVolume(struct SalvInfo *salvinfo, struct InodeSummary *isp,
     }
 }
 
-#ifdef AFS_DEMAND_ATTACH_FS
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
 /**
  * Locks a volume on disk for salvaging.
  *
@@ -4305,7 +4321,7 @@ LockVolume(struct SalvInfo *salvinfo, VolumeId volumeId)
 
     return 0;
 }
-#endif /* AFS_DEMAND_ATTACH_FS */
+#endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
 
 void
 AskOffline(struct SalvInfo *salvinfo, VolumeId volumeId)
@@ -4322,20 +4338,27 @@ AskOffline(struct SalvInfo *salvinfo, VolumeId volumeId)
        if (code == SYNC_OK) {
            break;
        } else if (code == SYNC_DENIED) {
-#ifdef DEMAND_ATTACH_ENABLE
-           Log("AskOffline:  file server denied offline request; a general salvage may be required.\n");
-#else
-           Log("AskOffline:  file server denied offline request; a general salvage is required.\n");
-#endif
+           if (AskDAFS())
+               Log("AskOffline:  file server denied offline request; a general salvage may be required.\n");
+           else
+               Log("AskOffline:  file server denied offline request; a general salvage is required.\n");
            Abort("Salvage aborted\n");
        } else if (code == SYNC_BAD_COMMAND) {
            Log("AskOffline:  fssync protocol mismatch (bad command word '%d'); salvage aborting.\n",
                FSYNC_VOL_OFF);
-#ifdef DEMAND_ATTACH_ENABLE
-           Log("AskOffline:  please make sure fileserver, volserver, salvageserver and salvager binaries are same version.\n");
+           if (AskDAFS()) {
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
+               Log("AskOffline:  please make sure dafileserver, davolserver, salvageserver and dasalvager binaries are same version.\n");
+#else
+               Log("AskOffline:  fileserver is DAFS but we are not.\n");
+#endif
+           } else {
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
+               Log("AskOffline:  fileserver is not DAFS but we are.\n");
 #else
-           Log("AskOffline:  please make sure fileserver, volserver and salvager binaries are same version.\n");
+               Log("AskOffline:  please make sure fileserver, volserver and salvager binaries are same version.\n");
 #endif
+           }
            Abort("Salvage aborted\n");
        } else if (i < 2) {
            /* try it again */
@@ -4350,6 +4373,63 @@ AskOffline(struct SalvInfo *salvinfo, VolumeId volumeId)
     }
 }
 
+/* don't want to pass around state; remember it here */
+static int isDAFS = -1;
+int
+AskDAFS(void)
+{
+    afs_int32 code, i, ret = 0;
+    SYNC_response res;
+
+    /* we don't care if we race. the answer shouldn't change */
+    if (isDAFS != -1)
+       return isDAFS;
+
+    memset(&res, 0, sizeof(res));
+
+    for (i = 0; i < 3; i++) {
+       code = FSYNC_VolOp(1, NULL,
+                          FSYNC_VOL_QUERY_VOP, FSYNC_SALVAGE, &res);
+
+       if (code == SYNC_OK) {
+           ret = 1;
+           break;
+       } else if (code == SYNC_DENIED) {
+           ret = 1;
+           break;
+       } else if (code == SYNC_BAD_COMMAND) {
+           ret = 0;
+           break;
+       } else if (code == SYNC_FAILED) {
+           if (res.hdr.reason == FSYNC_UNKNOWN_VOLID)
+               ret = 1;
+           else
+               ret = 0;
+       } else if (i < 2) {
+           /* try it again */
+           Log("AskDAFS:  request to query fileserver failed; trying again...\n");
+           FSYNC_clientFinis();
+           FSYNC_clientInit();
+       }
+    }
+
+    isDAFS = ret;
+    return ret;
+}
+
+static void
+MaybeAskOnline(struct SalvInfo *salvinfo, VolumeId volumeId)
+{
+    struct VolumeDiskHeader diskHdr;
+    int code;
+    code = VReadVolumeDiskHeader(volumeId, salvinfo->fileSysPartition, &diskHdr);
+    if (code) {
+       /* volume probably does not exist; no need to bring back online */
+       return;
+    }
+    AskOnline(salvinfo, volumeId);
+}
+
 void
 AskOnline(struct SalvInfo *salvinfo, VolumeId volumeId)
 {
@@ -4366,11 +4446,7 @@ AskOnline(struct SalvInfo *salvinfo, VolumeId volumeId)
        } else if (code == SYNC_BAD_COMMAND) {
            Log("AskOnline:  fssync protocol mismatch (bad command word '%d')\n",
                FSYNC_VOL_ON);
-#ifdef DEMAND_ATTACH_ENABLE
-           Log("AskOnline:  please make sure fileserver, volserver, salvageserver and salvager binaries are same version.\n");
-#else
-           Log("AskOnline:  please make sure fileserver, volserver and salvager binaries are same version.\n");
-#endif
+           Log("AskOnline:  please make sure file server binaries are same version.\n");
            break;
        } else if (i < 2) {
            /* try it again */
@@ -4385,10 +4461,12 @@ void
 AskDelete(struct SalvInfo *salvinfo, VolumeId volumeId)
 {
     afs_int32 code, i;
+    SYNC_response res;
 
     for (i = 0; i < 3; i++) {
+       memset(&res, 0, sizeof(res));
        code = FSYNC_VolOp(volumeId, salvinfo->fileSysPartition->name,
-                          FSYNC_VOL_DONE, FSYNC_SALVAGE, NULL);
+                          FSYNC_VOL_DONE, FSYNC_SALVAGE, &res);
 
        if (code == SYNC_OK) {
            break;
@@ -4397,11 +4475,24 @@ AskDelete(struct SalvInfo *salvinfo, VolumeId volumeId)
        } else if (code == SYNC_BAD_COMMAND) {
            Log("AskOnline:  fssync protocol mismatch (bad command word '%d')\n",
                FSYNC_VOL_DONE);
-#ifdef DEMAND_ATTACH_ENABLE
-           Log("AskOnline:  please make sure fileserver, volserver, salvageserver and salvager binaries are same version.\n");
+           if (AskDAFS()) {
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
+               Log("AskOnline:  please make sure dafileserver, davolserver, salvageserver and dasalvager binaries are same version.\n");
 #else
-           Log("AskOnline:  please make sure fileserver, volserver and salvager binaries are same version.\n");
+               Log("AskOnline:  fileserver is DAFS but we are not.\n");
 #endif
+           } else {
+#if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
+               Log("AskOnline:  fileserver is not DAFS but we are.\n");
+#else
+               Log("AskOnline:  please make sure fileserver, volserver and salvager binaries are same version.\n");
+#endif
+           }
+           break;
+       } else if (code == SYNC_FAILED &&
+                    (res.hdr.reason == FSYNC_UNKNOWN_VOLID ||
+                     res.hdr.reason == FSYNC_WRONG_PART)) {
+           /* volume is already effectively 'deleted' */
            break;
        } else if (i < 2) {
            /* try it again */
@@ -4446,15 +4537,16 @@ PrintInodeList(struct SalvInfo *salvinfo)
 {
     struct ViceInodeInfo *ip;
     struct ViceInodeInfo *buf;
-    struct afs_stat status;
     int nInodes;
     afs_ino_str_t stmp;
+    afs_sfsize_t st_size;
 
-    osi_Assert(afs_fstat(salvinfo->inodeFd, &status) == 0);
-    buf = (struct ViceInodeInfo *)malloc(status.st_size);
+    st_size = OS_SIZE(salvinfo->inodeFd);
+    osi_Assert(st_size >= 0);
+    buf = (struct ViceInodeInfo *)malloc(st_size);
     osi_Assert(buf != NULL);
-    nInodes = status.st_size / sizeof(struct ViceInodeInfo);
-    osi_Assert(read(salvinfo->inodeFd, buf, status.st_size) == status.st_size);
+    nInodes = st_size / sizeof(struct ViceInodeInfo);
+    osi_Assert(OS_READ(salvinfo->inodeFd, buf, st_size) == st_size);
     for (ip = buf; nInodes--; ip++) {
        Log("Inode:%s, linkCount=%d, size=%#llx, p=(%u,%u,%u,%u)\n",
            PrintInode(stmp, ip->inodeNumber), ip->linkCount,
@@ -4709,7 +4801,7 @@ void
 RemoveTheForce(char *path)
 {
     char target[1024];
-    struct afs_stat force; /* so we can use afs_stat to find it */
+    struct afs_stat_st force; /* so we can use afs_stat to find it */
     strcpy(target,path);
     strcat(target,"/FORCESALVAGE");
     if (!Testing && ForceSalvage) {
@@ -4724,7 +4816,7 @@ RemoveTheForce(char *path)
 int
 UseTheForceLuke(char *path)
 {
-    struct afs_stat force;
+    struct afs_stat_st force;
     char target[1024];
     strcpy(target,path);
     strcat(target,"/FORCESALVAGE");