volser: take RO volume offline during convertROtoRW
[openafs.git] / src / volser / volprocs.c
index 2e483f3..90c7778 100644 (file)
@@ -60,6 +60,8 @@
 extern int DoLogging;
 extern struct afsconf_dir *tdir;
 extern int DoPreserveVolumeStats;
+extern int restrictedQueryLevel;
+extern enum vol_s2s_crypt doCrypt;
 
 extern void LogError(afs_int32 errcode);
 
@@ -94,8 +96,7 @@ static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
                            struct destServer *destination, afs_int32,
                            struct restoreCookie *cookie);
 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
-static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
-                           struct restoreCookie *);
+static afs_int32 VolRestore(struct rx_call *, afs_int32, struct restoreCookie *);
 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
@@ -157,44 +158,6 @@ VPFullUnlock(void)
     return code;
 }
 
-/* get partition id from a name */
-afs_int32
-PartitionID(char *aname)
-{
-    char tc;
-    int code = 0;
-    char ascii[3];
-
-    tc = *aname;
-    if (tc == 0)
-       return -1;              /* unknown */
-
-    /* otherwise check for vicepa or /vicepa, or just plain "a" */
-    ascii[2] = 0;
-    if (!strncmp(aname, "/vicep", 6)) {
-       strncpy(ascii, aname + 6, 2);
-    } else
-       return -1;              /* bad partition name */
-    /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
-     * from 0.  Do the appropriate conversion */
-    if (ascii[1] == 0) {
-       /* one char name, 0..25 */
-       if (ascii[0] < 'a' || ascii[0] > 'z')
-           return -1;          /* wrongo */
-       return ascii[0] - 'a';
-    } else {
-       /* two char name, 26 .. <whatever> */
-       if (ascii[0] < 'a' || ascii[0] > 'z')
-           return -1;          /* wrongo */
-       if (ascii[1] < 'a' || ascii[1] > 'z')
-           return -1;          /* just as bad */
-       code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
-       if (code > VOLMAXPARTS)
-           return -1;
-       return code;
-    }
-}
-
 static int
 ConvertVolume(VolumeId avol, char *aname, afs_int32 asize)
 {
@@ -418,6 +381,7 @@ SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
     afs_int32 code;
     struct diskPartition64 *dp = malloc(sizeof(struct diskPartition64));
 
+    memset(partition, 0, sizeof(*partition));
     code = VolPartitionInfo(acid, pname, dp);
     if (!code) {
        strncpy(partition->name, dp->name, 32);
@@ -437,17 +401,21 @@ SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
 {
     afs_int32 code;
 
+    memset(partition, 0, sizeof(*partition));
     code = VolPartitionInfo(acid, pname, partition);
     osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
     return code;
 }
 
-afs_int32
+static afs_int32
 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
                 *partition)
 {
     struct DiskPartition64 *dp;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     VResetDiskUsage();
     dp = VGetPartition(pname, 0);
     if (dp) {
@@ -790,7 +758,8 @@ VolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
            VCreateVolume(&error, originalvp->partition->name, newId,
                          V_parentId(originalvp));
        if (error) {
-           Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
+           Log("1 Volser: Clone: Couldn't create new volume %" AFS_VOLID_FMT " for parent %" AFS_VOLID_FMT "; clone aborted\n",
+               afs_printable_VolumeId_lu(newId), afs_printable_VolumeId_lu(V_parentId(originalvp)));
            newvp = (Volume *) 0;
            goto fail;
        }
@@ -809,10 +778,8 @@ VolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
        goto fail;
     }
     if (newType == readonlyVolume) {
-       AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
        V_type(newvp) = readonlyVolume;
     } else if (newType == backupVolume) {
-       AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
        V_type(newvp) = backupVolume;
        V_backupId(originalvp) = newId;
     }
@@ -844,6 +811,10 @@ VolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
 #ifdef AFS_DEMAND_ATTACH_FS
     salv_vp = NULL;
 #endif
+
+    /* Clients could have callbacks to the clone ID */
+    FSYNC_VolOp(newId, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
+
     if (TRELE(tt)) {
        tt = (struct volser_trans *)0;
        error = VOLSERTRELE_ERROR;
@@ -1123,6 +1094,9 @@ static afs_int32
 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
                    afs_int32 *apart)
 {
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     Log("1 Volser: GetNthVolume: Not yet implemented\n");
     return VOLSERNO_OP;
 }
@@ -1145,6 +1119,9 @@ VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
 {
     struct volser_trans *tt;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     tt = FindTrans(atid);
     if (!tt)
        return ENOENT;
@@ -1248,6 +1225,35 @@ SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
     return code;
 }
 
+static_inline afs_int32
+MakeClient(struct rx_call *acid, struct rx_securityClass **securityObject,
+          afs_int32 *securityIndex)
+{
+    rxkad_level enc_level = rxkad_clear;
+    int docrypt;
+    int code;
+
+    switch (doCrypt) {
+    case VS2SC_ALWAYS:
+       docrypt = 1;
+       break;
+    case VS2SC_INHERIT:
+       rxkad_GetServerInfo(rx_ConnectionOf(acid), &enc_level, 0, 0, 0, 0, 0);
+       docrypt = (enc_level == rxkad_crypt ? 1 : 0);
+       break;
+    case VS2SC_NEVER:
+       docrypt = 0;
+       break;
+    default:
+       opr_Assert(0 && "doCrypt corrupt?");
+    }
+    if (docrypt)
+       code = afsconf_ClientAuthSecure(tdir, securityObject, securityIndex);
+    else
+       code = afsconf_ClientAuth(tdir, securityObject, securityIndex);
+    return code;
+}
+
 static afs_int32
 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
               struct destServer *destination, afs_int32 destTrans,
@@ -1278,7 +1284,7 @@ VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
     TSetRxCall(tt, NULL, "Forward");
 
     /* get auth info for the this connection (uses afs from ticket file) */
-    code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
+    code = MakeClient(acid, &securityObject, &securityIndex);
     if (code) {
        TRELE(tt);
        return code;
@@ -1289,6 +1295,9 @@ VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
        rx_NewConnection(htonl(destination->destHost),
                         htons(destination->destPort), VOLSERVICE_ID,
                         securityObject, securityIndex);
+
+    RXS_Close(securityObject); /* will be freed after connection destroyed */
+
     if (!tcon) {
         TClearRxCall(tt);
        TRELE(tt);
@@ -1390,7 +1399,7 @@ SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
     }
 
     /* get auth info for this connection (uses afs from ticket file) */
-    code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
+    code = MakeClient(acid, &securityObject, &securityIndex);
     if (code) {
        goto fail;              /* in order to audit each failure */
     }
@@ -1421,6 +1430,9 @@ SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
        }
     }
 
+    /* Security object will be freed when all connections destroyed */
+    RXS_Close(securityObject);
+
     /* these next calls implictly call rx_Write when writing out data */
     code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
 
@@ -1521,14 +1533,13 @@ SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
 {
     afs_int32 code;
 
-    code = VolRestore(acid, atrans, aflags, cookie);
+    code = VolRestore(acid, atrans, cookie);
     osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
     return code;
 }
 
 static afs_int32
-VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
-          struct restoreCookie *cookie)
+VolRestore(struct rx_call *acid, afs_int32 atrans, struct restoreCookie *cookie)
 {
     struct volser_trans *tt;
     afs_int32 code, tcode;
@@ -1553,7 +1564,7 @@ VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
 
     DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
 
-    code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie);      /* last is incrementalp */
+    code = RestoreVolume(acid, tt->volume, cookie);
     FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
     TClearRxCall(tt);
     tcode = TRELE(tt);
@@ -1650,6 +1661,8 @@ VolGetStatus(struct rx_call *acid, afs_int32 atrans,
     struct VolumeDiskData *td;
     struct volser_trans *tt;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
 
     tt = FindTrans(atrans);
     if (!tt)
@@ -1771,6 +1784,9 @@ VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
     struct volser_trans *tt;
     int len;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     /* We need to at least fill it in */
     *aname = malloc(1);
     if (!*aname)
@@ -1835,6 +1851,9 @@ VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
     char namehead[9];
     int i;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     strcpy(namehead, "/vicep");        /*7 including null terminator */
 
     /* Just return attached partitions. */
@@ -1867,6 +1886,9 @@ XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
     struct DiskPartition64 *dp;
     int i, j = 0;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     strcpy(namehead, "/vicep");        /*7 including null terminator */
 
     /* Only report attached partitions */
@@ -2254,6 +2276,7 @@ GetVolInfo(afs_uint32 partId,
        case VOL_INFO_LIST_SINGLE:
            Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) will be destroyed on next salvage\n",
                afs_printable_VolumeId_lu(volumeId), pname, volname);
+           goto drop;
 
        default:
            goto drop;
@@ -2342,6 +2365,9 @@ VolListOneVolume(struct rx_call *acid, afs_int32 partid,
     int found = 0;
     volint_info_handle_t handle;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
     if (!volumeInfo->volEntries_val)
        return ENOMEM;
@@ -2432,6 +2458,9 @@ VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
     int found = 0;             /*Did we find the volume we need? */
     volint_info_handle_t handle;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     /*
      * Set up our pointers for action, marking our structure to hold exactly
      * one entry.  Also, assume we'll fail in our quest.
@@ -2530,6 +2559,9 @@ VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
     int code;
     volint_info_handle_t handle;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
     if (!volumeInfo->volEntries_val)
        return ENOMEM;
@@ -2640,6 +2672,9 @@ VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
     int code;
     volint_info_handle_t handle;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     /*
      * Allocate a large array of extended volume info structures, then
      * set it up for action.
@@ -2754,8 +2789,12 @@ VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
 {
     transDebugInfo *pntr;
     afs_int32 allocSize = 50;
+    afs_int32 code = 0;
     struct volser_trans *tt, *nt, *allTrans;
 
+    if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
+        return VOLSERBAD_ACCESS;
+
     transInfo->transDebugEntries_val =
        malloc(allocSize * sizeof(transDebugInfo));
     if (!transInfo->transDebugEntries_val)
@@ -2769,6 +2808,7 @@ VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
        goto done;              /*no active transactions */
     for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
        nt = tt->next;
+       memset(pntr, 0, sizeof(*pntr));
         VTRANS_OBJ_LOCK(tt);
        pntr->tid = tt->tid;
        pntr->time = tt->time;
@@ -2783,12 +2823,8 @@ VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
        pntr->callValid = 0;
        if (tt->rxCallPtr) {    /*record call related info */
            pntr->callValid = 1;
-#if 0
-           pntr->readNext = tt->rxCallPtr->rnext;
-           pntr->transmitNext = tt->rxCallPtr->tnext;
-           pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
-           pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
-#endif
+           rx_GetCallStatus(tt->rxCallPtr, &(pntr->readNext), &(pntr->transmitNext),
+                               &(pntr->lastSendTime), &(pntr->lastReceiveTime));
        }
         VTRANS_OBJ_UNLOCK(tt);
        pntr++;
@@ -2797,6 +2833,10 @@ VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
            allocSize = (allocSize * 3) / 2;
            pntr = realloc(transInfo->transDebugEntries_val,
                           allocSize * sizeof(transDebugInfo));
+           if (pntr == NULL) {
+               code = ENOMEM;
+               goto done;
+           }
            transInfo->transDebugEntries_val = pntr;
            pntr =
                transInfo->transDebugEntries_val +
@@ -2808,7 +2848,7 @@ VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
 done:
     VTRANS_UNLOCK;
 
-    return 0;
+    return code;
 }
 
 afs_int32
@@ -2959,17 +2999,40 @@ SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
 #endif
             ttc = NewTrans(volumeId, partId);
             if (!ttc) {
-               return VOLSERVOLBUSY;
+               ret = VOLSERVOLBUSY;
+               goto done;
             }
+           ret = FSYNC_VolOp(volumeId, pname, FSYNC_VOL_NEEDVOLUME, V_VOLUPD,
+                             NULL);
+           if (ret != SYNC_OK) {
+               Log("SAFSVolConvertROtoRWvolume: Error %ld trying to check out "
+                   "vol %lu part %s.\n", afs_printable_int32_ld(ret),
+                   afs_printable_uint32_lu(volumeId), pname);
+               ret = VOLSERFAILEDOP;
+               goto done;
+           }
 #ifdef AFS_NAMEI_ENV
            ret = namei_ConvertROtoRWvolume(pname, volumeId);
 #else
            ret = inode_ConvertROtoRWvolume(pname, volumeId);
 #endif
+           if (ret != 0) {
+               Log("SAFSVolConvertROtoRWvolume: Error %ld trying to convert "
+                   "RO vol %lu to RW. The volume may be in an inconsistent or "
+                   "partially converted state; if the volume seems unusable, "
+                   "you can try salvaging it or restoring from another RO "
+                   "copy.\n", afs_printable_int32_ld(ret),
+                   afs_printable_uint32_lu(volumeId));
+               /*
+                * the volume may or may not be usable at this point; let the
+                * fileserver try to attach and decide.
+                */
+               FSYNC_VolOp(volumeId, pname, FSYNC_VOL_ON, 0, NULL);
+           }
            break;
        }
     }
