VirtualBox

Changeset 77770 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Mar 18, 2019 7:36:48 PM (6 years ago)
Author:
vboxsync
Message:

linux/vboxsf: Redid the code that synchronizes writes with mmappings (page cache). Probably way faster to copy over the data written than kick out page mappings. It certainly works better with older kernels. bugref:9172

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/linux/sharedfolders/regops.c

    r77741 r77770  
    4949# include <linux/splice.h>
    5050#endif
     51#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 10)
     52# include <linux/swap.h> /* for mark_page_accessed */
     53#endif
    5154#include <iprt/err.h>
    5255
     
    6164#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)
    6265# define vm_fault_t int
     66#endif
     67
     68#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 20)
     69# define pgoff_t    unsigned long
    6370#endif
    6471
     
    827834
    828835/**
    829  * Wrapper around invalidate_mapping_pages() for page cache invalidation so that
    830  * the changes written via vbsf_reg_write are made visible to mmap users.
    831  */
    832 DECLINLINE(void) vbsf_reg_write_invalidate_mapping_range(struct address_space *mapping, loff_t offStart, loff_t offEnd)
    833 {
    834     /*
    835      * Only bother with this if the mapping has any pages in it.
    836      *
    837      * Note! According to the docs, the last parameter, end, is inclusive (we
    838      *       would have named it 'last' to indicate this).
    839      *
    840      * Note! The pre-2.6.12 function might not do enough to sure consistency
    841      *       when any of the pages in the range is already mapped.
    842      */
    843 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)
    844     if (mapping)
    845         invalidate_inode_pages2_range(mapping, offStart >> PAGE_SHIFT, (offEnd - 1) >> PAGE_SHIFT);
    846 # elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
    847     if (mapping && mapping->nrpages > 0)
    848         invalidate_mapping_pages(mapping, offStart >> PAGE_SHIFT, (offEnd - 1) >> PAGE_SHIFT);
    849 # elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 60) && 0 /** @todo invalidate_mapping_pages was added in 2.5.60, but exported in 2.6.21 */
    850     if (mapping && mapping->nrpages > 0)
    851         invalidate_mapping_pages(mapping, offStart >> PAGE_SHIFT, (offEnd - 1) >> PAGE_SHIFT);
    852 # else
    853     /** @todo ... */
    854     RT_NOREF(mapping, offStart, offEnd);
     836 * Helper the synchronizes the page cache content with something we just wrote
     837 * to the host.
     838 */
     839void vbsf_reg_write_sync_page_cache(struct address_space *mapping, loff_t offFile, uint32_t cbRange,
     840                                    uint8_t const *pbSrcBuf, struct page **papSrcPages, uint32_t offSrcPage)
     841{
     842    if (mapping && mapping->nrpages > 0) {
     843        /*
     844         * Work the pages in the write range.
     845         */
     846        while (cbRange > 0) {
     847            /*
     848             * Lookup the page at offFile.  We're fine if there aren't
     849             * any there.  We're skip if it's dirty or is being written
     850             * back, at least for now.
     851             */
     852            size_t const  offDstPage = offFile & PAGE_OFFSET_MASK;
     853            size_t const  cbToCopy   = RT_MIN(PAGE_SIZE - offDstPage, cbRange);
     854            pgoff_t const idxPage    = offFile >> PAGE_SHIFT;
     855            struct page  *pDstPage   = find_lock_page(mapping, idxPage);
     856            if (pDstPage) {
     857                if (   pDstPage->mapping == mapping /* ignore if re-purposed (paranoia) */
     858                    && pDstPage->index == idxPage
     859                    && !PageDirty(pDstPage)         /* ignore if dirty */
     860                    && !PageWriteback(pDstPage)     /* ignore if being written back */ ) {
     861                    /*
     862                     * Map the page and do the copying.
     863                     */
     864                    uint8_t *pbDst = (uint8_t *)kmap(pDstPage);
     865                    if (pbSrcBuf)
     866                        memcpy(&pbDst[offDstPage], pbSrcBuf, cbToCopy);
     867                    else {
     868                        uint32_t const cbSrc0 = PAGE_SIZE - offSrcPage;
     869                        uint8_t const *pbSrc  = (uint8_t const *)kmap(papSrcPages[0]);
     870                        memcpy(&pbDst[offDstPage], &pbSrc[offSrcPage], RT_MIN(cbToCopy, cbSrc0));
     871                        kunmap(papSrcPages[0]);
     872                        if (cbToCopy > cbSrc0) {
     873                            pbSrc = (uint8_t const *)kmap(papSrcPages[1]);
     874                            memcpy(&pbDst[offDstPage + cbSrc0], pbSrc, cbToCopy - cbSrc0);
     875                            kunmap(papSrcPages[1]);
     876                        }
     877                    }
     878                    kunmap(pDstPage);
     879                    flush_dcache_page(pDstPage);
     880                    if (cbToCopy == PAGE_SIZE)
     881                        SetPageUptodate(pDstPage);
     882# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 10)
     883                    mark_page_accessed(pDstPage);
    855884# endif
     885                } else
     886                    SFLOGFLOW(("vbsf_reg_write_sync_page_cache: Skipping page %p: mapping=%p (vs %p) writeback=%d offset=%#lx (vs%#lx)\n",
     887                               pDstPage, pDstPage->mapping, mapping, PageWriteback(pDstPage), pDstPage->index, idxPage));
     888                unlock_page(pDstPage);
     889                vbsf_put_page(pDstPage);
     890            }
     891
     892            /*
     893             * Advance.
     894             */
     895            cbRange -= cbToCopy;
     896            offFile += cbToCopy;
     897            if (pbSrcBuf)
     898                pbSrcBuf += cbToCopy;
     899            else
     900            {
     901                offSrcPage += cbToCopy;
     902                if (offSrcPage >= PAGE_SIZE) {
     903                    offSrcPage &= PAGE_OFFSET_MASK;
     904                    papSrcPages++;
     905                }
     906            }
     907        }
     908    }
    856909}
    857910
     
    918971             */
    919972            rc = VbglR0SfHostReqWritePgLst(sf_g->map.root, pReq, sf_r->Handle.hHost, offFile, cbChunk, cPages);
    920 
    921             vbsf_unlock_user_pages(papPages, cPages, false /*fSetDirty*/, fLockPgHack);
    922 
    923973            if (RT_SUCCESS(rc)) {
    924974                /*
     
    927977                uint32_t cbActual = pReq->Parms.cb32Write.u.value32;
    928978                AssertStmt(cbActual <= cbChunk, cbActual = cbChunk);
     979
     980                vbsf_reg_write_sync_page_cache(inode->i_mapping, offFile, cbActual, NULL /*pbKrnlBuf*/,
     981                                               papPages, (uintptr_t)buf & PAGE_OFFSET_MASK);
     982                vbsf_unlock_user_pages(papPages, cPages, false /*fSetDirty*/, fLockPgHack);
     983
    929984                cbRet   += cbActual;
    930985                offFile += cbActual;
     
    933988                if (offFile > i_size_read(inode))
    934989                    i_size_write(inode, offFile);
    935                 vbsf_reg_write_invalidate_mapping_range(inode->i_mapping, offFile - cbActual, offFile);
    936990                sf_i->force_restat = 1; /* mtime (and size) may have changed */
    937991
     
    943997                    break;
    944998                }
    945             } else if (rc == VERR_NO_MEMORY && cMaxPages > 4) {
    946                 /*
    947                  * The host probably doesn't have enough heap to handle the
    948                  * request, reduce the page count and retry.
    949                  */
    950                 cMaxPages /= 4;
    951                 Assert(cMaxPages > 0);
    952999            } else {
    953                 /*
    954                  * If we've successfully written stuff, return it rather than
    955                  * the error.  (Not sure if this is such a great idea...)
    956                  */
    957                 if (cbRet > 0)
    958                     *off = offFile;
    959                 else
    960                     cbRet = -EPROTO;
    961                 break;
     1000                vbsf_unlock_user_pages(papPages, cPages, false /*fSetDirty*/, fLockPgHack);
     1001                if (rc == VERR_NO_MEMORY && cMaxPages > 4) {
     1002                    /*
     1003                     * The host probably doesn't have enough heap to handle the
     1004                     * request, reduce the page count and retry.
     1005                     */
     1006                    cMaxPages /= 4;
     1007                    Assert(cMaxPages > 0);
     1008                } else {
     1009                    /*
     1010                     * If we've successfully written stuff, return it rather than
     1011                     * the error.  (Not sure if this is such a great idea...)
     1012                     */
     1013                    if (cbRet > 0)
     1014                        *off = offFile;
     1015                    else
     1016                        cbRet = -EPROTO;
     1017                    break;
     1018                }
    9621019            }
    9631020        }
     
    10411098                    cbRet = pReq->Parms.cb32Write.u.value32;
    10421099                    AssertStmt(cbRet <= (ssize_t)size, cbRet = size);
     1100                    vbsf_reg_write_sync_page_cache(mapping, pos, (uint32_t)cbRet, pReq->abData,
     1101                                                   NULL /*papSrcPages*/, 0 /*offSrcPage0*/);
    10431102                    pos += cbRet;
    10441103                    *off = pos;
    10451104                    if (pos > i_size_read(inode))
    10461105                        i_size_write(inode, pos);
    1047                     vbsf_reg_write_invalidate_mapping_range(mapping, pos - cbRet, pos);
    10481106                } else
    10491107                    cbRet = -EPROTO;
     
    10751133                        cbRet = pReq->Parms.cb32Write.u.value32;
    10761134                        AssertStmt(cbRet <= (ssize_t)size, cbRet = size);
     1135                        vbsf_reg_write_sync_page_cache(mapping, pos, (uint32_t)cbRet, (uint8_t const *)pvBounce,
     1136                                                       NULL /*papSrcPages*/, 0 /*offSrcPage0*/);
    10771137                        pos += cbRet;
    10781138                        *off = pos;
    10791139                        if (pos > i_size_read(inode))
    10801140                            i_size_write(inode, pos);
    1081                         vbsf_reg_write_invalidate_mapping_range(mapping, pos - cbRet, pos);
    10821141                    } else
    10831142                        cbRet = -EPROTO;
     
    17941853            SFLOGFLOW(("vbsf_reg_write_iter_locking: VbglR0SfHostReqWritePgLst -> %d (cbActual=%#x cbChunk=%#zx of %#zx cPages=%#zx offPage0=%#x\n",
    17951854                       rc, pReq->Parms.cb32Write.u.value32, cbChunk, cbToWrite, cPages, offPage0));
    1796 
    1797             vbsf_iter_unlock_pages(iter, papPages, cPages, false /*fSetDirty*/);
    1798 
    17991855            if (RT_SUCCESS(rc)) {
    18001856                /*
     
    18031859                uint32_t cbActual = pReq->Parms.cb32Write.u.value32;
    18041860                AssertStmt(cbActual <= cbChunk, cbActual = cbChunk);
     1861
     1862                vbsf_reg_write_sync_page_cache(mapping, offFile, (uint32_t)cbRet, NULL /*pbSrcBuf*/, papPages, offPage0);
     1863                vbsf_iter_unlock_pages(iter, papPages, cPages, false /*fSetDirty*/);
     1864
    18051865                cbRet      += cbActual;
    18061866                offFile    += cbActual;
     
    18091869                if (offFile > i_size_read(inode))
    18101870                    i_size_write(inode, offFile);
    1811                 vbsf_reg_write_invalidate_mapping_range(mapping, offFile - cbActual, offFile);
    18121871                sf_i->force_restat = 1; /* mtime (and size) may have changed */
    18131872
     
    18261885                 * Try rewind the iter structure.
    18271886                 */
    1828                 bool const fRewindOkay = vbsf_iter_rewind(iter, &Stash, cbChunk, cbChunk);
     1887                bool fRewindOkay;
     1888                vbsf_iter_unlock_pages(iter, papPages, cPages, false /*fSetDirty*/);
     1889                fRewindOkay = vbsf_iter_rewind(iter, &Stash, cbChunk, cbChunk);
    18291890                if (rc == VERR_NO_MEMORY && cMaxPages > 4 && fRewindOkay) {
    18301891                    /*
     
    19402001                        cbRet = pReq->Parms.cb32Write.u.value32;
    19412002                        AssertStmt(cbRet <= (ssize_t)cbToWrite, cbRet = cbToWrite);
     2003                        vbsf_reg_write_sync_page_cache(mapping, offFile, (uint32_t)cbRet, pReq->abData,
     2004                                                       NULL /*papSrcPages*/, 0 /*offSrcPage0*/);
    19422005                        kio->ki_pos = offFile += cbRet;
    19432006                        if (offFile > i_size_read(inode))
    19442007                            i_size_write(inode, offFile);
    1945                         vbsf_reg_write_invalidate_mapping_range(mapping, offFile - cbRet, offFile);
    19462008# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
    19472009                        if ((size_t)cbRet < cbToWrite)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette