]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
Windows: Redirector must query volume size when asked
authorJeffrey Altman <jaltman@your-file-system.com>
Thu, 5 Apr 2012 18:40:18 +0000 (14:40 -0400)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Thu, 5 Apr 2012 23:43:13 +0000 (16:43 -0700)
The volume size and free space cannot be obtained at volume
initialization and then re-used for all FileFsSizeInformation
and FileFsFullSizeInformation queries.  Doing so prevents Windows
from being able to see changes in the available free space.

The maximum size of the volume is not the size of the partition
and the available space on the partition unless there is no quota
applied to the volume.  If there is a quota, then the free space
is the smaller of the available quota and the available partition
space.

Add a new ioctl request to permit the redirector to query the
current Volume Size Information details.

Change-Id: I3414f314d7780fd12489e0d278b71bcadc1a72e6
Reviewed-on: http://gerrit.openafs.org/7052
Reviewed-by: Jeffrey Altman <jaltman@secure-endpoints.com>
Tested-by: Jeffrey Altman <jaltman@secure-endpoints.com>
src/WINNT/afsrdr/common/AFSUserDefines.h
src/WINNT/afsrdr/common/AFSUserStructs.h
src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp
src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp
src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h
src/WINNT/afsrdr/user/RDRFunction.c
src/WINNT/afsrdr/user/RDRInit.cpp
src/WINNT/afsrdr/user/RDRPrototypes.h

index 6c93461edfcfa4a61bfbab710b293cf023fe374e..b3037b1a63644fa4e32fb6ffb6bbc876f56da266 100644 (file)
@@ -90,6 +90,7 @@
 #define AFS_REQUEST_TYPE_CREATE_MOUNTPOINT       0x0000001F
 #define AFS_REQUEST_TYPE_CREATE_SYMLINK          0x00000020
 #define AFS_REQUEST_TYPE_RELEASE_FILE_ACCESS     0x00000021
+#define AFS_REQUEST_TYPE_GET_VOLUME_SIZE_INFO    0x00000022
 
 //
 // Request Flags, these are passed up from the file system
index db573432f5bdcab188af4bdbf8abe108f25a89ad..c759cec8e045aa20dccfb8922bc017e13bd2a163 100644 (file)
@@ -241,9 +241,9 @@ typedef struct _AFS_DIR_ENUM_RESP
 typedef struct _AFS_VOLUME_INFORMATION
 {
 
-    LARGE_INTEGER   TotalAllocationUnits;       /* Partition Max Blocks */
+    LARGE_INTEGER   TotalAllocationUnits;       /* Volume Max Blocks (Partition or Quota) */
 
-    LARGE_INTEGER   AvailableAllocationUnits;   /* Partition Blocks Avail */
+    LARGE_INTEGER   AvailableAllocationUnits;   /* Volume Blocks Avail (Partition or Quota) */
 
     LARGE_INTEGER   VolumeCreationTime;         /* AFS Last Update - Not Creation */
 
@@ -264,10 +264,29 @@ typedef struct _AFS_VOLUME_INFORMATION
 
     ULONG           VolumeLabelLength;
 
-    WCHAR           VolumeLabel[20];            /* Volume:Cell */
+    WCHAR           VolumeLabel[128];            /* Volume:Cell */
 
 } AFSVolumeInfoCB;
 
+
+//
+// Volume size information CB passed used to satisfy
+// FileFsFullSizeInformation and FileFsSizeInformation
+//
+
+typedef struct _AFS_VOLUME_SIZE_INFORMATION
+{
+
+    LARGE_INTEGER   TotalAllocationUnits;       /* Max Blocks (Quota or Partition) */
+
+    LARGE_INTEGER   AvailableAllocationUnits;   /* Blocks Avail (Quota or Partition) */
+
+    ULONG           SectorsPerAllocationUnit;   /* = 1 */
+
+    ULONG           BytesPerSector;             /* = 1024 */
+
+} AFSVolumeSizeInfoCB;
+
 //
 // File create CB
 //
index 9afcdf9e6691553e7de8339b8ad9dd5f249bfcba..008d5636916b8f8b298f366c4c8996eef839a5c2 100644 (file)
@@ -2560,6 +2560,44 @@ try_exit:
     return ntStatus;
 }
 