-
+  done:
     if (ttc)
         DeleteTrans(ttc, 1);
 
@@ -3006,7 +3069,7 @@ SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
 }
 
 afs_int32
-SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
+SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 ovid, afs_uint32 onew,
                   afs_uint32 where, afs_int32 verbose)
 {
 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
@@ -3015,6 +3078,8 @@ SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
     struct volser_trans *tt = 0, *tt2 = 0;
     char caller[MAXKTCNAMELEN];
     char line[128];
+    VolumeId new = onew;
+    VolumeId vid = ovid;
 
     if (!afsconf_SuperUser(tdir, acall, caller))
         return EPERM;
@@ -3035,12 +3100,14 @@ SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
     if (V_device(vol) != V_device(newvol)
        || V_uniquifier(newvol) != 2) {
         if (V_device(vol) != V_device(newvol)) {
-            sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
-                   vid, new);
+            sprintf(line, "Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are not in the same partition, aborted.\n",
+                   afs_printable_VolumeId_lu(vid),
+                   afs_printable_VolumeId_lu(new));
             rx_Write(acall, line, strlen(line));
         }
         if (V_uniquifier(newvol) != 2) {
-            sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
+            sprintf(line, "Volume %" AFS_VOLID_FMT " is not freshly created, aborted.\n",
+                   afs_printable_VolumeId_lu(new));
             rx_Write(acall, line, strlen(line));
         }
         line[0] = 0;
@@ -3051,7 +3118,8 @@ SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
     }
     tt = NewTrans(vid, V_device(vol));
     if (!tt) {
-        sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
+        sprintf(line, "Couldn't create transaction for %" AFS_VOLID_FMT ", aborted.\n",
+               afs_printable_VolumeId_lu(vid));
         rx_Write(acall, line, strlen(line));
         line[0] = 0;
         rx_Write(acall, line, 1);
@@ -3067,7 +3135,8 @@ SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
 
     tt2 = NewTrans(new, V_device(newvol));
     if (!tt2) {
-        sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
+        sprintf(line, "Couldn't create transaction for %" AFS_VOLID_FMT ", aborted.\n",
+               afs_printable_VolumeId_lu(new));
         rx_Write(acall, line, strlen(line));
         line[0] = 0;
         rx_Write(acall, line, 1);