NTFS has an emergency stash of disk space
I would really love to have a better understanding of what is going on here!
If you format a 32 MB disk using NTFS, you’ll get the following result:
So about 10 MB are taken for NTFS metadata. I guess that makes sense, and giving up 10 MB isn’t generally a big deal these days, so I wouldn’t worry about it.
I write a 20 MB file and punch a hole in it between 6 MB and 18 MB (12 MB in total), so we have:
And in terms of disk space, we have:
The numbers match, awesome! Let’s create a new 12 MB file, like so:
And the disk is:
And now I’m running the following code, which maps the first file (with the hole punched in it) and writes 4 MB to it using memory-mapped I/O:
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hMapFile == NULL) {
fprintf(stderr, "Could not create file mapping object: %x\n", GetLastError());
exit(__LINE__);
}
char* lpMapAddress = MapViewOfFile(hMapFile, FILE_MAP_WRITE, 0, 0, 0);
if (lpMapAddress == NULL) {
fprintf(stderr, "Could not map view of file: %x\n", GetLastError());
exit(__LINE__);
}
for (i = 6 * MB; i < 10 * MB; i++) {
((char*)lpMapAddress)[i]++;
}
if (!FlushViewOfFile(lpMapAddress, 0)) {
fprintf(stderr, "Could not flush view of file: %x\n", GetLastError());
exit(__LINE__);
}
if (!FlushFileBuffers(hFile)) {
fprintf(stderr, "Could not flush file buffers: %x\n", GetLastError());
exit(__LINE__);
}
The end for this file is:
So with the other file, we have a total of 24 MB in use on a 32 MB disk. And here is the state of the disk itself:
The problem is that there used to be 9.78 MB that were busy when we had a newly formatted disk. And now we are using at least some of that disk space for storing file data somehow.
I’m getting the same behavior when I use normal file I/O:
moveAmount.QuadPart = 6 * MB;
SetFilePointerEx(hFile, moveAmount, NULL, FILE_BEGIN);
for (i = 6 ; i < 10 ; i++) {
if (!WriteFile(hFile, buffer, MB, &bytesWritten, NULL)) {
fprintf(stderr, "WriteFile failed on iteration %d: %x\n", i, GetLastError());
exit(__LINE__);
}
}
So somehow in this sequence of operations, we get more disk space. On the other hand, if I try to write just 22 MB into a single file, it fails. See:
hFile = CreateFileA("R:/original_file.bin", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Error creating file: %d\n", GetLastError());
exit(__LINE__);
}
for (int i = 0; i < 22; i++) {
if (!WriteFile(hFile, buffer, MB, &bytesWritten, NULL)) {
fprintf(stderr, "WriteFile failed on iteration %d: %x\n", i, GetLastError());
exit(__LINE__);
}
}
You can find the full source here. I would love to understand what exactly is happening and how we suddenly get more disk space usage in this scenario.
Comments
From: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc781134(v=ws.10)
Comment preview
Join the conversation...