VirtualBox

Ignore:
Timestamp:
Mar 10, 2019 4:14:09 AM (6 years ago)
Author:
vboxsync
Message:

linux/vboxsf: Implemented write_iter as well. Can write to loop mounted ext4 image now. bugref:9172 ticketref:17360

Location:
trunk/src/VBox/Additions/linux/sharedfolders
Files:
2 edited

Legend:

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

    r77628 r77631  
    923923                    i_size_write(inode, offFile);
    924924                vbsf_reg_write_invalidate_mapping_range(inode->i_mapping, offFile - cbActual, offFile);
     925                sf_i->force_restat = 1; /* mtime (and size) may have changed */
    925926
    926927                /*
     
    949950                break;
    950951            }
    951             sf_i->force_restat = 1; /* mtime (and size) may have changed */
    952952        }
    953953    }
     
    10261026            if (copy_from_user(pReq->abData, buf, size) == 0) {
    10271027                int vrc = VbglR0SfHostReqWriteEmbedded(sf_g->map.root, pReq, sf_r->Handle.hHost,
    1028                                        pos, (uint32_t)size);
     1028                                                       pos, (uint32_t)size);
    10291029                if (RT_SUCCESS(vrc)) {
    10301030                    cbRet = pReq->Parms.cb32Write.u.value32;
     
    16421642
    16431643
     1644/**
     1645 * Worker for vbsf_reg_write_iter() that deals with larger writes using page
     1646 * locking.
     1647 */
     1648static ssize_t vbsf_reg_write_iter_locking(struct kiocb *kio, struct iov_iter *iter, size_t cbToWrite, loff_t offFile,
     1649                                           struct vbsf_super_info *sf_g, struct vbsf_reg_info *sf_r,
     1650                                           struct inode *inode, struct vbsf_inode_info *sf_i, struct address_space *mapping)
     1651{
     1652    /*
     1653     * Estimate how many pages we may possible submit in a single request so
     1654     * that we can allocate matching request buffer and page array.
     1655     */
     1656    struct page         *apPagesStack[16];
     1657    struct page        **papPages     = &apPagesStack[0];
     1658    struct page        **papPagesFree = NULL;
     1659    VBOXSFWRITEPGLSTREQ *pReq;
     1660    ssize_t              cbRet        = 0;
     1661    size_t               cMaxPages    = vbsf_iter_max_span_of_pages(iter);
     1662    cMaxPages = RT_MIN(RT_MAX(sf_g->cMaxIoPages, 2), cMaxPages);
     1663
     1664    pReq = (VBOXSFWRITEPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cMaxPages]));
     1665    while (!pReq && cMaxPages > 4) {
     1666        cMaxPages /= 2;
     1667        pReq = (VBOXSFWRITEPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cMaxPages]));
     1668    }
     1669    if (pReq && cMaxPages > RT_ELEMENTS(apPagesStack))
     1670        papPagesFree = papPages = kmalloc(cMaxPages * sizeof(sizeof(papPages[0])), GFP_KERNEL);
     1671    if (pReq && papPages) {
     1672
     1673        /*
     1674         * The write loop.
     1675         */
     1676        struct vbsf_iter_stash Stash = VBSF_ITER_STASH_INITIALIZER;
     1677        do {
     1678            /*
     1679             * Grab as many pages as we can.  This means that if adjacent
     1680             * segments both starts and ends at a page boundrary, we can
     1681             * do them both in the same transfer from the host.
     1682             */
     1683            size_t cPages   = 0;
     1684            size_t cbChunk  = 0;
     1685            size_t offPage0 = 0;
     1686            int rc = vbsf_iter_lock_pages(iter, false /*fWrite*/, &Stash, cMaxPages, papPages, &cPages, &offPage0, &cbChunk);
     1687            if (rc == 0) {
     1688                size_t iPage = cPages;
     1689                while (iPage-- > 0)
     1690                    pReq->PgLst.aPages[iPage] = page_to_phys(papPages[iPage]);
     1691                pReq->PgLst.offFirstPage = (uint16_t)offPage0;
     1692                AssertStmt(cbChunk <= cbToWrite, cbChunk = cbToWrite);
     1693            } else {
     1694                cbRet = rc;
     1695                break;
     1696            }
     1697
     1698            /*
     1699             * Issue the request and unlock the pages.
     1700             */
     1701            rc = VbglR0SfHostReqWritePgLst(sf_g->map.root, pReq, sf_r->Handle.hHost, offFile, cbChunk, cPages);
     1702            SFLOGFLOW(("vbsf_reg_write_iter_locking: VbglR0SfHostReqWritePgLst -> %d (cbActual=%#x cbChunk=%#zx of %#zx cPages=%#zx offPage0=%#x\n",
     1703                       rc, pReq->Parms.cb32Write.u.value32, cbChunk, cbToWrite, cPages, offPage0));
     1704
     1705            vbsf_iter_unlock_pages(iter, papPages, cPages, false /*fSetDirty*/);
     1706
     1707            if (RT_SUCCESS(rc)) {
     1708                /*
     1709                 * Success, advance position and buffer.
     1710                 */
     1711                uint32_t cbActual = pReq->Parms.cb32Write.u.value32;
     1712                AssertStmt(cbActual <= cbChunk, cbActual = cbChunk);
     1713                cbRet      += cbActual;
     1714                offFile    += cbActual;
     1715                kio->ki_pos = offFile;
     1716                cbToWrite  -= cbActual;
     1717                if (offFile > i_size_read(inode))
     1718                    i_size_write(inode, offFile);
     1719                vbsf_reg_write_invalidate_mapping_range(mapping, offFile - cbActual, offFile);
     1720                sf_i->force_restat = 1; /* mtime (and size) may have changed */
     1721
     1722                /*
     1723                 * Are we done already?
     1724                 */
     1725                if (!cbToWrite)
     1726                    break;
     1727                if (cbActual < cbChunk) { /* We ASSUME end-of-file here. */
     1728                    if (vbsf_iter_rewind(iter, &Stash, cbChunk - cbActual, cbActual))
     1729                        iov_iter_truncate(iter, 0);
     1730                    break;
     1731                }
     1732            } else {
     1733                /*
     1734                 * Try rewind the iter structure.
     1735                 */
     1736                bool const fRewindOkay = vbsf_iter_rewind(iter, &Stash, cbChunk, cbChunk);
     1737                if (rc == VERR_NO_MEMORY && cMaxPages > 4 && fRewindOkay) {
     1738                    /*
     1739                     * The host probably doesn't have enough heap to handle the
     1740                     * request, reduce the page count and retry.
     1741                     */
     1742                    cMaxPages /= 4;
     1743                    Assert(cMaxPages > 0);
     1744                } else {
     1745                    /*
     1746                     * If we've successfully written stuff, return it rather than
     1747                     * the error.  (Not sure if this is such a great idea...)
     1748                     */
     1749                    if (cbRet <= 0)
     1750                        cbRet = -EPROTO;
     1751                    break;
     1752                }
     1753            }
     1754        } while (cbToWrite > 0);
     1755
     1756        vbsf_iter_cleanup_stash(iter, &Stash);
     1757    }
     1758    else
     1759        cbRet = -ENOMEM;
     1760    if (papPagesFree)
     1761        kfree(papPages);
     1762    if (pReq)
     1763        VbglR0PhysHeapFree(pReq);
     1764    SFLOGFLOW(("vbsf_reg_write_iter_locking: returns %#zx (%zd)\n", cbRet, cbRet));
     1765    return cbRet;
     1766}
     1767
     1768
     1769
     1770/**
     1771 * Write from I/O vector iterator.
     1772 *
     1773 * @returns Number of bytes written on success, negative errno on error.
     1774 * @param   kio         The kernel I/O control block (or something like that).
     1775 * @param   iter        The I/O vector iterator describing the buffer.
     1776 */
    16441777static ssize_t vbsf_reg_write_iter(struct kiocb *kio, struct iov_iter *iter)
    16451778{
    1646     SFLOGFLOW(("vbsf_reg_write_iter: -> EINVAL\n"));
    1647     return -EINVAL;
     1779    size_t                  cbToWrite = iov_iter_count(iter);
     1780    struct inode           *inode     = VBSF_GET_F_DENTRY(kio->ki_filp)->d_inode;
     1781    struct vbsf_inode_info *sf_i      = VBSF_GET_INODE_INFO(inode);
     1782    struct address_space   *mapping   = inode->i_mapping;
     1783
     1784    struct vbsf_reg_info   *sf_r      = kio->ki_filp->private_data;
     1785    struct vbsf_super_info *sf_g      = VBSF_GET_SUPER_INFO(inode->i_sb);
     1786    loff_t                  offFile   = kio->ki_pos;
     1787
     1788    SFLOGFLOW(("vbsf_reg_write_iter: inode=%p file=%p size=%#zx off=%#llx type=%#x\n",
     1789               inode, kio->ki_filp, cbToWrite, offFile, iter->type));
     1790    AssertReturn(S_ISREG(inode->i_mode), -EINVAL);
     1791
     1792    /*
     1793     * Enforce APPEND flag.
     1794     */
     1795    /** @todo This should be handled by the host, it returning the new file
     1796     *        offset when appending.  We may have an outdated i_size value here! */
     1797    if (kio->ki_flags & IOCB_APPEND)
     1798        kio->ki_pos = offFile = i_size_read(inode);
     1799
     1800    /*
     1801     * Do we have anything at all to do here?
     1802     */
     1803    if (!cbToWrite)
     1804        return 0;
     1805
     1806    /*
     1807     * Now now we reject async I/O requests.
     1808     */
     1809    if (!is_sync_kiocb(kio)) {
     1810        SFLOGFLOW(("vbsf_reg_write_iter: async I/O not yet supported\n")); /** @todo extend FsPerf with AIO tests. */
     1811        return -EOPNOTSUPP;
     1812    }
     1813
     1814    /*
     1815     * If there are active writable mappings, coordinate with any
     1816     * pending writes via those.
     1817     */
     1818    if (   mapping
     1819        && mapping->nrpages > 0
     1820        && mapping_writably_mapped(mapping)) {
     1821#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
     1822        int err = filemap_fdatawait_range(mapping, offFile, offFile + cbToWrite - 1);
     1823        if (err)
     1824            return err;
     1825#else
     1826        /** @todo ... */
     1827#endif
     1828    }
     1829
     1830    /*
     1831     * For small requests, try use an embedded buffer provided we get a heap block
     1832     * that does not cross page boundraries (see host code).
     1833     */
     1834    if (cbToWrite <= PAGE_SIZE / 4 * 3 - RT_UOFFSETOF(VBOXSFWRITEEMBEDDEDREQ, abData[0]) /* see allocator */) {
     1835        uint32_t const         cbReq = RT_UOFFSETOF(VBOXSFWRITEEMBEDDEDREQ, abData[0]) + cbToWrite;
     1836        VBOXSFWRITEEMBEDDEDREQ *pReq = (VBOXSFWRITEEMBEDDEDREQ *)VbglR0PhysHeapAlloc(cbReq);
     1837        if (pReq) {
     1838            if ((PAGE_SIZE - ((uintptr_t)pReq & PAGE_OFFSET_MASK)) >= cbReq) {
     1839                ssize_t cbRet;
     1840                if (copy_from_iter(pReq->abData, cbToWrite, iter) == cbToWrite) {
     1841                    int vrc = VbglR0SfHostReqWriteEmbedded(sf_g->map.root, pReq, sf_r->Handle.hHost,
     1842                                                           offFile, (uint32_t)cbToWrite);
     1843                    if (RT_SUCCESS(vrc)) {
     1844                        cbRet = pReq->Parms.cb32Write.u.value32;
     1845                        AssertStmt(cbRet <= (ssize_t)cbToWrite, cbRet = cbToWrite);
     1846                        kio->ki_pos = offFile += cbRet;
     1847                        if (offFile > i_size_read(inode))
     1848                            i_size_write(inode, offFile);
     1849                        vbsf_reg_write_invalidate_mapping_range(mapping, offFile - cbRet, offFile);
     1850# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
     1851                        if ((size_t)cbRet < cbToWrite)
     1852                            iov_iter_revert(iter, cbToWrite - cbRet);
     1853# endif
     1854                    } else
     1855                        cbRet = -EPROTO;
     1856                    sf_i->force_restat = 1; /* mtime (and size) may have changed */
     1857                } else
     1858                    cbRet = -EFAULT;
     1859                VbglR0PhysHeapFree(pReq);
     1860                SFLOGFLOW(("vbsf_reg_write_iter: returns %#zx (%zd)\n", cbRet, cbRet));
     1861                return cbRet;
     1862            }
     1863            VbglR0PhysHeapFree(pReq);
     1864        }
     1865    }
     1866
     1867    /*
     1868     * Otherwise do the page locking thing.
     1869     */
     1870    return vbsf_reg_write_iter_locking(kio, iter, cbToWrite, offFile, sf_g, sf_r, inode, sf_i, mapping);
    16481871}
    16491872
  • trunk/src/VBox/Additions/linux/sharedfolders/vfsmod.h

    r77628 r77631  
    5454#include <iprt/asm.h>
    5555#include "vbsfmount.h"
     56
     57
     58/*
     59 * Logging wrappers.
     60 */
     61#if 1
     62# define TRACE()          LogFunc(("tracepoint\n"))
     63# define SFLOGFLOW(aArgs) Log(aArgs)
     64# define SFLOG2(aArgs)    Log2(aArgs)
     65# define SFLOG3(aArgs)    Log3(aArgs)
     66# ifdef LOG_ENABLED
     67#  define SFLOG_ENABLED   1
     68# endif
     69#else
     70# define TRACE()          RTLogBackdoorPrintf("%s: tracepoint\n", __FUNCTION__)
     71# define SFLOGFLOW(aArgs) RTLogBackdoorPrintf aArgs
     72# define SFLOG2(aArgs)    RTLogBackdoorPrintf aArgs
     73# define SFLOG3(aArgs)    RTLogBackdoorPrintf aArgs
     74# define SFLOG_ENABLED    1
     75#endif
    5676
    5777
     
    313333DECLINLINE(void) vbsf_dentry_set_update_jiffies(struct dentry *pDirEntry, unsigned long uToSet)
    314334{
     335    /*SFLOG3(("vbsf_dentry_set_update_jiffies: %p: %lx -> %#lx\n", pDirEntry, (unsigned long)pDirEntry->d_fsdata, uToSet));*/
    315336    pDirEntry->d_fsdata = (void *)uToSet;
    316337}
     
    393414}
    394415
    395 #if 1
    396 # define TRACE()          LogFunc(("tracepoint\n"))
    397 # define SFLOGFLOW(aArgs) Log(aArgs)
    398 # define SFLOG2(aArgs)    Log2(aArgs)
    399 # define SFLOG3(aArgs)    Log3(aArgs)
    400 # ifdef LOG_ENABLED
    401 #  define SFLOG_ENABLED   1
    402 # endif
    403 #else
    404 # define TRACE()          RTLogBackdoorPrintf("%s: tracepoint\n", __FUNCTION__)
    405 # define SFLOGFLOW(aArgs) RTLogBackdoorPrintf aArgs
    406 # define SFLOG2(aArgs)    RTLogBackdoorPrintf aArgs
    407 # define SFLOG3(aArgs)    RTLogBackdoorPrintf aArgs
    408 # define SFLOG_ENABLED    1
    409 #endif
    410 
    411416#endif /* !GA_INCLUDED_SRC_linux_sharedfolders_vfsmod_h */
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