// SPDX-License-Identifier: MIT /* * VirtualBox Guest Shared Folders support: Regular file inode and file ops. * * Copyright (C) 2006-2018 Oracle Corporation */ #include <linux/mm.h> #include <linux/page-flags.h> #include <linux/pagemap.h> #include <linux/highmem.h> #include <linux/sizes.h> #include "vfsmod.h" struct vboxsf_handle { … }; struct vboxsf_handle *vboxsf_create_sf_handle(struct inode *inode, u64 handle, u32 access_flags) { … } static int vboxsf_file_open(struct inode *inode, struct file *file) { … } static void vboxsf_handle_release(struct kref *refcount) { … } void vboxsf_release_sf_handle(struct inode *inode, struct vboxsf_handle *sf_handle) { … } static int vboxsf_file_release(struct inode *inode, struct file *file) { … } /* * Write back dirty pages now, because there may not be any suitable * open files later */ static void vboxsf_vma_close(struct vm_area_struct *vma) { … } static const struct vm_operations_struct vboxsf_file_vm_ops = …; static int vboxsf_file_mmap(struct file *file, struct vm_area_struct *vma) { … } /* * Note that since we are accessing files on the host's filesystem, files * may always be changed underneath us by the host! * * The vboxsf API between the guest and the host does not offer any functions * to deal with this. There is no inode-generation to check for changes, no * events / callback on changes and no way to lock files. * * To avoid returning stale data when a file gets *opened* on our (the guest) * side, we do a "stat" on the host side, then compare the mtime with the * last known mtime and invalidate the page-cache if they differ. * This is done from vboxsf_inode_revalidate(). * * When reads are done through the read_iter fop, it is possible to do * further cache revalidation then, there are 3 options to deal with this: * * 1) Rely solely on the revalidation done at open time * 2) Do another "stat" and compare mtime again. Unfortunately the vboxsf * host API does not allow stat on handles, so we would need to use * file->f_path.dentry and the stat will then fail if the file was unlinked * or renamed (and there is no thing like NFS' silly-rename). So we get: * 2a) "stat" and compare mtime, on stat failure invalidate the cache * 2b) "stat" and compare mtime, on stat failure do nothing * 3) Simply always call invalidate_inode_pages2_range on the range of the read * * Currently we are keeping things KISS and using option 1. this allows * directly using generic_file_read_iter without wrapping it. * * This means that only data written on the host side before open() on * the guest side is guaranteed to be seen by the guest. If necessary * we may provide other read-cache strategies in the future and make this * configurable through a mount option. */ const struct file_operations vboxsf_reg_fops = …; const struct inode_operations vboxsf_reg_iops = …; static int vboxsf_read_folio(struct file *file, struct folio *folio) { … } static struct vboxsf_handle *vboxsf_get_write_handle(struct vboxsf_inode *sf_i) { … } static int vboxsf_writepage(struct page *page, struct writeback_control *wbc) { … } static int vboxsf_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned int len, unsigned int copied, struct page *page, void *fsdata) { … } /* * Note simple_write_begin does not read the page from disk on partial writes * this is ok since vboxsf_write_end only writes the written parts of the * page and it does not call SetPageUptodate for partial writes. */ const struct address_space_operations vboxsf_reg_aops = …; static const char *vboxsf_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { … } const struct inode_operations vboxsf_lnk_iops = …;