7bb8e57c34db069013b5348ff72a260d10c41ad1vboxsync * vboxsf - VBox Linux Shared Folders, Regular file inode and file operations.
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2012 Oracle Corporation
13fdd42f1fc3e519650037a920e6a54c24973866vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
13fdd42f1fc3e519650037a920e6a54c24973866vboxsync * available from http://www.virtualbox.org. This file is free software;
13fdd42f1fc3e519650037a920e6a54c24973866vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
13fdd42f1fc3e519650037a920e6a54c24973866vboxsync * Limitations: only COW memory mapping is supported
7bb8e57c34db069013b5348ff72a260d10c41ad1vboxsyncstatic void *alloc_bounce_buffer(size_t *tmp_sizep, PRTCCPHYS physp, size_t
7ca4727ba2f9e3703771a308b11cd551f3fca4fdvboxsync /* try for big first. */
7ca4727ba2f9e3703771a308b11cd551f3fca4fdvboxsync /* fall back on a page sized buffer. */
7ca4727ba2f9e3703771a308b11cd551f3fca4fdvboxsync LogRel(("%s: could not allocate bounce buffer for xfer_size=%zu %s\n", caller, xfer_size));
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic int sf_reg_read_aux(const char *caller, struct sf_glob_info *sf_g,
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync /** @todo bird: yes, kmap() and kmalloc() input only. Since the buffer is
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * contiguous in physical memory (kmalloc or single page), we should
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * use a physical address here to speed things up. */
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync int rc = vboxCallRead(&client_handle, &sf_g->map, sf_r->handle,
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync LogFunc(("vboxCallRead failed. caller=%s, rc=%Rrc\n", caller, rc));
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic int sf_reg_write_aux(const char *caller, struct sf_glob_info *sf_g,
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync /** @todo bird: yes, kmap() and kmalloc() input only. Since the buffer is
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * contiguous in physical memory (kmalloc or single page), we should
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * use a physical address here to speed things up. */
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync int rc = vboxCallWrite(&client_handle, &sf_g->map, sf_r->handle,
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync LogFunc(("vboxCallWrite failed. caller=%s, rc=%Rrc\n",
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * Read from a regular file.
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param file the file
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param buf the buffer
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param size length of the buffer
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param off offset within the file
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @returns the number of read bytes on success, Linux error code otherwise
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic ssize_t sf_reg_read(struct file *file, char *buf, size_t size, loff_t *off)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync LogFunc(("read from non regular file %d\n", inode->i_mode));
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /** XXX Check read permission according to inode->i_mode! */
7bb8e57c34db069013b5348ff72a260d10c41ad1vboxsync tmp = alloc_bounce_buffer(&tmp_size, &tmp_phys, size, __PRETTY_FUNCTION__);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync err = sf_reg_read_aux(__func__, sf_g, sf_r, tmp, &nread, pos);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * Write to a regular file.
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param file the file
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param buf the buffer
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param size length of the buffer
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param off offset within the file
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @returns the number of written bytes on success, Linux error code otherwise
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic ssize_t sf_reg_write(struct file *file, const char *buf, size_t size, loff_t *off)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync LogFunc(("write to non regular file %d\n", inode->i_mode));
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /** XXX Check write permission according to inode->i_mode! */
7bb8e57c34db069013b5348ff72a260d10c41ad1vboxsync tmp = alloc_bounce_buffer(&tmp_size, &tmp_phys, size, __PRETTY_FUNCTION__);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync err = VbglR0SfWritePhysCont(&client_handle, &sf_g->map, sf_r->handle,
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync err = sf_reg_write_aux(__func__, sf_g, sf_r, tmp, &nwritten, pos);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * Open a regular file.
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param inode the inode
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param file the file
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @returns 0 on success, Linux error code otherwise
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic int sf_reg_open(struct inode *inode, struct file *file)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync /* Already open? */
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * This inode was created with sf_create_aux(). Check the CreateFlags:
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * O_CREAT, O_TRUNC: inherent true (file was just created). Not sure
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * about the access flags (SHFL_CF_ACCESS_*).
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync /* We check the value of params.Handle afterwards to find out if
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * the call succeeded or failed, as the API does not seem to cleanly
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * distinguish error and informational messages.
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * Furthermore, we must set params.Handle to SHFL_HANDLE_NIL to
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * make the shared folders host service use our fMode parameter */
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync /* We ignore O_EXCL, as the Linux kernel seems to call create
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync beforehand itself, so O_EXCL should always fail. */
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync params.CreateFlags |= ( SHFL_CF_ACT_OVERWRITE_IF_EXISTS
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync params.CreateFlags |= ( SHFL_CF_ACT_OVERWRITE_IF_EXISTS
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync if (!(params.CreateFlags & SHFL_CF_ACCESS_READWRITE))
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync LogFunc(("sf_reg_open: calling vboxCallCreate, file %s, flags=%#x, %#x\n",
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync sf_i->path->String.utf8 , file->f_flags, params.CreateFlags));
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync rc = vboxCallCreate(&client_handle, &sf_g->map, sf_i->path, ¶ms);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync LogFunc(("vboxCallCreate failed flags=%d,%#x rc=%Rrc\n",
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * Close a regular file.
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param inode the inode
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @param file the file
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync * @returns 0 on success, Linux error code otherwise
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic int sf_reg_release(struct inode *inode, struct file *file)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
d34b48c33206883798ebbcf53ad8a3b9d81b9b43vboxsync /* See the smbfs source (file.c). mmap in particular can cause data to be
ea9a25c873380b5352595e122e40a3a6935e4ca1vboxsync * written to the file after it is closed, which we can't cope with. We
ea9a25c873380b5352595e122e40a3a6935e4ca1vboxsync * copy and paste the body of filemap_write_and_wait() here as it was not
ea9a25c873380b5352595e122e40a3a6935e4ca1vboxsync * defined before 2.6.6 and not exported until quite a bit later. */
ea9a25c873380b5352595e122e40a3a6935e4ca1vboxsync /* filemap_write_and_wait(inode->i_mapping); */
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync rc = vboxCallClose(&client_handle, &sf_g->map, sf_r->handle);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic int sf_reg_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic struct page *sf_reg_nopage(struct vm_area_struct *vma, unsigned long vaddr, int *type)
335339b2f047d0cc077224d3d724b2c3b1a6a383vboxsync#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic struct page *sf_reg_nopage(struct vm_area_struct *vma, unsigned long vaddr, int unused)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
1bf70aeaad14c047c2b006602463761663c0a61dvboxsync /* Don't use GFP_HIGHUSER as long as sf_reg_read_aux() calls vboxCallRead()
1bf70aeaad14c047c2b006602463761663c0a61dvboxsync * which works on virtual addresses. On Linux cannot reliably determine the
1bf70aeaad14c047c2b006602463761663c0a61dvboxsync * physical address for high memory, see rtR0MemObjNativeLockKernel(). */
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync off = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync err = sf_reg_read_aux(__func__, sf_g, sf_r, buf, &nread, off);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync clear_user_page(page_address(page), vmf->pgoff, page);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic int sf_reg_mmap(struct file *file, struct vm_area_struct *vma)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncstatic int sf_readpage(struct file *file, struct page *page)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync ret = sf_reg_read_aux(__func__, sf_g, sf_r, buf, &nread, off);
9afa6c5f4f1d021b1c7d066967ed02037fb14c42vboxsyncsf_writepage(struct page *page, struct writeback_control *wbc)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync err = sf_reg_write_aux(__func__, sf_g, sf_r, buf, &nwritten, off);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncint sf_write_begin(struct file *file, struct address_space *mapping, loff_t pos,
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync unsigned len, unsigned flags, struct page **pagep, void **fsdata)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync return simple_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsyncint sf_write_end(struct file *file, struct address_space *mapping, loff_t pos,
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync unsigned len, unsigned copied, struct page *page, void *fsdata)
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync err = sf_reg_write_aux(__func__, sf_g, sf_r, buf+from, &nwritten, pos);
60d03c38311c6e4c34add74be472fe2098f52d6evboxsync if (err >= 0) {
9afa6c5f4f1d021b1c7d066967ed02037fb14c42vboxsync# endif /* KERNEL_VERSION >= 2.6.24 */