18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * VirtualBox Guest Shared Folders support: Regular file inode and file ops.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2018 Oracle Corporation
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/mm.h>
98c2ecf20Sopenharmony_ci#include <linux/page-flags.h>
108c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
118c2ecf20Sopenharmony_ci#include <linux/highmem.h>
128c2ecf20Sopenharmony_ci#include <linux/sizes.h>
138c2ecf20Sopenharmony_ci#include "vfsmod.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cistruct vboxsf_handle {
168c2ecf20Sopenharmony_ci	u64 handle;
178c2ecf20Sopenharmony_ci	u32 root;
188c2ecf20Sopenharmony_ci	u32 access_flags;
198c2ecf20Sopenharmony_ci	struct kref refcount;
208c2ecf20Sopenharmony_ci	struct list_head head;
218c2ecf20Sopenharmony_ci};
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistruct vboxsf_handle *vboxsf_create_sf_handle(struct inode *inode,
248c2ecf20Sopenharmony_ci					      u64 handle, u32 access_flags)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct vboxsf_inode *sf_i = VBOXSF_I(inode);
278c2ecf20Sopenharmony_ci	struct vboxsf_handle *sf_handle;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	sf_handle = kmalloc(sizeof(*sf_handle), GFP_KERNEL);
308c2ecf20Sopenharmony_ci	if (!sf_handle)
318c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	/* the host may have given us different attr then requested */
348c2ecf20Sopenharmony_ci	sf_i->force_restat = 1;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	/* init our handle struct and add it to the inode's handles list */
378c2ecf20Sopenharmony_ci	sf_handle->handle = handle;
388c2ecf20Sopenharmony_ci	sf_handle->root = VBOXSF_SBI(inode->i_sb)->root;
398c2ecf20Sopenharmony_ci	sf_handle->access_flags = access_flags;
408c2ecf20Sopenharmony_ci	kref_init(&sf_handle->refcount);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	mutex_lock(&sf_i->handle_list_mutex);
438c2ecf20Sopenharmony_ci	list_add(&sf_handle->head, &sf_i->handle_list);
448c2ecf20Sopenharmony_ci	mutex_unlock(&sf_i->handle_list_mutex);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	return sf_handle;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic int vboxsf_file_open(struct inode *inode, struct file *file)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb);
528c2ecf20Sopenharmony_ci	struct shfl_createparms params = {};
538c2ecf20Sopenharmony_ci	struct vboxsf_handle *sf_handle;
548c2ecf20Sopenharmony_ci	u32 access_flags = 0;
558c2ecf20Sopenharmony_ci	int err;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	/*
588c2ecf20Sopenharmony_ci	 * We check the value of params.handle afterwards to find out if
598c2ecf20Sopenharmony_ci	 * the call succeeded or failed, as the API does not seem to cleanly
608c2ecf20Sopenharmony_ci	 * distinguish error and informational messages.
618c2ecf20Sopenharmony_ci	 *
628c2ecf20Sopenharmony_ci	 * Furthermore, we must set params.handle to SHFL_HANDLE_NIL to
638c2ecf20Sopenharmony_ci	 * make the shared folders host service use our mode parameter.
648c2ecf20Sopenharmony_ci	 */
658c2ecf20Sopenharmony_ci	params.handle = SHFL_HANDLE_NIL;
668c2ecf20Sopenharmony_ci	if (file->f_flags & O_CREAT) {
678c2ecf20Sopenharmony_ci		params.create_flags |= SHFL_CF_ACT_CREATE_IF_NEW;
688c2ecf20Sopenharmony_ci		/*
698c2ecf20Sopenharmony_ci		 * We ignore O_EXCL, as the Linux kernel seems to call create
708c2ecf20Sopenharmony_ci		 * beforehand itself, so O_EXCL should always fail.
718c2ecf20Sopenharmony_ci		 */
728c2ecf20Sopenharmony_ci		if (file->f_flags & O_TRUNC)
738c2ecf20Sopenharmony_ci			params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
748c2ecf20Sopenharmony_ci		else
758c2ecf20Sopenharmony_ci			params.create_flags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
768c2ecf20Sopenharmony_ci	} else {
778c2ecf20Sopenharmony_ci		params.create_flags |= SHFL_CF_ACT_FAIL_IF_NEW;
788c2ecf20Sopenharmony_ci		if (file->f_flags & O_TRUNC)
798c2ecf20Sopenharmony_ci			params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	switch (file->f_flags & O_ACCMODE) {
838c2ecf20Sopenharmony_ci	case O_RDONLY:
848c2ecf20Sopenharmony_ci		access_flags |= SHFL_CF_ACCESS_READ;
858c2ecf20Sopenharmony_ci		break;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	case O_WRONLY:
888c2ecf20Sopenharmony_ci		access_flags |= SHFL_CF_ACCESS_WRITE;
898c2ecf20Sopenharmony_ci		break;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	case O_RDWR:
928c2ecf20Sopenharmony_ci		access_flags |= SHFL_CF_ACCESS_READWRITE;
938c2ecf20Sopenharmony_ci		break;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	default:
968c2ecf20Sopenharmony_ci		WARN_ON(1);
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (file->f_flags & O_APPEND)
1008c2ecf20Sopenharmony_ci		access_flags |= SHFL_CF_ACCESS_APPEND;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	params.create_flags |= access_flags;
1038c2ecf20Sopenharmony_ci	params.info.attr.mode = inode->i_mode;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	err = vboxsf_create_at_dentry(file_dentry(file), &params);
1068c2ecf20Sopenharmony_ci	if (err == 0 && params.handle == SHFL_HANDLE_NIL)
1078c2ecf20Sopenharmony_ci		err = (params.result == SHFL_FILE_EXISTS) ? -EEXIST : -ENOENT;
1088c2ecf20Sopenharmony_ci	if (err)
1098c2ecf20Sopenharmony_ci		return err;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	sf_handle = vboxsf_create_sf_handle(inode, params.handle, access_flags);
1128c2ecf20Sopenharmony_ci	if (IS_ERR(sf_handle)) {
1138c2ecf20Sopenharmony_ci		vboxsf_close(sbi->root, params.handle);
1148c2ecf20Sopenharmony_ci		return PTR_ERR(sf_handle);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	file->private_data = sf_handle;
1188c2ecf20Sopenharmony_ci	return 0;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic void vboxsf_handle_release(struct kref *refcount)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct vboxsf_handle *sf_handle =
1248c2ecf20Sopenharmony_ci		container_of(refcount, struct vboxsf_handle, refcount);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	vboxsf_close(sf_handle->root, sf_handle->handle);
1278c2ecf20Sopenharmony_ci	kfree(sf_handle);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_civoid vboxsf_release_sf_handle(struct inode *inode, struct vboxsf_handle *sf_handle)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct vboxsf_inode *sf_i = VBOXSF_I(inode);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	mutex_lock(&sf_i->handle_list_mutex);
1358c2ecf20Sopenharmony_ci	list_del(&sf_handle->head);
1368c2ecf20Sopenharmony_ci	mutex_unlock(&sf_i->handle_list_mutex);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	kref_put(&sf_handle->refcount, vboxsf_handle_release);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic int vboxsf_file_release(struct inode *inode, struct file *file)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	/*
1448c2ecf20Sopenharmony_ci	 * When a file is closed on our (the guest) side, we want any subsequent
1458c2ecf20Sopenharmony_ci	 * accesses done on the host side to see all changes done from our side.
1468c2ecf20Sopenharmony_ci	 */
1478c2ecf20Sopenharmony_ci	filemap_write_and_wait(inode->i_mapping);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	vboxsf_release_sf_handle(inode, file->private_data);
1508c2ecf20Sopenharmony_ci	return 0;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci/*
1548c2ecf20Sopenharmony_ci * Write back dirty pages now, because there may not be any suitable
1558c2ecf20Sopenharmony_ci * open files later
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_cistatic void vboxsf_vma_close(struct vm_area_struct *vma)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	filemap_write_and_wait(vma->vm_file->f_mapping);
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic const struct vm_operations_struct vboxsf_file_vm_ops = {
1638c2ecf20Sopenharmony_ci	.close		= vboxsf_vma_close,
1648c2ecf20Sopenharmony_ci	.fault		= filemap_fault,
1658c2ecf20Sopenharmony_ci	.map_pages	= filemap_map_pages,
1668c2ecf20Sopenharmony_ci};
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic int vboxsf_file_mmap(struct file *file, struct vm_area_struct *vma)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	int err;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	err = generic_file_mmap(file, vma);
1738c2ecf20Sopenharmony_ci	if (!err)
1748c2ecf20Sopenharmony_ci		vma->vm_ops = &vboxsf_file_vm_ops;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	return err;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/*
1808c2ecf20Sopenharmony_ci * Note that since we are accessing files on the host's filesystem, files
1818c2ecf20Sopenharmony_ci * may always be changed underneath us by the host!
1828c2ecf20Sopenharmony_ci *
1838c2ecf20Sopenharmony_ci * The vboxsf API between the guest and the host does not offer any functions
1848c2ecf20Sopenharmony_ci * to deal with this. There is no inode-generation to check for changes, no
1858c2ecf20Sopenharmony_ci * events / callback on changes and no way to lock files.
1868c2ecf20Sopenharmony_ci *
1878c2ecf20Sopenharmony_ci * To avoid returning stale data when a file gets *opened* on our (the guest)
1888c2ecf20Sopenharmony_ci * side, we do a "stat" on the host side, then compare the mtime with the
1898c2ecf20Sopenharmony_ci * last known mtime and invalidate the page-cache if they differ.
1908c2ecf20Sopenharmony_ci * This is done from vboxsf_inode_revalidate().
1918c2ecf20Sopenharmony_ci *
1928c2ecf20Sopenharmony_ci * When reads are done through the read_iter fop, it is possible to do
1938c2ecf20Sopenharmony_ci * further cache revalidation then, there are 3 options to deal with this:
1948c2ecf20Sopenharmony_ci *
1958c2ecf20Sopenharmony_ci * 1)  Rely solely on the revalidation done at open time
1968c2ecf20Sopenharmony_ci * 2)  Do another "stat" and compare mtime again. Unfortunately the vboxsf
1978c2ecf20Sopenharmony_ci *     host API does not allow stat on handles, so we would need to use
1988c2ecf20Sopenharmony_ci *     file->f_path.dentry and the stat will then fail if the file was unlinked
1998c2ecf20Sopenharmony_ci *     or renamed (and there is no thing like NFS' silly-rename). So we get:
2008c2ecf20Sopenharmony_ci * 2a) "stat" and compare mtime, on stat failure invalidate the cache
2018c2ecf20Sopenharmony_ci * 2b) "stat" and compare mtime, on stat failure do nothing
2028c2ecf20Sopenharmony_ci * 3)  Simply always call invalidate_inode_pages2_range on the range of the read
2038c2ecf20Sopenharmony_ci *
2048c2ecf20Sopenharmony_ci * Currently we are keeping things KISS and using option 1. this allows
2058c2ecf20Sopenharmony_ci * directly using generic_file_read_iter without wrapping it.
2068c2ecf20Sopenharmony_ci *
2078c2ecf20Sopenharmony_ci * This means that only data written on the host side before open() on
2088c2ecf20Sopenharmony_ci * the guest side is guaranteed to be seen by the guest. If necessary
2098c2ecf20Sopenharmony_ci * we may provide other read-cache strategies in the future and make this
2108c2ecf20Sopenharmony_ci * configurable through a mount option.
2118c2ecf20Sopenharmony_ci */
2128c2ecf20Sopenharmony_ciconst struct file_operations vboxsf_reg_fops = {
2138c2ecf20Sopenharmony_ci	.llseek = generic_file_llseek,
2148c2ecf20Sopenharmony_ci	.read_iter = generic_file_read_iter,
2158c2ecf20Sopenharmony_ci	.write_iter = generic_file_write_iter,
2168c2ecf20Sopenharmony_ci	.mmap = vboxsf_file_mmap,
2178c2ecf20Sopenharmony_ci	.open = vboxsf_file_open,
2188c2ecf20Sopenharmony_ci	.release = vboxsf_file_release,
2198c2ecf20Sopenharmony_ci	.fsync = noop_fsync,
2208c2ecf20Sopenharmony_ci	.splice_read = generic_file_splice_read,
2218c2ecf20Sopenharmony_ci};
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ciconst struct inode_operations vboxsf_reg_iops = {
2248c2ecf20Sopenharmony_ci	.getattr = vboxsf_getattr,
2258c2ecf20Sopenharmony_ci	.setattr = vboxsf_setattr
2268c2ecf20Sopenharmony_ci};
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int vboxsf_readpage(struct file *file, struct page *page)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct vboxsf_handle *sf_handle = file->private_data;
2318c2ecf20Sopenharmony_ci	loff_t off = page_offset(page);
2328c2ecf20Sopenharmony_ci	u32 nread = PAGE_SIZE;
2338c2ecf20Sopenharmony_ci	u8 *buf;
2348c2ecf20Sopenharmony_ci	int err;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	buf = kmap(page);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	err = vboxsf_read(sf_handle->root, sf_handle->handle, off, &nread, buf);
2398c2ecf20Sopenharmony_ci	if (err == 0) {
2408c2ecf20Sopenharmony_ci		memset(&buf[nread], 0, PAGE_SIZE - nread);
2418c2ecf20Sopenharmony_ci		flush_dcache_page(page);
2428c2ecf20Sopenharmony_ci		SetPageUptodate(page);
2438c2ecf20Sopenharmony_ci	} else {
2448c2ecf20Sopenharmony_ci		SetPageError(page);
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	kunmap(page);
2488c2ecf20Sopenharmony_ci	unlock_page(page);
2498c2ecf20Sopenharmony_ci	return err;
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic struct vboxsf_handle *vboxsf_get_write_handle(struct vboxsf_inode *sf_i)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct vboxsf_handle *h, *sf_handle = NULL;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	mutex_lock(&sf_i->handle_list_mutex);
2578c2ecf20Sopenharmony_ci	list_for_each_entry(h, &sf_i->handle_list, head) {
2588c2ecf20Sopenharmony_ci		if (h->access_flags == SHFL_CF_ACCESS_WRITE ||
2598c2ecf20Sopenharmony_ci		    h->access_flags == SHFL_CF_ACCESS_READWRITE) {
2608c2ecf20Sopenharmony_ci			kref_get(&h->refcount);
2618c2ecf20Sopenharmony_ci			sf_handle = h;
2628c2ecf20Sopenharmony_ci			break;
2638c2ecf20Sopenharmony_ci		}
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci	mutex_unlock(&sf_i->handle_list_mutex);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return sf_handle;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int vboxsf_writepage(struct page *page, struct writeback_control *wbc)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct inode *inode = page->mapping->host;
2738c2ecf20Sopenharmony_ci	struct vboxsf_inode *sf_i = VBOXSF_I(inode);
2748c2ecf20Sopenharmony_ci	struct vboxsf_handle *sf_handle;
2758c2ecf20Sopenharmony_ci	loff_t off = page_offset(page);
2768c2ecf20Sopenharmony_ci	loff_t size = i_size_read(inode);
2778c2ecf20Sopenharmony_ci	u32 nwrite = PAGE_SIZE;
2788c2ecf20Sopenharmony_ci	u8 *buf;
2798c2ecf20Sopenharmony_ci	int err;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (off + PAGE_SIZE > size)
2828c2ecf20Sopenharmony_ci		nwrite = size & ~PAGE_MASK;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	sf_handle = vboxsf_get_write_handle(sf_i);
2858c2ecf20Sopenharmony_ci	if (!sf_handle)
2868c2ecf20Sopenharmony_ci		return -EBADF;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	buf = kmap(page);
2898c2ecf20Sopenharmony_ci	err = vboxsf_write(sf_handle->root, sf_handle->handle,
2908c2ecf20Sopenharmony_ci			   off, &nwrite, buf);
2918c2ecf20Sopenharmony_ci	kunmap(page);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	kref_put(&sf_handle->refcount, vboxsf_handle_release);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (err == 0) {
2968c2ecf20Sopenharmony_ci		ClearPageError(page);
2978c2ecf20Sopenharmony_ci		/* mtime changed */
2988c2ecf20Sopenharmony_ci		sf_i->force_restat = 1;
2998c2ecf20Sopenharmony_ci	} else {
3008c2ecf20Sopenharmony_ci		ClearPageUptodate(page);
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	unlock_page(page);
3048c2ecf20Sopenharmony_ci	return err;
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic int vboxsf_write_end(struct file *file, struct address_space *mapping,
3088c2ecf20Sopenharmony_ci			    loff_t pos, unsigned int len, unsigned int copied,
3098c2ecf20Sopenharmony_ci			    struct page *page, void *fsdata)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct inode *inode = mapping->host;
3128c2ecf20Sopenharmony_ci	struct vboxsf_handle *sf_handle = file->private_data;
3138c2ecf20Sopenharmony_ci	unsigned int from = pos & ~PAGE_MASK;
3148c2ecf20Sopenharmony_ci	u32 nwritten = len;
3158c2ecf20Sopenharmony_ci	u8 *buf;
3168c2ecf20Sopenharmony_ci	int err;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* zero the stale part of the page if we did a short copy */
3198c2ecf20Sopenharmony_ci	if (!PageUptodate(page) && copied < len)
3208c2ecf20Sopenharmony_ci		zero_user(page, from + copied, len - copied);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	buf = kmap(page);
3238c2ecf20Sopenharmony_ci	err = vboxsf_write(sf_handle->root, sf_handle->handle,
3248c2ecf20Sopenharmony_ci			   pos, &nwritten, buf + from);
3258c2ecf20Sopenharmony_ci	kunmap(page);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (err) {
3288c2ecf20Sopenharmony_ci		nwritten = 0;
3298c2ecf20Sopenharmony_ci		goto out;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	/* mtime changed */
3338c2ecf20Sopenharmony_ci	VBOXSF_I(inode)->force_restat = 1;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (!PageUptodate(page) && nwritten == PAGE_SIZE)
3368c2ecf20Sopenharmony_ci		SetPageUptodate(page);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	pos += nwritten;
3398c2ecf20Sopenharmony_ci	if (pos > inode->i_size)
3408c2ecf20Sopenharmony_ci		i_size_write(inode, pos);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ciout:
3438c2ecf20Sopenharmony_ci	unlock_page(page);
3448c2ecf20Sopenharmony_ci	put_page(page);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return nwritten;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci/*
3508c2ecf20Sopenharmony_ci * Note simple_write_begin does not read the page from disk on partial writes
3518c2ecf20Sopenharmony_ci * this is ok since vboxsf_write_end only writes the written parts of the
3528c2ecf20Sopenharmony_ci * page and it does not call SetPageUptodate for partial writes.
3538c2ecf20Sopenharmony_ci */
3548c2ecf20Sopenharmony_ciconst struct address_space_operations vboxsf_reg_aops = {
3558c2ecf20Sopenharmony_ci	.readpage = vboxsf_readpage,
3568c2ecf20Sopenharmony_ci	.writepage = vboxsf_writepage,
3578c2ecf20Sopenharmony_ci	.set_page_dirty = __set_page_dirty_nobuffers,
3588c2ecf20Sopenharmony_ci	.write_begin = simple_write_begin,
3598c2ecf20Sopenharmony_ci	.write_end = vboxsf_write_end,
3608c2ecf20Sopenharmony_ci};
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic const char *vboxsf_get_link(struct dentry *dentry, struct inode *inode,
3638c2ecf20Sopenharmony_ci				   struct delayed_call *done)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb);
3668c2ecf20Sopenharmony_ci	struct shfl_string *path;
3678c2ecf20Sopenharmony_ci	char *link;
3688c2ecf20Sopenharmony_ci	int err;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (!dentry)
3718c2ecf20Sopenharmony_ci		return ERR_PTR(-ECHILD);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	path = vboxsf_path_from_dentry(sbi, dentry);
3748c2ecf20Sopenharmony_ci	if (IS_ERR(path))
3758c2ecf20Sopenharmony_ci		return ERR_CAST(path);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	link = kzalloc(PATH_MAX, GFP_KERNEL);
3788c2ecf20Sopenharmony_ci	if (!link) {
3798c2ecf20Sopenharmony_ci		__putname(path);
3808c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	err = vboxsf_readlink(sbi->root, path, PATH_MAX, link);
3848c2ecf20Sopenharmony_ci	__putname(path);
3858c2ecf20Sopenharmony_ci	if (err) {
3868c2ecf20Sopenharmony_ci		kfree(link);
3878c2ecf20Sopenharmony_ci		return ERR_PTR(err);
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	set_delayed_call(done, kfree_link, link);
3918c2ecf20Sopenharmony_ci	return link;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ciconst struct inode_operations vboxsf_lnk_iops = {
3958c2ecf20Sopenharmony_ci	.get_link = vboxsf_get_link
3968c2ecf20Sopenharmony_ci};
397