Samba + exFAT : how to avoid pre-allocating when copying big files?
jra at samba.org
Thu Dec 10 00:37:57 UTC 2020
On Wed, Dec 09, 2020 at 08:50:49AM -0500, Joseph via samba-technical wrote:
>> FileEndOfFileInformation == ftruncate();
>> FileAllocationInformation == fallocate(.., FALLOC_FL_KEEP_SIZE, offset,
>Jeremy, by ftruncate() do you mean "immediate writing of null bytes"?
No, ftruncate sets the length (EOF) of the file.
Whether it fills the intermediate areas with zero
bytes is a driver/filesystem dependent issue.
If it sets the length greater than the current file
then the POSIX requirement is that when an application
reads between the old EOF and the new (extended) EOF
then zero bytes must be returned.
Whether they are stored on disk or the file is marked
sparse and they are added on read is filesystem dependent.
Samba doesn't know or care about the filesystem layout
(not strictly true for some advanced filesystems, but
in general this is the case).
>I've analyzed syscall logs to see how some programs on Windows do, which
>1) create a file on exFAT partition
>2) immediately set 1 GB file size *without* any delay; it's instantaneously
>reported as 1GB in the Explorer; also, there is no 1GB null-bytes writing
So the Windows driver is setting EOF without writing
>3) then write the actual file content
>It goes like this:
>t=0.000s: SetFileInformationByHandle with FILE_END_OF_FILE_INFO,
>with FILE_ALLOCATION_INFO, AllocationSize=1073741824
>t=0.001s WriteFile (here the real data writing begins)
>t~44sec WriteFile (last block written)
>So this confirms that, with the Windows native exFAT driver, neither
>"FileEndOfFileInformation" nor "FileAllocationInformation" triggers an
>immediate truncate() or writing of null bytes for an opened file handle.
>This "writing of null bytes" only happens when the file is closed for the
>"remaining unwritten blocks", that's the trick. Example:
> CreateFile, SetEndOfFileInfo+SetAllocationInfo 1GB, Close => then 1GB
>of null bytes written
> CreateFile, SetEndOfFileInfo+SetAllocationInfo 1GB, Write 100MB, Close
>=> then only 900 MB of null bytes written
> CreateFile, SetEndOfFileInfo+SetAllocationInfo 1GB, Write 500MB, Close
>=> then only 500 MB of null bytes written
> CreateFile, SetEndOfFileInfo+SetAllocationInfo 1GB, Write 1000MB,
>Close => then 0 MB of null bytes written ! <-----
>Namjae, do you think this should be done directly at the Linux exFAT driver
This has to be done in the exFAT driver code. Samba as a userspace
program can't know if setting EOF writes out zero bytes or merely
sets an sparse extent. Reading just returns zero bytes for us
whichever the filesystem driver choses.
>I'm not sure if the modification should be at the Linux exFAT driver layer,
>or in Samba?
>If the latter, in Samba, would it be possible to avoid that
>SetFileEndOfFileInformation == ftruncate() == immediate writing of null
The only way to do that is as I said to have a customer VFS
module that lies to the upper layers about file length. This
is a somewhat complex bit of code as it has to catch and lie
to the smbd code for all possible accesses of the filename/handle
for all stat() calls.
>TL;DR: with Windows' native exFAT driver, SetAllocation+SetEndOfFileInfo
>does not write any null bytes now, if the file handle is still open. It
>will only write null bytes, on file close, on the *remaining* space that
>has not been written before. If all the preallocated blocks are already
>written, there is no null-bytes writing.
That's a driver decision.
More information about the samba-technical