From c19d1b875fab472dc7474c70529ab7fc2f7bf106 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Thu, 5 Apr 2012 14:40:18 -0400 Subject: [PATCH] Windows: Redirector must query volume size when asked 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 Tested-by: Jeffrey Altman --- src/WINNT/afsrdr/common/AFSUserDefines.h | 1 + src/WINNT/afsrdr/common/AFSUserStructs.h | 25 ++- .../afsrdr/kernel/lib/AFSCommSupport.cpp | 38 ++++ src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp | 56 ++++- .../afsrdr/kernel/lib/Include/AFSCommon.h | 5 + src/WINNT/afsrdr/user/RDRFunction.c | 199 ++++++++++++++++-- src/WINNT/afsrdr/user/RDRInit.cpp | 19 ++ src/WINNT/afsrdr/user/RDRPrototypes.h | 7 + 8 files changed, 322 insertions(+), 28 deletions(-) diff --git a/src/WINNT/afsrdr/common/AFSUserDefines.h b/src/WINNT/afsrdr/common/AFSUserDefines.h index 6c93461ed..b3037b1a6 100644 --- a/src/WINNT/afsrdr/common/AFSUserDefines.h +++ b/src/WINNT/afsrdr/common/AFSUserDefines.h @@ -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 diff --git a/src/WINNT/afsrdr/common/AFSUserStructs.h b/src/WINNT/afsrdr/common/AFSUserStructs.h index db573432f..c759cec8e 100644 --- a/src/WINNT/afsrdr/common/AFSUserStructs.h +++ b/src/WINNT/afsrdr/common/AFSUserStructs.h @@ -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 // diff --git a/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp index 9afcdf9e6..008d56369 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp @@ -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, diff --git a/src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp b/src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp index 72c1e4c39..33e174bfe 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp @@ -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 { diff --git a/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h b/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h index fc130b09c..003b3a711 100644 --- a/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h @@ -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, diff --git a/src/WINNT/afsrdr/user/RDRFunction.c b/src/WINNT/afsrdr/user/RDRFunction.c index 8aca9b3c2..03475c731 100644 --- a/src/WINNT/afsrdr/user/RDRFunction.c +++ b/src/WINNT/afsrdr/user/RDRFunction.c @@ -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, diff --git a/src/WINNT/afsrdr/user/RDRInit.cpp b/src/WINNT/afsrdr/user/RDRInit.cpp index 18bc9ad9f..3870e6f12 100644 --- a/src/WINNT/afsrdr/user/RDRInit.cpp +++ b/src/WINNT/afsrdr/user/RDRInit.cpp @@ -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: { diff --git a/src/WINNT/afsrdr/user/RDRPrototypes.h b/src/WINNT/afsrdr/user/RDRPrototypes.h index 2130fe057..5ec9af3b8 100644 --- a/src/WINNT/afsrdr/user/RDRPrototypes.h +++ b/src/WINNT/afsrdr/user/RDRPrototypes.h @@ -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, -- 2.39.5