MmFlushImageSection(MmFlushForDelete) during Rename

Happy holidays to all. Here I am with another obscure file system failure.

Consider the following test:
<<
Handle = CreateFileW(File0Path,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping0 = CreateFileMappingW(Handle, 0, PAGE_READWRITE,
0, SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping0);
Success = CloseHandle(Handle);
ASSERT(Success);

Handle = CreateFileW(File1Path,
GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(INVALID_HANDLE_VALUE != Handle);
Mapping1 = CreateFileMappingW(Handle, 0, PAGE_READWRITE,
0, SystemInfo.dwAllocationGranularity, 0);
ASSERT(0 != Mapping1);
Success = CloseHandle(Handle);
ASSERT(Success);

Success = MoveFileExW(File0Path, File2Path, MOVEFILE_REPLACE_EXISTING);
ASSERT(Success);
Success = MoveFileExW(File2Path, File1Path, MOVEFILE_REPLACE_EXISTING);
ASSERT(Success); // <— FAILURE HERE on my FSD

Success = CloseHandle(Mapping0);
ASSERT(Success);
Success = CloseHandle(Mapping1);
ASSERT(Success);

>

This test creates two files and two mappings for them and then closes them. Thus their HandleCount is 0 (CLEANUP has been called) and their OpenCount is non-0 (CLOSE has not been called).

It then attempts the following renames:

  • The file “file0” is renamed to the NON-EXISTING “file2”. This succeeds.
  • The file “file2” is renamed to the EXISTING file “file1”. This test succeeds on NTFS. It fails on my FSD.

My FSD calls MmFlushImageSection with MmFlushForDelete. This call returns FALSE in this particular case. Since there is no mapped image I would expect that MmFlushImageSection should return TRUE!

There is an interesting note in the MmFlushImageSection documentation that may explain why:
<<
NOTE: If the FlushType MmFlushForDelete value is specified and there are one or more outstanding write probes on the file’s data section, MmFlushImageSection returns FALSE.

>

Looking at the public sources for FastFat it appears to do an MmFlushImageSection(MmFlushForDelete) for the target, which means that it should have the same behavior as my FSD (I have not had the chance to test it):
https://github.com/Microsoft/Windows-driver-samples/blob/master/filesys/fastfat/fileinfo.c#L3345

What does NTFS do then? Does it not do MmFlushImageSection(MmFlushForDelete)? Does it do an MmFlushImageSection(MmFlushForDelete) only if the ImageSectionObject exists?

Many thanks. Off to cook now as the family is getting hungry :slight_smile:

Bill

NTFS does MmFlushImageSection only if there is image section mapped for any
stream of a file. Also it doesn’t do MmFlushImageSection if this is not
last link of a file and therefore file is not going to be deleted from disk.

Anatoly, thanks. This is great information.

I have modified my FSD to only do MmFlushImageSection if an ImageSectionObject exists (in the Rename case). The test now passes on both NTFS and my FSD.

Bill