From: Jeffrey Altman Date: Thu, 5 Apr 2012 18:40:18 +0000 (-0400) Subject: Windows: Redirector must query volume size when asked X-Git-Tag: openafs-stable-1_8_0pre1~2639 X-Git-Url: https://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=c19d1b875fab472dc7474c70529ab7fc2f7bf106 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 --- diff --git a/src/WINNT/afsrdr/common/AFSUserDefines.h b/src/WINNT/afsrdr/common/AFSUserDefines.h index 6c93461..b3037b1 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 db57343..c759cec 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 9afcdf9..008d563 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp @@ -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, diff --git a/src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp b/src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp index 72c1e4c..33e174b 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 fc130b0..003b3a7 100644 --- a/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h @@ -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, diff --git a/src/WINNT/afsrdr/user/RDRFunction.c b/src/WINNT/afsrdr/user/RDRFunction.c index 8aca9b3..03475c7 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; @@ -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, diff --git a/src/WINNT/afsrdr/user/RDRInit.cpp b/src/WINNT/afsrdr/user/RDRInit.cpp index 18bc9ad..3870e6f 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 2130fe0..5ec9af3 100644 --- a/src/WINNT/afsrdr/user/RDRPrototypes.h +++ b/src/WINNT/afsrdr/user/RDRPrototypes.h @@ -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,