Opened 7 years ago
Closed 7 years ago
#17053 closed defect (duplicate)
Linux guest readv system call returns stale (cached) shared folder file data -> duplicate of #819
Reported by: | Heath | Owned by: | |
---|---|---|---|
Component: | shared folders | Version: | VirtualBox 5.1.26 |
Keywords: | shared folder, stale data, file cache, readv, sendfile | Cc: | |
Guest type: | Linux | Host type: | Windows |
Description
I use Windows 7 host and a Linux guest and am using a shared folder to share a source code tree between them. I have been experiencing problems with the Linux VM (kernel 4.x) continuing to read stale file data after a file has been updated by the Windows host.
Interestingly, not all programs read the stale cached data. For example, the cat utility will get the correct data, but my version of the GNU Assembler gas does not. (This has led to great confusion when building my program!).
I have discovered that programs that read files using the read system call return the correct data, but those using the readv system call (such as my version of gas) read stale cached data. I wrote a simple test implementation of the cat utility which uses readv, and it too reads the stale data.
So, this bash command will essentially report that a file differs with itself:
$ diff <(cat /share/testfile.txt) <(cat_using_readv /share/testfile.txt)
I further discovered that telling Linux to drop its file caches (very) temporarily solves the problem.
$ echo 3 > /proc/sys/vm/drop_caches
I have been looking through the shared folder source, and I believe the problem lies within 'src/VBox/Additions/linux/sharedfolders/regops.c' and the use of kernel function generic_file_read_iter as the .read_iter member of the file_operations structure (.read_iter is used when doing a readv system call). This function WILL write to and read from the file cache. However, vbox function sf_reg_read, as used for the generic .read member and read system call, appears to always bypass Linux's FS cache.
556 struct file_operations sf_reg_fops = 557 { 558 .read = sf_reg_read, 559 .open = sf_reg_open, 560 .write = sf_reg_write, 561 .release = sf_reg_release, 562 .mmap = sf_reg_mmap, 563 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) 564 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) 565 .splice_read = generic_file_splice_read, 566 # else 567 .sendfile = generic_file_sendfile, 568 # endif 569 # if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) 570 .read_iter = generic_file_read_iter, // 571 .write_iter = generic_file_write_iter, 572 # else 573 .aio_read = generic_file_aio_read, 574 .aio_write = generic_file_aio_write, 575 # endif
Further I believe that a similar long-lived issue is reported as ticket #819, only for the sendfile system call. It seems that all of these generic_file_* functions have the expectation that the host controls all access to the drive. However, this is not the case for the shared folder. One may look at the cifs and nfs network shared folder drivers to see how they manage the FS cache.
For reference, some relevant linux kernel files are:
- fs/read_write.c
- mm/filemap.c
- include/linux/fs.h
Change History (2)
comment:2 by , 7 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
Summary: | Linux guest readv system call returns stale (cached) shared folder file data → Linux guest readv system call returns stale (cached) shared folder file data -> duplicate of #819 |
Here's a patch that should fix this issue and issue #819. https://pastebin.com/NU5VrsRR
Your analysis was spot on. The generic_file_* functions implement caching and should not be used by this driver unless the driver takes care to invalidate the cache when the host system changes the file. In my opinion, there's no need to cache the data in the guest system as it will most likely already be cached by the host. This patch causes the driver to revert to kernel provided functions for (splice_read / sendfile), (read_iter / aio_read), and (write_iter / aio_write) which do NOT cache data.
Kernel versions prior to 2.6.31 do not provide a default handler for (splice_read / sendfile) and will return an error if sendfile is used. That kernel is now 8 years old. Linux Kernel 2.6.32 was an LTS release for which support ended in February 2016. This patch will break sendfile support for earlier kernels, but it can be argued that the existing support via the generic_file_* functions was broken as it returns stale data for those kernels.
I see little point in supporting kernels prior to 2.6.31, especially since support for the 2.6.32 LTS release has ended and is nonetheless still supported by this patch.