I have made the following changes intended for : CE:Adaptation:x86-generic / virtualbox
Please review and accept or decline. BOSS has already run some checks on this request. See the "Messages from BOSS" section below. https://build.pub.meego.com//request/show/7849 Thank You, rbraakman [This message was auto-generated] --- Request # 7849: Messages from BOSS: WARNING check_package_is_complete_sources (virtualbox) failed: No dsc file found Extra source files: boss.conf, vbox-slow-logging.diff, virtualbox.changes_suse. State: review at 2013-02-11T19:22:58 by bossbot Reviews: accepted by bossbot : Prechecks succeeded. new for CE-maintainers : Please replace this text with a review and approve/reject the review (not the SR). BOSS will take care of the rest Changes: submit: home:rbraakman:branches:CE:Adaptation:x86-generic / virtualbox -> CE:Adaptation:x86-generic / virtualbox changes files: -------------- --- virtualbox.changes +++ virtualbox.changes @@ -0,0 +1,8 @@ +* Fri Feb 01 2013 Richard Braakman <[email protected]> - 4.2.4 +- Ensure build failure if guest modules do not compile +- [vboxsf] + Bugfixes to shared folders module + Enable writable mmap (needed by zypper, building kernel, probably more) + Performance improvements, it is now about 40% slower than guest-native + Use page cache when reading + new: ---- vbox-handles.diff vbox-less-restat.diff vbox-mmap-02.diff vbox-mmap.diff vbox-pagecache.diff vbox-physread.diff vbox-readpages.diff vbox-slow-logging.diff spec files: ----------- --- virtualbox.spec +++ virtualbox.spec @@ -109,6 +109,13 @@ Patch103: vbox-disable-updates.diff #use pie/fPIE for setuid binaries (bnc#743143) Patch104: vbox-fpie.diff +Patch201: vbox-less-restat.diff +Patch202: vbox-handles.diff +Patch203: vbox-physread.diff +Patch204: vbox-mmap.diff +Patch205: vbox-mmap-02.diff +Patch206: vbox-pagecache.diff +Patch207: vbox-readpages.diff BuildRoot: %{_tmppath}/%{name}-%{version}-build #PreReq: pwdutils permissions Requires: %{name}-host-kmp = %version @@ -171,7 +178,13 @@ #Y%patch101 %patch103 %patch104 -p1 -#Y%patch105 -p1 +%patch201 -p1 +%patch202 -p1 +%patch203 -p1 +%patch204 -p1 +%patch205 -p1 +%patch206 -p1 +%patch207 -p1 #copy user manual %__cp %{S:1} UserManual.pdf #copy kbuild config @@ -258,6 +271,11 @@ for module_name in modules_build_dir/*/. do %__make -C $KERNEL_DIR modules_install M=$(dirname $PWD/$module_name) + if [ ! -f "$INSTALL_MOD_PATH"/lib/modules/*/vbox/$(basename $(dirname $module_name)).* ] + then + echo "Failed to build $module_name" + exit 1 + fi done # Clean up spurious stuff rm -f %{buildroot}/lib/modules/*/modules.* other changes: -------------- ++++++ vbox-handles.diff (new) --- vbox-handles.diff +++ vbox-handles.diff @@ -0,0 +1,215 @@ +commit 3fbf480c55f1a6e7049d333c48fdb0ecb550e99b +Author: Richard Braakman <[email protected]> +Date: Thu Jan 31 01:15:25 2013 +0200 + + vboxsf: make sure writepage still works after concurrent open/close + +diff --git a/src/VBox/Additions/linux/sharedfolders/dirops.c b/src/VBox/Additions/linux/sharedfolders/dirops.c +index d0d7b85..5e32135 100644 +--- a/src/VBox/Additions/linux/sharedfolders/dirops.c ++++ b/src/VBox/Additions/linux/sharedfolders/dirops.c +@@ -358,8 +358,10 @@ static struct dentry *sf_lookup(struct inode *parent, struct dentry *dentry + err = -ENOMEM; + goto fail1; + } ++ INIT_LIST_HEAD(&sf_new_i->handles); + sf_new_i->handle = SHFL_HANDLE_NIL; + sf_new_i->force_reread = 0; ++ sf_new_i->force_restat = 0; + + ino = iunique(parent->i_sb, 1); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25) +@@ -458,6 +460,7 @@ static int sf_instantiate(struct inode *parent, struct dentry *dentry, + #else + dentry->d_op = &sf_dentry_ops; + #endif ++ INIT_LIST_HEAD(&sf_new_i->handles); + sf_new_i->force_restat = 0; + sf_new_i->force_reread = 0; + +diff --git a/src/VBox/Additions/linux/sharedfolders/regops.c b/src/VBox/Additions/linux/sharedfolders/regops.c +index 1ba03e3..db1641b 100644 +--- a/src/VBox/Additions/linux/sharedfolders/regops.c ++++ b/src/VBox/Additions/linux/sharedfolders/regops.c +@@ -294,21 +294,6 @@ static int sf_reg_open(struct inode *inode, struct file *file) + return -ENOMEM; + } + +- /* Already open? */ +- if (sf_i->handle != SHFL_HANDLE_NIL) +- { +- /* +- * This inode was created with sf_create_aux(). Check the CreateFlags: +- * O_CREAT, O_TRUNC: inherent true (file was just created). Not sure +- * about the access flags (SHFL_CF_ACCESS_*). +- */ +- sf_r->handle = sf_i->handle; +- sf_i->handle = SHFL_HANDLE_NIL; +- sf_i->file = file; +- file->private_data = sf_r; +- return 0; +- } +- + RT_ZERO(params); + params.Handle = SHFL_HANDLE_NIL; + /* We check the value of params.Handle afterwards to find out if +@@ -371,6 +356,19 @@ static int sf_reg_open(struct inode *inode, struct file *file) + params.CreateFlags |= SHFL_CF_ACCESS_APPEND; + } + ++ /* Already open? */ ++ if (sf_i->handle != SHFL_HANDLE_NIL) ++ { ++ /* ++ * This inode was created with sf_create_aux(). Check the CreateFlags: ++ * O_CREAT, O_TRUNC: inherent true (file was just created). Not sure ++ * about the access flags (SHFL_CF_ACCESS_*). ++ */ ++ sf_r->handle = sf_i->handle; ++ sf_i->handle = SHFL_HANDLE_NIL; ++ goto out; ++ } ++ + params.Info.Attr.fMode = inode->i_mode; + LogFunc(("sf_reg_open: calling vboxCallCreate, file %s, flags=%#x, %#x\n", + sf_i->path->String.utf8 , file->f_flags, params.CreateFlags)); +@@ -404,7 +402,10 @@ static int sf_reg_open(struct inode *inode, struct file *file) + sf_init_inode(sf_g, inode, ¶ms.Info); + + sf_r->handle = params.Handle; +- sf_i->file = file; ++ out: ++ sf_r->createflags = params.CreateFlags; ++ INIT_LIST_HEAD(&sf_r->head); ++ list_add(&sf_r->head, &sf_i->handles); + file->private_data = sf_r; + return rc_linux; + } +@@ -440,14 +441,16 @@ static int sf_reg_release(struct inode *inode, struct file *file) + && filemap_fdatawrite(inode->i_mapping) != -EIO) + filemap_fdatawait(inode->i_mapping); + #endif ++ ++ list_del(&sf_r->head); ++ + rc = vboxCallClose(&client_handle, &sf_g->map, sf_r->handle); + if (RT_FAILURE(rc)) + LogFunc(("vboxCallClose failed rc=%Rrc\n", rc)); + +- kfree(sf_r); +- sf_i->file = NULL; + sf_i->handle = SHFL_HANDLE_NIL; + file->private_data = NULL; ++ kfree(sf_r); + return 0; + } + +@@ -600,6 +603,26 @@ struct inode_operations sf_reg_iops = + + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++/* Helper function to pick a suitable handle for pagecache operations. ++ * It picks the most recently opened handle for this inode that has the ++ * requested flags (SHFL_CF_ACCESS_READ or SHFL_CF_ACCESS_WRITE). ++ * Handles with SHFL_CF_ACCESS_APPEND are not suitable for paged use ++ * so they are always skipped. ++ */ ++static struct sf_reg_info *sf_select_handle(struct inode *inode, u32 flags) ++{ ++ struct sf_inode_info *sf_i = GET_INODE_INFO(inode); ++ struct sf_reg_info *sf_r; ++ ++ list_for_each_entry(sf_r, &sf_i->handles, head) ++ { ++ if ( sf_r->handle != SHFL_HANDLE_NIL ++ && (sf_r->createflags & (flags | SHFL_CF_ACCESS_APPEND)) == flags) ++ return sf_r; ++ } ++ return NULL; ++} ++ + static int sf_readpage(struct file *file, struct page *page) + { + struct inode *inode = file->f_dentry->d_inode; +@@ -636,9 +659,7 @@ sf_writepage(struct page *page, struct writeback_control *wbc) + struct address_space *mapping = page->mapping; + struct inode *inode = mapping->host; + struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb); +- struct sf_inode_info *sf_i = GET_INODE_INFO(inode); +- struct file *file = sf_i->file; +- struct sf_reg_info *sf_r = file->private_data; ++ struct sf_reg_info *sf_r; + char *buf; + uint32_t nwritten = PAGE_SIZE; + int end_index = inode->i_size >> PAGE_SHIFT; +@@ -647,6 +668,15 @@ sf_writepage(struct page *page, struct writeback_control *wbc) + + TRACE(); + ++ sf_r = sf_select_handle(inode, SHFL_CF_ACCESS_WRITE); ++ if (unlikely(!sf_r)) ++ { ++ /* At least the handle of whoever wrote to the page should ++ * still be available; see the wait in sf_reg_release() */ ++ WARN_ONCE(1, "vboxsf: could not find handle for writepage"); ++ return -EBADF; ++ } ++ + if (page->index >= end_index) + nwritten = inode->i_size & (PAGE_SIZE-1); + +diff --git a/src/VBox/Additions/linux/sharedfolders/vfsmod.c b/src/VBox/Additions/linux/sharedfolders/vfsmod.c +index 3c55136..79097c5 100644 +--- a/src/VBox/Additions/linux/sharedfolders/vfsmod.c ++++ b/src/VBox/Additions/linux/sharedfolders/vfsmod.c +@@ -237,6 +237,7 @@ static int sf_read_super_aux(struct super_block *sb, void *data, int flags) + goto fail1; + } + ++ INIT_LIST_HEAD(&sf_i->handles); + sf_i->handle = SHFL_HANDLE_NIL; + sf_i->path = kmalloc(sizeof(SHFLSTRING) + 1, GFP_KERNEL); + if (!sf_i->path) +@@ -372,6 +373,7 @@ static void sf_clear_inode(struct inode *inode) + if (!sf_i) + return; + ++ WARN_ON(!list_empty(&sf_i->handles)); + BUG_ON(!sf_i->path); + kfree(sf_i->path); + kfree(sf_i); +@@ -394,6 +396,7 @@ static void sf_evict_inode(struct inode *inode) + if (!sf_i) + return; + ++ WARN_ON(!list_empty(&sf_i->handles)); + BUG_ON(!sf_i->path); + kfree(sf_i->path); + kfree(sf_i); +diff --git a/src/VBox/Additions/linux/sharedfolders/vfsmod.h b/src/VBox/Additions/linux/sharedfolders/vfsmod.h +index 6a20eb7..c7df740 100644 +--- a/src/VBox/Additions/linux/sharedfolders/vfsmod.h ++++ b/src/VBox/Additions/linux/sharedfolders/vfsmod.h +@@ -58,11 +58,11 @@ struct sf_inode_info + int force_restat; + /* directory content changed, update the whole directory on next sf_getdent */ + int force_reread; +- /* file structure, only valid between open() and release() */ +- struct file *file; + /* handle valid if a file was created with sf_create_aux until it will (16 more lines skipped) ++++++ vbox-less-restat.diff (new) --- vbox-less-restat.diff +++ vbox-less-restat.diff @@ -0,0 +1,71 @@ +commit bce05d945b143926548b8f8d289dfa3ec02f3788 +Author: Richard Braakman <[email protected]> +Date: Fri Jan 25 11:33:47 2013 +0200 + + linux sharedfolders: remove redundant statting + + There's no need to force a restat right after filling a new inode with stat + information. Also, open() can use the stat info it gets with the handle + instead of statting again. + + In addition, sf_inode_revalidate should actually set force_restat back to 0 + when statting. + +diff --git a/src/VBox/Additions/linux/sharedfolders/dirops.c b/src/VBox/Additions/linux/sharedfolders/dirops.c +index f7f558a..d0d7b85 100644 +--- a/src/VBox/Additions/linux/sharedfolders/dirops.c ++++ b/src/VBox/Additions/linux/sharedfolders/dirops.c +@@ -458,7 +458,7 @@ static int sf_instantiate(struct inode *parent, struct dentry *dentry, + #else + dentry->d_op = &sf_dentry_ops; + #endif +- sf_new_i->force_restat = 1; ++ sf_new_i->force_restat = 0; + sf_new_i->force_reread = 0; + + d_instantiate(dentry, inode); +diff --git a/src/VBox/Additions/linux/sharedfolders/regops.c b/src/VBox/Additions/linux/sharedfolders/regops.c +index 37adbcb..1ba03e3 100644 +--- a/src/VBox/Additions/linux/sharedfolders/regops.c ++++ b/src/VBox/Additions/linux/sharedfolders/regops.c +@@ -302,7 +302,6 @@ static int sf_reg_open(struct inode *inode, struct file *file) + * O_CREAT, O_TRUNC: inherent true (file was just created). Not sure + * about the access flags (SHFL_CF_ACCESS_*). + */ +- sf_i->force_restat = 1; + sf_r->handle = sf_i->handle; + sf_i->handle = SHFL_HANDLE_NIL; + sf_i->file = file; +@@ -378,6 +377,7 @@ static int sf_reg_open(struct inode *inode, struct file *file) + rc = vboxCallCreate(&client_handle, &sf_g->map, sf_i->path, ¶ms); + if (RT_FAILURE(rc)) + { ++ sf_i->force_restat = 1; + LogFunc(("vboxCallCreate failed flags=%d,%#x rc=%Rrc\n", + file->f_flags, params.CreateFlags, rc)); + kfree(sf_r); +@@ -398,9 +398,11 @@ static int sf_reg_open(struct inode *inode, struct file *file) + default: + break; + } ++ sf_i->force_restat = 1; + } ++ else ++ sf_init_inode(sf_g, inode, ¶ms.Info); + +- sf_i->force_restat = 1; + sf_r->handle = params.Handle; + sf_i->file = file; + file->private_data = sf_r; +diff --git a/src/VBox/Additions/linux/sharedfolders/utils.c b/src/VBox/Additions/linux/sharedfolders/utils.c +index aa9c396..7ba8276 100644 +--- a/src/VBox/Additions/linux/sharedfolders/utils.c ++++ b/src/VBox/Additions/linux/sharedfolders/utils.c +@@ -238,6 +238,7 @@ int sf_inode_revalidate(struct dentry *dentry) + return 0; + } + ++ sf_i->force_restat = 0; + err = sf_stat(__func__, sf_g, sf_i->path, &info, 1); + if (err) + return err; ++++++ vbox-mmap-02.diff (new) --- vbox-mmap-02.diff +++ vbox-mmap-02.diff @@ -0,0 +1,53 @@ +commit 7d8a6d68c286e3544645a54d5fcc14f1de7b16f4 +Author: Richard Braakman <[email protected]> +Date: Fri Feb 1 00:18:24 2013 +0200 + + sharedfolders bugfix: set access read/write even if some bits already set + + In sf_reg_open(), a file opened with O_TRUNC|O_RDWR wouldn't get the + SHFL_CF_ACCESS_READ flag because of the logic that skipped processing + the O_RDWR after seeing O_TRUNC. This is wrong, and it shows up with + the new pagecache code because the handle is not flagged as readable. + +diff --git a/src/VBox/Additions/linux/sharedfolders/regops.c b/src/VBox/Additions/linux/sharedfolders/regops.c +index c3b314e..c39fc97 100644 +--- a/src/VBox/Additions/linux/sharedfolders/regops.c ++++ b/src/VBox/Additions/linux/sharedfolders/regops.c +@@ -341,25 +341,22 @@ static int sf_reg_open(struct inode *inode, struct file *file) + } + } + +- if (!(params.CreateFlags & SHFL_CF_ACCESS_READWRITE)) ++ switch (file->f_flags & O_ACCMODE) + { +- switch (file->f_flags & O_ACCMODE) +- { +- case O_RDONLY: +- params.CreateFlags |= SHFL_CF_ACCESS_READ; +- break; ++ case O_RDONLY: ++ params.CreateFlags |= SHFL_CF_ACCESS_READ; ++ break; + +- case O_WRONLY: +- params.CreateFlags |= SHFL_CF_ACCESS_WRITE; +- break; ++ case O_WRONLY: ++ params.CreateFlags |= SHFL_CF_ACCESS_WRITE; ++ break; + +- case O_RDWR: +- params.CreateFlags |= SHFL_CF_ACCESS_READWRITE; +- break; ++ case O_RDWR: ++ params.CreateFlags |= SHFL_CF_ACCESS_READWRITE; ++ break; + +- default: +- BUG (); +- } ++ default: ++ BUG (); + } + + if (file->f_flags & O_APPEND) ++++++ vbox-mmap.diff (new) --- vbox-mmap.diff +++ vbox-mmap.diff @@ -0,0 +1,123 @@ +commit c1e45e725b91bc4e03d7e3acc94673ea7b16d762 +Author: Richard Braakman <[email protected]> +Date: Tue Jan 29 21:48:13 2013 +0200 + + [vboxsf] support writable mmap + + This is mainly so that guest processes can use the shared folder as a backing + for database files and such. Don't expect coherence if a file is simultaneously + mmapped on the host and guest sides. + +diff --git a/src/VBox/Additions/linux/sharedfolders/regops.c b/src/VBox/Additions/linux/sharedfolders/regops.c +index a0586bd..c3b314e 100644 +--- a/src/VBox/Additions/linux/sharedfolders/regops.c ++++ b/src/VBox/Additions/linux/sharedfolders/regops.c +@@ -16,7 +16,7 @@ + */ + + /* +- * Limitations: only COW memory mapping is supported ++ * Limitations: MAP_SHARED mmap does not notice changes made on the host. + */ + + #include "vfsmod.h" +@@ -501,7 +501,7 @@ static struct page *sf_reg_nopage(struct vm_area_struct *vma, unsigned long vadd + /* Don't use GFP_HIGHUSER as long as sf_reg_read_aux() calls vboxCallRead() + * which works on virtual addresses. On Linux cannot reliably determine the + * physical address for high memory, see rtR0MemObjNativeLockKernel(). */ +- page = alloc_page(GFP_USER); ++ page = find_or_create_page(inode->i_mapping, vmf->pgoff, GFP_USER); + if (!page) { + LogRelFunc(("failed to allocate page\n")); + #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) +@@ -522,7 +522,8 @@ static struct page *sf_reg_nopage(struct vm_area_struct *vma, unsigned long vadd + if (err) + { + kunmap(page); +- put_page(page); ++ unlock_page(page); ++ page_cache_release(page); + #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) + return VM_FAULT_SIGBUS; + #else +@@ -546,7 +547,9 @@ static struct page *sf_reg_nopage(struct vm_area_struct *vma, unsigned long vadd + memset(buf + nread, 0, PAGE_SIZE - nread); + + flush_dcache_page(page); ++ SetPageUptodate(page); + kunmap(page); ++ unlock_page(page); + #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) + vmf->page = page; + return 0; +@@ -556,24 +559,51 @@ static struct page *sf_reg_nopage(struct vm_area_struct *vma, unsigned long vadd + #endif + } + ++/** ++ * Prepare for a mmap page to be made writable. ++ * Check that the page is still there, and lock it if necessary to keep it there. ++ * Part of MAP_SHARED support. ++ * ++ * @returns VM_FAULT_LOCKED if the page is ready, otherwise VM_FAULT_NOPAGE. ++ */ ++static int sf_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ++{ ++ struct page *page = vmf->page; ++ struct inode *inode = vma->vm_file->f_path.dentry->d_inode; ++ loff_t size; ++ ++ TRACE(); ++ ++ lock_page(page); ++ size = i_size_read(inode); ++ if (page->mapping != inode->i_mapping || page_offset(page) > size) ++ { ++ /* file was truncated */ ++ unlock_page(page); ++ return VM_FAULT_NOPAGE; ++ } ++ ++ wait_on_page_writeback(page); ++ return VM_FAULT_LOCKED; ++} ++ + static struct vm_operations_struct sf_vma_ops = + { + #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25) +- .fault = sf_reg_fault ++ .fault = sf_reg_fault, + #else +- .nopage = sf_reg_nopage ++ .nopage = sf_reg_nopage, + #endif ++ .page_mkwrite = sf_page_mkwrite + }; + + static int sf_reg_mmap(struct file *file, struct vm_area_struct *vma) + { +- TRACE(); +- if (vma->vm_flags & VM_SHARED) +- { +- LogFunc(("shared mmapping not available\n")); +- return -EINVAL; +- } ++ struct sf_reg_info *sf_r = file->private_data; + ++ TRACE(); ++ if (sf_r->createflags & SHFL_CF_ACCESS_APPEND) ++ return -EINVAL; /* can't simulate page operations */ + vma->vm_ops = &sf_vma_ops; + return 0; + } +@@ -701,8 +731,8 @@ sf_writepage(struct page *page, struct writeback_control *wbc) + goto out; + } + +- if (off > inode->i_size) +- inode->i_size = off; ++ if (off + nwritten > inode->i_size) ++ inode->i_size = off + nwritten; + + if (PageError(page)) + ClearPageError(page); ++++++ vbox-pagecache.diff (new) --- vbox-pagecache.diff +++ vbox-pagecache.diff @@ -0,0 +1,205 @@ +commit ee6ca84b247485b40c375ebb7e29a046446374df +Author: Richard Braakman <[email protected]> +Date: Thu Jan 31 19:19:22 2013 +0200 + + sharedfolders: read() from page cache + +diff --git a/src/VBox/Additions/linux/sharedfolders/dirops.c b/src/VBox/Additions/linux/sharedfolders/dirops.c +index 5e32135..1ed25dc 100644 +--- a/src/VBox/Additions/linux/sharedfolders/dirops.c ++++ b/src/VBox/Additions/linux/sharedfolders/dirops.c +@@ -450,9 +450,9 @@ static int sf_instantiate(struct inode *parent, struct dentry *dentry, + goto fail1; + } + ++ SET_INODE_INFO(inode, sf_new_i); + sf_init_inode(sf_g, inode, info); + sf_new_i->path = path; +- SET_INODE_INFO(inode, sf_new_i); + + dentry->d_time = jiffies; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) +diff --git a/src/VBox/Additions/linux/sharedfolders/regops.c b/src/VBox/Additions/linux/sharedfolders/regops.c +index c39fc97..37849cf 100644 +--- a/src/VBox/Additions/linux/sharedfolders/regops.c ++++ b/src/VBox/Additions/linux/sharedfolders/regops.c +@@ -147,6 +147,13 @@ static ssize_t sf_reg_read(struct file *file, char *buf, size_t size, loff_t *of + if (!size) + return 0; + ++ /* Try reading from the page cache */ ++ if (sf_r->generation == inode->i_generation) ++ return do_sync_read(file, buf, size, off); ++ else ++ printk("vboxsf: doing direct read, generation %u != %u\n", ++ sf_r->generation, inode->i_generation); ++ + tmp = alloc_bounce_buffer(&tmp_size, size, __PRETTY_FUNCTION__); + if (!tmp) + return -ENOMEM; +@@ -265,6 +272,18 @@ static ssize_t sf_reg_write(struct file *file, const char *buf, size_t size, lof + break; + } + ++ /* force-invalidate the corresponding part of the page cache */ ++ err = invalidate_inode_pages2_range(inode->i_mapping, ++ *off >> PAGE_CACHE_SHIFT, ++ (*off + total_bytes_written - 1) >> PAGE_CACHE_SHIFT); ++ if (err) ++ { ++ printk("vboxsf: could not invalidate inode page cache for %s\n", ++ sf_i->path->String.utf8); ++ /** @todo fall back on pagecache write here? */ ++ inode->i_generation++; /* disable pagecache reads for current fds */ ++ } ++ + *off += total_bytes_written; + if (*off > inode->i_size) + inode->i_size = *off; +@@ -408,11 +427,15 @@ static int sf_reg_open(struct inode *inode, struct file *file) + sf_i->force_restat = 1; + } + else ++ { ++ sf_revalidate_mapping(inode, ¶ms.Info); + sf_init_inode(sf_g, inode, ¶ms.Info); ++ } + + sf_r->handle = params.Handle; + out: + sf_r->createflags = params.CreateFlags; ++ sf_r->generation = inode->i_generation; + INIT_LIST_HEAD(&sf_r->head); + list_add(&sf_r->head, &sf_i->handles); + file->private_data = sf_r; +@@ -674,6 +697,15 @@ static int sf_readpage(struct file *file, struct page *page) + + TRACE(); + ++ sf_r = sf_select_handle(inode, SHFL_CF_ACCESS_READ); ++ if (unlikely(!sf_r)) ++ { ++ struct sf_inode_info *sf_i = GET_INODE_INFO(inode); ++ WARN(1, "vboxsf: could not find handle for readpage for %s", ++ sf_i->path->String.utf8); ++ sf_r = file->private_data; ++ } ++ + buf = kmap(page); + ret = sf_reg_read_aux(__func__, sf_g, sf_r, buf, &nread, off); + if (ret) +diff --git a/src/VBox/Additions/linux/sharedfolders/utils.c b/src/VBox/Additions/linux/sharedfolders/utils.c +index 7ba8276..d2be0c5 100644 +--- a/src/VBox/Additions/linux/sharedfolders/utils.c ++++ b/src/VBox/Additions/linux/sharedfolders/utils.c +@@ -71,6 +71,7 @@ static void sf_timespec_from_ftime(RTTIMESPEC *ts, struct timespec *tv) + void sf_init_inode(struct sf_glob_info *sf_g, struct inode *inode, + PSHFLFSOBJINFO info) + { ++ struct sf_inode_info *sf_i = GET_INODE_INFO(inode); + PSHFLFSOBJATTR attr; + int mode; + +@@ -159,6 +160,49 @@ void sf_init_inode(struct sf_glob_info *sf_g, struct inode *inode, + sf_ftime_from_timespec(&inode->i_atime, &info->AccessTime); + sf_ftime_from_timespec(&inode->i_ctime, &info->ChangeTime); + sf_ftime_from_timespec(&inode->i_mtime, &info->ModificationTime); ++ ++ if (attr->enmAdditional == SHFLFSOBJATTRADD_UNIX) ++ { ++ sf_i->host_dev = attr->u.Unix.INodeIdDevice; ++ sf_i->host_ino = attr->u.Unix.INodeId; ++ } ++} ++ ++/* Check if the host-side inode is likely to have had content changes, ++ * so that we should throw away the cached pages. */ ++void sf_revalidate_mapping(struct inode *inode, PSHFLFSOBJINFO info) ++{ ++ struct timespec mtime; ++ PSHFLFSOBJATTR attr = &info->Attr; ++ ++ TRACE(); ++ ++ if (i_size_read(inode) != info->cbObject) ++ { ++ spin_lock(&inode->i_lock); ++ truncate_setsize(inode, info->cbObject); ++ spin_unlock(&inode->i_lock); ++ goto out_invalid; ++ } ++ ++ sf_ftime_from_timespec(&mtime, &info->ModificationTime); ++ if (timespec_compare(&inode->i_mtime, &mtime)) ++ goto out_invalid; ++ ++ if (attr->enmAdditional == SHFLFSOBJATTRADD_UNIX) ++ { ++ struct sf_inode_info *sf_i = GET_INODE_INFO(inode); ++ if ( (sf_i->host_dev && sf_i->host_dev != attr->u.Unix.INodeIdDevice) ++ || (sf_i->host_ino && sf_i->host_ino != attr->u.Unix.INodeId)) ++ goto out_invalid; ++ } ++ ++ return; ++ ++ out_invalid: ++ invalidate_inode_pages2(inode->i_mapping); ++ inode->i_generation++; ++ return; + } + + int sf_stat(const char *caller, struct sf_glob_info *sf_g, +@@ -244,6 +288,7 @@ int sf_inode_revalidate(struct dentry *dentry) + return err; + + dentry->d_time = jiffies; ++ sf_revalidate_mapping(dentry->d_inode, &info); + sf_init_inode(sf_g, dentry->d_inode, &info); + return 0; + } +diff --git a/src/VBox/Additions/linux/sharedfolders/vfsmod.c b/src/VBox/Additions/linux/sharedfolders/vfsmod.c +index 79097c5..ef4daa9 100644 +--- a/src/VBox/Additions/linux/sharedfolders/vfsmod.c ++++ b/src/VBox/Additions/linux/sharedfolders/vfsmod.c +@@ -300,8 +300,8 @@ static int sf_read_super_aux(struct super_block *sb, void *data, int flags) + goto fail4; + } + +- sf_init_inode(sf_g, iroot, &fsinfo); + SET_INODE_INFO(iroot, sf_i); ++ sf_init_inode(sf_g, iroot, &fsinfo); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25) + unlock_new_inode(iroot); +diff --git a/src/VBox/Additions/linux/sharedfolders/vfsmod.h b/src/VBox/Additions/linux/sharedfolders/vfsmod.h +index c7df740..62fb489 100644 +--- a/src/VBox/Additions/linux/sharedfolders/vfsmod.h ++++ b/src/VBox/Additions/linux/sharedfolders/vfsmod.h +@@ -63,6 +63,10 @@ struct sf_inode_info + SHFLHANDLE handle; + /* list of sf_reg_info for open files, most recent first */ + struct list_head handles; ++ /* identification of host-side inode, to detect if it changed */ ++ /* these can be 0 if not known yet */ ++ RTINODE host_ino; ++ RTDEV host_dev; + }; + + struct sf_dir_info +@@ -84,6 +88,7 @@ struct sf_reg_info + SHFLHANDLE handle; + u32 createflags; /* SHFL_CF_ flags for this handle */ + struct list_head head; /* starts at sf_i->handles */ ++ u32 generation; + }; + + /* globals */ +@@ -103,6 +108,7 @@ extern void sf_init_inode(struct sf_glob_info *sf_g, struct inode *inode, + extern int sf_stat(const char *caller, struct sf_glob_info *sf_g, (6 more lines skipped) ++++++ vbox-physread.diff (new) --- vbox-physread.diff +++ vbox-physread.diff @@ -0,0 +1,230 @@ +commit 1d3a5cd2f8d4d061e7aa82f08a3470a074f1f66b +Author: Richard Braakman <[email protected]> +Date: Sun Feb 3 11:30:43 2013 +0200 + + vboxsf: speed up reads by using multipage transfers + +diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.c b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.c +index 03af236..b49e217 100644 +--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.c ++++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.c +@@ -524,6 +524,53 @@ DECLVBGL(int) VbglR0SfWritePhysCont(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHAND + + } + ++DECLVBGL(int) VbglR0SfReadPhysCont(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, RTCCPHYS PhysBuffer) ++{ ++ uint32_t cbToRead = *pcbBuffer; ++ uint32_t cPages = RT_ALIGN_32((PhysBuffer & PAGE_OFFSET_MASK) + cbToRead, PAGE_SIZE) >> PAGE_SHIFT; ++ uint32_t cbData = sizeof(VBoxSFRead) + RT_UOFFSETOF(HGCMPageListInfo, aPages[cPages]); ++ VBoxSFRead *pData = (VBoxSFRead *)RTMemTmpAlloc(cbData); ++ HGCMPageListInfo *pPgLst = (HGCMPageListInfo *)(pData + 1); ++ uint32_t iPage; ++ int rc; ++ ++ if (RT_UNLIKELY(!pData)) ++ return VERR_NO_TMP_MEMORY; ++ ++ VBOX_INIT_CALL(&pData->callInfo, READ, pClient); ++ ++ pData->root.type = VMMDevHGCMParmType_32bit; ++ pData->root.u.value32 = pMap->root; ++ ++ pData->handle.type = VMMDevHGCMParmType_64bit; ++ pData->handle.u.value64 = hFile; ++ pData->offset.type = VMMDevHGCMParmType_64bit; ++ pData->offset.u.value64 = offset; ++ pData->cb.type = VMMDevHGCMParmType_32bit; ++ pData->cb.u.value32 = cbToRead; ++ pData->buffer.type = VMMDevHGCMParmType_PageList; ++ pData->buffer.u.PageList.size = cbToRead; ++ pData->buffer.u.PageList.offset = sizeof(VBoxSFRead); ++ ++ pPgLst->flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; ++ pPgLst->offFirstPage = (uint16_t)(PhysBuffer & PAGE_OFFSET_MASK); ++ pPgLst->cPages = cPages; ++ PhysBuffer &= ~(RTCCPHYS)PAGE_OFFSET_MASK; ++ for (iPage = 0; iPage < cPages; iPage++, PhysBuffer += PAGE_SIZE) ++ pPgLst->aPages[iPage] = PhysBuffer; ++ ++ rc = VbglHGCMCall (pClient->handle, &pData->callInfo, cbData); ++ if (RT_SUCCESS (rc)) ++ { ++ rc = pData->callInfo.result; ++ *pcbBuffer = pData->cb.u.value32; ++ } ++ ++ RTMemTmpFree(pData); ++ return rc; ++ ++} ++ + DECLVBGL(int) vboxCallFlush(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile) + { + int rc = VINF_SUCCESS; +diff --git a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.h b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.h +index 3947a13..4d7e4a9 100644 +--- a/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.h ++++ b/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR0LibSharedFolders.h +@@ -174,6 +174,7 @@ DECLVBGL(int) vboxCallFlush (PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFil + DECLVBGL(int) vboxCallRead (PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked); + DECLVBGL(int) vboxCallWrite (PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked); + DECLVBGL(int) VbglR0SfWritePhysCont(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, RTCCPHYS PhysBuffer); ++DECLVBGL(int) VbglR0SfReadPhysCont(PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, RTCCPHYS PhysBuffer); + + DECLVBGL(int) vboxCallLock (PVBSFCLIENT pClient, PVBSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint64_t cbSize, uint32_t fLock); + +diff --git a/src/VBox/Additions/linux/sharedfolders/regops.c b/src/VBox/Additions/linux/sharedfolders/regops.c +index db1641b..a0586bd 100644 +--- a/src/VBox/Additions/linux/sharedfolders/regops.c ++++ b/src/VBox/Additions/linux/sharedfolders/regops.c +@@ -21,8 +21,8 @@ + + #include "vfsmod.h" + +-static void *alloc_bounce_buffer(size_t *tmp_sizep, PRTCCPHYS physp, size_t +- xfer_size, const char *caller) ++static void * ++alloc_bounce_buffer(size_t *tmp_sizep, size_t xfer_size, const char *caller) + { + size_t tmp_size; + void *tmp; +@@ -45,7 +45,6 @@ static void *alloc_bounce_buffer(size_t *tmp_sizep, PRTCCPHYS physp, size_t + } + + *tmp_sizep = tmp_size; +- *physp = virt_to_phys(tmp); + return tmp; + } + +@@ -56,37 +55,61 @@ static void free_bounce_buffer(void *tmp) + + + /* fops */ ++ ++/* Input buf must be physically contiguous memory */ + static int sf_reg_read_aux(const char *caller, struct sf_glob_info *sf_g, + struct sf_reg_info *sf_r, void *buf, + uint32_t *nread, uint64_t pos) + { +- /** @todo bird: yes, kmap() and kmalloc() input only. Since the buffer is +- * contiguous in physical memory (kmalloc or single page), we should +- * use a physical address here to speed things up. */ +- int rc = vboxCallRead(&client_handle, &sf_g->map, sf_r->handle, +- pos, nread, buf, false /* already locked? */); +- if (RT_FAILURE(rc)) ++ if (VbglR0CanUsePhysPageList()) ++ { ++ int rc = VbglR0SfReadPhysCont(&client_handle, &sf_g->map, sf_r->handle, ++ pos, nread, virt_to_phys(buf)); ++ if (RT_FAILURE(rc)) ++ { ++ LogFunc(("VbglR0SfReadPhysCont failed. caller=%s, rc=%Rrc\n", ++ caller, rc)); ++ return -EPROTO; ++ } ++ } ++ else + { +- LogFunc(("vboxCallRead failed. caller=%s, rc=%Rrc\n", caller, rc)); +- return -EPROTO; ++ int rc = vboxCallRead(&client_handle, &sf_g->map, sf_r->handle, ++ pos, nread, buf, false /* already locked? */); ++ if (RT_FAILURE(rc)) ++ { ++ LogFunc(("vboxCallRead failed. caller=%s, rc=%Rrc\n", caller, rc)); ++ return -EPROTO; ++ } + } + return 0; + } + ++/* Input buf must be physically contiguous memory */ + static int sf_reg_write_aux(const char *caller, struct sf_glob_info *sf_g, + struct sf_reg_info *sf_r, void *buf, + uint32_t *nwritten, uint64_t pos) + { +- /** @todo bird: yes, kmap() and kmalloc() input only. Since the buffer is +- * contiguous in physical memory (kmalloc or single page), we should +- * use a physical address here to speed things up. */ +- int rc = vboxCallWrite(&client_handle, &sf_g->map, sf_r->handle, +- pos, nwritten, buf, false /* already locked? */); +- if (RT_FAILURE(rc)) ++ if (VbglR0CanUsePhysPageList()) + { +- LogFunc(("vboxCallWrite failed. caller=%s, rc=%Rrc\n", +- caller, rc)); +- return -EPROTO; ++ int rc = VbglR0SfWritePhysCont(&client_handle, &sf_g->map, sf_r->handle, ++ pos, nwritten, virt_to_phys(buf)); ++ if (RT_FAILURE(rc)) ++ { ++ LogFunc(("VbglR0SfWritePhysCont failed. caller=%s, rc=%Rrc\n", ++ caller, rc)); ++ return -EPROTO; ++ } ++ } ++ else ++ { ++ int rc = vboxCallWrite(&client_handle, &sf_g->map, sf_r->handle, ++ pos, nwritten, buf, false /* already locked? */); ++ if (RT_FAILURE(rc)) ++ { ++ LogFunc(("vboxCallWrite failed. caller=%s, rc=%Rrc\n", caller, rc)); ++ return -EPROTO; ++ } + } + return 0; + } +@@ -104,7 +127,6 @@ static ssize_t sf_reg_read(struct file *file, char *buf, size_t size, loff_t *of + { + int err; + void *tmp; +- RTCCPHYS tmp_phys; + size_t tmp_size; + size_t left = size; + ssize_t total_bytes_read = 0; +@@ -125,7 +147,7 @@ static ssize_t sf_reg_read(struct file *file, char *buf, size_t size, loff_t *of + if (!size) + return 0; + +- tmp = alloc_bounce_buffer(&tmp_size, &tmp_phys, size, __PRETTY_FUNCTION__); ++ tmp = alloc_bounce_buffer(&tmp_size, size, __PRETTY_FUNCTION__); + if (!tmp) + return -ENOMEM; + +@@ -179,7 +201,6 @@ static ssize_t sf_reg_write(struct file *file, const char *buf, size_t size, lof + { + int err; + void *tmp; (31 more lines skipped) ++++++ vbox-readpages.diff (new) --- vbox-readpages.diff +++ vbox-readpages.diff @@ -0,0 +1,114 @@ +commit 2e991b96673cb5f6f2093a7ccbc94e403aad46d7 +Author: Richard Braakman <[email protected]> +Date: Sun Feb 3 02:38:15 2013 +0200 + + vboxsf: implement readpages() for efficiency + +diff --git a/src/VBox/Additions/linux/sharedfolders/regops.c b/src/VBox/Additions/linux/sharedfolders/regops.c +index 37849cf..e9b2ace 100644 +--- a/src/VBox/Additions/linux/sharedfolders/regops.c ++++ b/src/VBox/Additions/linux/sharedfolders/regops.c +@@ -689,7 +689,7 @@ static int sf_readpage(struct file *file, struct page *page) + { + struct inode *inode = file->f_dentry->d_inode; + struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb); +- struct sf_reg_info *sf_r = file->private_data; ++ struct sf_reg_info *sf_r; + uint32_t nread = PAGE_SIZE; + char *buf; + loff_t off = ((loff_t)page->index) << PAGE_SHIFT; +@@ -724,6 +724,87 @@ static int sf_readpage(struct file *file, struct page *page) + return 0; + } + ++/* ++ * Read a list of pages into the page cache. ++ * This is only used for readahead, so it's ok to give up. ++ * The caller will fall back on readpage() for the important pages. ++ */ ++static int sf_readpages(struct file *file, struct address_space *mapping, ++ struct list_head *pages, unsigned nr_pages) ++{ ++ struct inode *inode = file->f_dentry->d_inode; ++ struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb); ++ struct sf_reg_info *sf_r; ++ struct page *physbuf = 0; ++ int bufsize; ++ pgoff_t buf_startindex = 0; ++ pgoff_t pages_in_buf = 0; ++ int err = 0; ++ ++ TRACE(); ++ ++ if (nr_pages <= 1) ++ return 0; /* either nothing to do or not worth batching */ ++ ++ sf_r = sf_select_handle(inode, SHFL_CF_ACCESS_READ); ++ if (unlikely(!sf_r)) ++ { ++ struct sf_inode_info *sf_i = GET_INODE_INFO(inode); ++ WARN(1, "vboxsf: could not find handle for readpages for %s", ++ sf_i->path->String.utf8); ++ sf_r = file->private_data; ++ } ++ ++ /* ++ * Performance really depends on the number of calls we make to the host, so ++ * allocate a physically contiguous buffer to read multiple pages per call. ++ */ ++ /* first try to get everything in one read */ ++ bufsize = PAGE_SIZE * (list_entry(pages->next, struct page, lru)->index ++ - list_entry(pages->prev, struct page, lru)->index); ++ if (bufsize > 32 * PAGE_SIZE) ++ bufsize = 32 * PAGE_SIZE; /* don't go crazy though */ ++ ++ physbuf = alloc_pages_exact(bufsize, GFP_KERNEL); ++ if (!physbuf) ++ return -ENOMEM; /* Memory pressure - best not to readahead at all */ ++ ++ while (!list_empty(pages)) ++ { ++ struct page *page = list_first_entry(pages, struct page, lru); ++ loff_t off = (loff_t) page->index << PAGE_SHIFT; ++ list_del(&page->lru); ++ if (add_to_page_cache_lru(page, mapping, page->index, GFP_KERNEL)) ++ { ++ page_cache_release(page); ++ continue; ++ } ++ page_cache_release(page); ++ ++ /* read the next chunk if needed */ ++ if (page->index >= buf_startindex + pages_in_buf) ++ { ++ uint32_t nread = bufsize; ++ err = sf_reg_read_aux(__func__, sf_g, sf_r, physbuf, &nread, off); ++ if (err || nread == 0) ++ break; ++ buf_startindex = page->index; ++ pages_in_buf = nread >> PAGE_SHIFT; ++ /* fix up possible partial page at end */ ++ if (nread != PAGE_ALIGN(nread)) ++ { ++ pages_in_buf++; ++ memset(physbuf + nread, 0, (pages_in_buf << PAGE_SHIFT) - nread); ++ } ++ } ++ copy_page(page_address(page), ++ physbuf + ((page->index - buf_startindex) << PAGE_SHIFT)); ++ } ++ ++ free_pages_exact(physbuf, bufsize); ++ return err; ++} ++ + static int + sf_writepage(struct page *page, struct writeback_control *wbc) + { +@@ -828,5 +909,6 @@ struct address_space_operations sf_reg_aops = + .prepare_write = simple_prepare_write, + .commit_write = simple_commit_write, + # endif ++ .readpages = sf_readpages, + }; + #endif ++++++ vbox-slow-logging.diff (new) --- vbox-slow-logging.diff +++ vbox-slow-logging.diff @@ -0,0 +1,47 @@ +diff --git a/src/VBox/Additions/linux/sharedfolders/regops.c b/src/VBox/Additions/linux/sharedfolders/regops.c +index c39fc97..7f73a67 100644 +--- a/src/VBox/Additions/linux/sharedfolders/regops.c ++++ b/src/VBox/Additions/linux/sharedfolders/regops.c +@@ -63,6 +63,8 @@ static int sf_reg_read_aux(const char *caller, struct sf_glob_info *sf_g, + { + if (VbglR0CanUsePhysPageList()) + { ++ TRACE(); ++ printk("vboxsf starting phys read\n"); + int rc = VbglR0SfReadPhysCont(&client_handle, &sf_g->map, sf_r->handle, + pos, nread, virt_to_phys(buf)); + if (RT_FAILURE(rc)) +@@ -71,6 +73,7 @@ static int sf_reg_read_aux(const char *caller, struct sf_glob_info *sf_g, + caller, rc)); + return -EPROTO; + } ++ printk("vboxsf ended phys read\n"); + } + else + { +diff --git a/src/VBox/Additions/linux/sharedfolders/vfsmod.h b/src/VBox/Additions/linux/sharedfolders/vfsmod.h +index c7df740..043c478 100644 +--- a/src/VBox/Additions/linux/sharedfolders/vfsmod.h ++++ b/src/VBox/Additions/linux/sharedfolders/vfsmod.h +@@ -157,5 +157,21 @@ int sf_get_volume_info(struct super_block *sb,STRUCT_STATFS *stat); + # define SET_INODE_INFO(i, sf_i) (i)->u.generic_ip = sf_i + #endif + ++#undef LogFunc ++#define LogFunc__(format, args...) do { \ ++ if (strstr(format, "%Rrc")) { \ ++ char *printkformat = kstrdup("%s: " format, GFP_KERNEL); \ ++ char *p = printkformat; \ ++ while ((p = strstr(p, "%Rrc"))) \ ++ p[1] = 'd'; \ ++ printk(printkformat, __func__, ##args); \ ++ kfree(printkformat); \ ++ } else { \ ++ printk("%s: " format, __func__, ##args); \ ++ } \ ++} while (0) ++/* This strips the extra parentheses that are used with the real LogFunc */ ++#define LogFunc(...) LogFunc__ __VA_ARGS__ ++ + #endif +
