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 6c93461..b3037b1 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 db57343..c759cec 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 9afcdf9..008d563 100644 (file)
@@ -2561,6 +2561,44 @@ try_exit:
 }
 
 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,
                          IN ULONG OutputLength,
index 72c1e4c..33e174b 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 fc130b0..003b3a7 100644 (file)
@@ -220,6 +220,11 @@ AFSRetrieveVolumeInformation( IN GUID *AuthGroup,
                               OUT AFSVolumeInfoCB *VolumeInformation);
 
 NTSTATUS
+AFSRetrieveVolumeSizeInformation( IN GUID *AuthGroup,
+                                  IN AFSFileID *FileID,
+                                  OUT AFSVolumeSizeInfoCB *VolumeSizeInformation);
+
+NTSTATUS
 AFSNotifyPipeTransceive( IN AFSCcb *Ccb,
                          IN ULONG InputLength,
                          IN ULONG OutputLength,
index 8aca9b3..03475c7 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;
@@ -5119,6 +5129,167 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
 }
 
 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,
              IN BOOL bFast,
index 18bc9ad..3870e6f 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 2130fe0..5ec9af3 100644 (file)
@@ -268,6 +268,13 @@ RDR_GetVolumeInfo( IN cm_user_t     *userp,
                    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,
              IN BOOL bFast,