+NTSTATUS
+AFSRetrieveVolumeSizeInformation( IN GUID *AuthGroup,
+                                  IN AFSFileID *FileID,
+                                  OUT AFSVolumeSizeInfoCB *VolumeSizeInformation)
+{
+
+    NTSTATUS ntStatus = STATUS_SUCCESS;
+    ULONG ulResultLen = 0;
+
+    __Enter
+    {
+
+        ulResultLen = sizeof( AFSVolumeSizeInfoCB);
+
+        ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_GET_VOLUME_SIZE_INFO,
+                                      AFS_REQUEST_FLAG_SYNCHRONOUS,
+                                      AuthGroup,
+                                      NULL,
+                                      FileID,
+                                      NULL,
+                                      0,
+                                      VolumeSizeInformation,
+                                      &ulResultLen);
+
+        if( ntStatus != STATUS_SUCCESS)
+        {
+
+            try_return( ntStatus);
+        }
+
+try_exit:
+
+        NOTHING;
+    }
+
+    return ntStatus;
+}
+
 NTSTATUS
 AFSNotifyPipeTransceive( IN AFSCcb *Ccb,
                          IN ULONG InputLength,
index 72c1e4c398edcb55528f2702b0bc856e94464798..33e174bfee01c5f73eb552551afec5ad84830916 100644 (file)
@@ -308,6 +308,8 @@ AFSQueryFsSizeInfo( IN AFSVolumeInfoCB *VolumeInfo,
 {
 
     NTSTATUS ntStatus = STATUS_SUCCESS;
+    AFSFileID FileID;
+    AFSVolumeSizeInfoCB VolumeSizeInfo;
 
     RtlZeroMemory( Buffer,
                    *Length);
@@ -315,15 +317,30 @@ AFSQueryFsSizeInfo( IN AFSVolumeInfoCB *VolumeInfo,
     if( *Length >= sizeof( FILE_FS_SIZE_INFORMATION))
     {
 
-        Buffer->TotalAllocationUnits.QuadPart = VolumeInfo->TotalAllocationUnits.QuadPart;
+        RtlZeroMemory( &FileID,
+                       sizeof(AFSFileID));
 
-        Buffer->AvailableAllocationUnits.QuadPart = VolumeInfo->AvailableAllocationUnits.QuadPart;
+        FileID.Cell = VolumeInfo->CellID;
 
-        Buffer->SectorsPerAllocationUnit = VolumeInfo->SectorsPerAllocationUnit;
+        FileID.Volume = VolumeInfo->VolumeID;
 
-        Buffer->BytesPerSector = VolumeInfo->BytesPerSector;
+        ntStatus = AFSRetrieveVolumeSizeInformation( NULL,
+                                                     &FileID,
+                                                     &VolumeSizeInfo);
 
-        *Length -= sizeof( FILE_FS_SIZE_INFORMATION);
+        if ( NT_SUCCESS( ntStatus))
+        {
+
+            Buffer->TotalAllocationUnits.QuadPart = VolumeSizeInfo.TotalAllocationUnits.QuadPart;
+
+            Buffer->AvailableAllocationUnits.QuadPart = VolumeSizeInfo.AvailableAllocationUnits.QuadPart;
+
+            Buffer->SectorsPerAllocationUnit = VolumeSizeInfo.SectorsPerAllocationUnit;
+
+            Buffer->BytesPerSector = VolumeSizeInfo.BytesPerSector;
+
+            *Length -= sizeof( FILE_FS_SIZE_INFORMATION);
+        }
     }
     else
     {
@@ -416,6 +433,8 @@ AFSQueryFsFullSizeInfo( IN AFSVolumeInfoCB *VolumeInfo,
 {
 
     NTSTATUS ntStatus = STATUS_SUCCESS;
+    AFSFileID FileID;
+    AFSVolumeSizeInfoCB VolumeSizeInfo;
 
     RtlZeroMemory( Buffer,
                    *Length);
@@ -423,17 +442,32 @@ AFSQueryFsFullSizeInfo( IN AFSVolumeInfoCB *VolumeInfo,
     if( *Length >= sizeof( FILE_FS_FULL_SIZE_INFORMATION))
     {
 
-        Buffer->TotalAllocationUnits.QuadPart = VolumeInfo->TotalAllocationUnits.QuadPart;
+        RtlZeroMemory( &FileID,
+                       sizeof(AFSFileID));
 
-        Buffer->CallerAvailableAllocationUnits.QuadPart = VolumeInfo->AvailableAllocationUnits.QuadPart;
+        FileID.Cell = VolumeInfo->CellID;
 
-        Buffer->ActualAvailableAllocationUnits.QuadPart = VolumeInfo->AvailableAllocationUnits.QuadPart;
+        FileID.Volume = VolumeInfo->VolumeID;
 
-        Buffer->SectorsPerAllocationUnit = VolumeInfo->SectorsPerAllocationUnit;
+        ntStatus = AFSRetrieveVolumeSizeInformation( NULL,
+                                                     &FileID,
+                                                     &VolumeSizeInfo);
 
-        Buffer->BytesPerSector = VolumeInfo->BytesPerSector;
+        if ( NT_SUCCESS( ntStatus))
+        {
+
+            Buffer->TotalAllocationUnits.QuadPart = VolumeSizeInfo.TotalAllocationUnits.QuadPart;
+
+            Buffer->CallerAvailableAllocationUnits.QuadPart = VolumeSizeInfo.AvailableAllocationUnits.QuadPart;
+
+            Buffer->ActualAvailableAllocationUnits.QuadPart = VolumeSizeInfo.AvailableAllocationUnits.QuadPart;
 
-        *Length -= sizeof( FILE_FS_FULL_SIZE_INFORMATION);
+            Buffer->SectorsPerAllocationUnit = VolumeSizeInfo.SectorsPerAllocationUnit;
+
+            Buffer->BytesPerSector = VolumeSizeInfo.BytesPerSector;
+
+            *Length -= sizeof( FILE_FS_FULL_SIZE_INFORMATION);
+        }
     }
     else
     {
index fc130b09c79221402006cc97a8377916ae43b32a..003b3a7118886cf8224863a4e3c1cc3a178d8775 100644 (file)
@@ -219,6 +219,11 @@ AFSRetrieveVolumeInformation( IN GUID *AuthGroup,
                               IN AFSFileID *FileID,
                               OUT AFSVolumeInfoCB *VolumeInformation);
 
+NTSTATUS
+AFSRetrieveVolumeSizeInformation( IN GUID *AuthGroup,
+                                  IN AFSFileID *FileID,
+                                  OUT AFSVolumeSizeInfoCB *VolumeSizeInformation);
+
 NTSTATUS
 AFSNotifyPipeTransceive( IN AFSCcb *Ccb,
                          IN ULONG InputLength,
index 8aca9b3c2f079849e85556a346dd0da6a184ce7b..03475c7310e4d25e8376e636e1c2bde5db264c98 100644 (file)
@@ -4995,14 +4995,8 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
     (*ResultCB)->ResultBufferLength = sizeof(AFSVolumeInfoCB);
     pResultCB = (AFSVolumeInfoCB *)(*ResultCB)->ResultData;
 
-    /* Allocate the extents from the buffer package */
     if (FileId.Cell != 0) {
-        Fid.cell = FileId.Cell;
-        Fid.volume = FileId.Volume;
-        Fid.vnode = FileId.Vnode;
-        Fid.unique = FileId.Unique;
-        Fid.hash = FileId.Hash;
-
+        cm_SetFid(&Fid, FileId.Cell, FileId.Volume, 1, 1);
         code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
         if (code) {
             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
@@ -5019,7 +5013,6 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
     }
     lock_ObtainWrite(&scp->rw);
 
-    /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) {
@@ -5032,7 +5025,6 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
         return;
     }
 
-    /* Fake for now */
     pResultCB->SectorsPerAllocationUnit = 1;
     pResultCB->BytesPerSector = 1024;
 
@@ -5084,11 +5076,29 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
        } while (cm_Analyze(connp, userp, &req, &scp->fid, 0, NULL, NULL, NULL, code));
        code = cm_MapRPCError(code, &req);
         if (code == 0) {
-            pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
-            pResultCB->AvailableAllocationUnits.QuadPart = volStat.PartBlocksAvail;
-
-            pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( Name, -1, pResultCB->VolumeLabel,
-                                                           (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
+            if (volStat.MaxQuota)
+            {
+                pResultCB->TotalAllocationUnits.QuadPart = volStat.MaxQuota;
+                if (volType == ROVOL || volType == BACKVOL) {
+                    pResultCB->AvailableAllocationUnits.QuadPart = 0;
+                }
+                else
+                {
+                    pResultCB->AvailableAllocationUnits.QuadPart =
+                        min(volStat.MaxQuota - volStat.BlocksInUse, volStat.PartBlocksAvail);
+                }
+            }
+            else
+            {
+                pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
+                if (volType == ROVOL || volType == BACKVOL) {
+                    pResultCB->AvailableAllocationUnits.QuadPart = 0;
+                }
+                else
+                {
+                    pResultCB->AvailableAllocationUnits.QuadPart = volStat.PartBlocksAvail;
+                }
+            }
         } else {
             pResultCB->TotalAllocationUnits.QuadPart = 0x7FFFFFFF;
             pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000;
@@ -5118,6 +5128,167 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
     return;
 }
 
+void
+RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
+                   IN AFSFileID     FileId,
+                   IN BOOL bWow64,
+                   IN DWORD ResultBufferLength,
+                   IN OUT AFSCommResult **ResultCB)
+{
+    AFSVolumeSizeInfoCB *pResultCB = NULL;
+    DWORD       Length;
+    cm_scache_t *scp = NULL;
+    cm_volume_t *volp = NULL;
+    afs_uint32   volType;
+    cm_cell_t   *cellp = NULL;
+    cm_fid_t    Fid;
+    afs_uint32  code;
+    cm_req_t    req;
+    DWORD       status;
+
+    char volName[32]="(unknown)";
+    char offLineMsg[256]="server temporarily inaccessible";
+    char motd[256]="server temporarily inaccessible";
+    cm_conn_t *connp;
+    AFSFetchVolumeStatus volStat;
+    char *Name;
+    char *OfflineMsg;
+    char *MOTD;
+    struct rx_connection * rxconnp;
+
+    RDR_InitReq(&req);
+    if ( bWow64 )
+        req.flags |= CM_REQ_WOW64;
+
+    osi_Log4(afsd_logp, "RDR_GetVolumeSizeInfo File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
+             FileId.Cell, FileId.Volume,
+             FileId.Vnode, FileId.Unique);
+
+    Length = sizeof( AFSCommResult) + sizeof(AFSVolumeSizeInfoCB);
+    if (sizeof(AFSVolumeSizeInfoCB) > ResultBufferLength) {
+        *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
+        if (!(*ResultCB))
+            return;
+        memset( *ResultCB, 0, sizeof(AFSCommResult));
+        (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
+        return;
+    }
+
+    *ResultCB = (AFSCommResult *)malloc( Length );
+    if (!(*ResultCB))
+       return;
+    memset( *ResultCB, '\0', Length );
+    (*ResultCB)->ResultBufferLength = sizeof(AFSVolumeSizeInfoCB);
+    pResultCB = (AFSVolumeSizeInfoCB *)(*ResultCB)->ResultData;
+
+    if (FileId.Cell != 0) {
+        cm_SetFid(&Fid, FileId.Cell, FileId.Volume, 1, 1);
+        code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
+        if (code) {
+            smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+            (*ResultCB)->ResultStatus = status;
+            (*ResultCB)->ResultBufferLength = 0;
+            osi_Log2(afsd_logp, "RDR_GetVolumeSizeInfo cm_GetSCache FID failure code=0x%x status=0x%x",
+                      code, status);
+            return;
+        }
+    } else {
+        (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
+        osi_Log0(afsd_logp, "RDR_GetVolumeSizeInfo Object Name Invalid - Cell = 0");
+        return;
+    }
+    lock_ObtainWrite(&scp->rw);
+
+    code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+    if (code) {
+        lock_ReleaseWrite(&scp->rw);
+        smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+        (*ResultCB)->ResultStatus = status;
+        (*ResultCB)->ResultBufferLength = 0;
+        osi_Log3(afsd_logp, "RDR_GetVolumeSizeInfo cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
+                 scp, code, status);
+        return;
+    }
+
+    pResultCB->SectorsPerAllocationUnit = 1;
+    pResultCB->BytesPerSector = 1024;
+
+    if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
+         scp->fid.volume==AFS_FAKE_ROOT_VOL_ID)
+    {
+        pResultCB->TotalAllocationUnits.QuadPart = 100;
+        pResultCB->AvailableAllocationUnits.QuadPart = 0;
+    } else {
+        volp = cm_GetVolumeByFID(&scp->fid);
+        if (!volp) {
+            code = CM_ERROR_NOSUCHVOLUME;
+            goto _done;
+        }
+
+        volType = cm_VolumeType(volp, scp->fid.volume);
+        Name = volName;
+       OfflineMsg = offLineMsg;
+       MOTD = motd;
+       lock_ReleaseWrite(&scp->rw);
+       do {
+           code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
+           if (code) continue;
+
+           rxconnp = cm_GetRxConn(connp);
+           code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
+                                        &volStat, &Name, &OfflineMsg, &MOTD);
+           rx_PutConnection(rxconnp);
+
+       } while (cm_Analyze(connp, userp, &req, &scp->fid, 0, NULL, NULL, NULL, code));
+       code = cm_MapRPCError(code, &req);
+        if (code == 0) {
+            if (volStat.MaxQuota)
+            {
+                pResultCB->TotalAllocationUnits.QuadPart = volStat.MaxQuota;
+                if (volType == ROVOL || volType == BACKVOL) {
+                    pResultCB->AvailableAllocationUnits.QuadPart = 0;
+                }
+                else
+                {
+                    pResultCB->AvailableAllocationUnits.QuadPart =
+                        min(volStat.MaxQuota - volStat.BlocksInUse, volStat.PartBlocksAvail);
+                }
+            }
+            else
+            {
+                pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
+                if (volType == ROVOL || volType == BACKVOL) {
+                    pResultCB->AvailableAllocationUnits.QuadPart = 0;
+                }
+                else
+                {
+                    pResultCB->AvailableAllocationUnits.QuadPart = volStat.PartBlocksAvail;
+                }
+            }
+        } else {
+
+            pResultCB->TotalAllocationUnits.QuadPart = 0x7FFFFFFF;
+            pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000;
+            code = 0;
+        }
+        lock_ObtainWrite(&scp->rw);
+    }
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+  _done:
+    lock_ReleaseWrite(&scp->rw);
+    if (volp)
+       cm_PutVolume(volp);
+    cm_ReleaseSCache(scp);
+
+    smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
+    (*ResultCB)->ResultStatus = status;
+    osi_Log0(afsd_logp, "RDR_GetVolumeSizeInfo SUCCESS");
+    return;
+}
+
 void
 RDR_HoldFid( IN cm_user_t     *userp,
              IN AFSHoldFidRequestCB * pHoldFidCB,
index 18bc9ad9fb7cf9903566d5c0b87f4a4ae66b88b2..3870e6f124776968ceda51f1c49bb40b93906f54 100644 (file)
@@ -1015,6 +1015,25 @@ RDR_ProcessRequest( AFSCommRequest *RequestBuffer)
                 break;
             }
 
+    case AFS_REQUEST_TYPE_GET_VOLUME_SIZE_INFO:
+            {
+                if (afsd_logp->enabled) {
+                    swprintf( wchBuffer, L"ProcessRequest Processing AFS_REQUEST_TYPE_GET_VOLUME_SIZE_INFO Index %08lX File %08lX.%08lX.%08lX.%08lX",
+                              RequestBuffer->RequestIndex,
+                              RequestBuffer->FileId.Cell, RequestBuffer->FileId.Volume,
+                              RequestBuffer->FileId.Vnode, RequestBuffer->FileId.Unique);
+
+                    osi_Log1(afsd_logp, "%S", osi_LogSaveStringW(afsd_logp, wchBuffer));
+                }
+
+                RDR_GetVolumeSizeInfo( userp,
+                                       RequestBuffer->FileId,
+                                       bWow64,
+                                       RequestBuffer->ResultBufferLength,
+                                       &pResultCB);
+                break;
+            }
+
     case AFS_REQUEST_TYPE_HOLD_FID:
             {
 
index 2130fe057978081e161763a7d8b090d7bb108973..5ec9af3b88e892a6af980f9a9b8f3f8dd1bb571f 100644 (file)
@@ -267,6 +267,13 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
                    IN DWORD ResultBufferLength,
                    IN OUT AFSCommResult **ResultCB);
 
+void
+RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
+                       IN AFSFileID     FileId,
+                       IN BOOL bWow64,
+                       IN DWORD ResultBufferLength,
+                       IN OUT AFSCommResult **ResultCB);
+
 void
 RDR_HoldFid( IN cm_user_t     *userp,
              IN AFSHoldFidRequestCB * pHoldFidCB,