-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Windows] potential directory sync API misuse #699
Comments
Thanks for the report and sorry for the delay, @djdv Is this issue still occurring on master? What version are you using? |
I spent some time today looking into this failure but couldn't find anything relevant. The issue is with how windows deals with sync on volumes.
From https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-flushfilebuffers#remarks This means we might have to flush all the files individually. It might also require administrator privileges which might not be feasible every time. |
Spent some more time digging into the failure and it's easily reproducible using the following script func main() {
dir := "Z:\\smb-test" // Path to network mapped drive
f, err := openDir(dir)
if err != nil {
log.Fatal(err)
}
// Works fine if the path is located on a local disk but
// fails if the directory is on a network mapped drive
if err := f.Sync(); err != nil {
log.Fatal(err)
}
if err := f.Close(); err != nil {
log.Fatal(err)
}
}
func openDir(path string) (*os.File, error) {
fd, err := openDirWin(path)
if err != nil {
return nil, err
}
return os.NewFile(uintptr(fd), path), nil
}
func openDirWin(path string) (fd syscall.Handle, err error) {
pathp, err := syscall.UTF16PtrFromString(path)
if err != nil {
return syscall.InvalidHandle, err
}
access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE)
sharemode := uint32(syscall.FILE_SHARE_READ | syscall.FILE_SHARE_WRITE)
createmode := uint32(syscall.OPEN_EXISTING)
fl := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
return syscall.CreateFile(pathp, access, sharemode, nil, createmode, fl, 0)
}
|
This is now the last "actual" issue in the v2.0.0 milestone 🎉 Let me know if you need someone with Windows expertise to look into this, happy to see who can help. |
@campoy It would be great if someone with windows expertise can have a look at this issue. I also raised https://social.msdn.microsoft.com/Forums/Windowsdesktop/en-US/847a735b-f21a-4be2-880b-12660e5b98b4/flushfilebuffers-system-call-fails-on-network-mapped-drive?forum=windowsgeneraldevelopmentissues to figure out the way to do but it looks like we cannot call |
It seems like this will be harder to fix than initially expected and is definitely not a release blocker. Thanks for all the investigation work, @jarifibrahim! |
From Syncing Network Mapped Directory MSDN ticket and Syncing Local Directories MSDN ticket I understand that there's no way to sync directories on windows.
From the same tickets, I found out that instead of flushing files on windows we should open them using FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITETHROUGH (see docs) which would ensure we sync files to the disk and it also performs better than |
Windows doesn't support syncing directories. This commit adds a no-op method for syncing directories on windows. See #699 (comment) for more details.
Windows doesn't support syncing directories. This commit adds a no-op method for syncing directories on windows. See #699 (comment) for more details.
Windows doesn't support syncing directories. This commit adds a no-op method for syncing directories on windows. See hypermodeinc/badger#699 (comment) for more details.
On Windows, I have an SMB share mounted as
Z:
.Using it as the target directory results in an error
The source of the error seems to be returned from the
FlushFileBuffers
syscall here:https://github.com/golang/go/blob/66065c3115861c73b8804037a6d9d5986ffa9913/src/syscall/zsyscall_windows.go#L970
which is called as a result of bader.syncDir -> os.File.Fsync
While investigating this, I found it strange that this call does not return an error for local drives, but does for network drives.
MSDN states that the handle passed in should either be a handle to a file, or to a volume, but says nothing about directories.
https://docs.microsoft.com/en-us/windows/desktop/api/FileAPI/nf-fileapi-flushfilebuffers
And FlushFileBuffers is not listed as a function that accepts directory handles
https://docs.microsoft.com/en-us/windows/desktop/fileio/obtaining-a-handle-to-a-directory
I could be wrong but I believe this is an invalid/ineffectual argument to pass to this function on this platform. Or at the very least, not API defined, and thus not guaranteed to succeed.
So even for local disks where this currently returns without an error, files should probably be synced individually by their opened handles anyway.
And while this function accepts volumes, I don't think triggering a full disk sync is likely desirable.
In the SMB case you can't retrieve a handle to the volume through the same methods either, but syncing individual files appears to be valid. (it should trigger an SMB
FLUSH
request which should force the transmit buffer to flush at least to the network).For some additional context, (while not safe) commenting out
err = f.Sync()
undersyncDir()
allowed me to run an instance ofgo-ipfs
using badger as the datastore (hosted on the SMB share) without any obvious issues. Although testing was not extensive.To avoid the possibility that this was a Go related issue, I probed around on my systems using a small C program. I listed the various results for the given arguments in the comments.
Test environment was W10 connecting to a remote share on a Solaris system, a remote share on a W10 system, and W10 connecting to a share it itself is hosting (local loop with full access).
All had the same output.
The text was updated successfully, but these errors were encountered: