VirtualBox

Changeset 77942 in vbox


Ignore:
Timestamp:
Mar 28, 2019 5:33:49 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
129663
Message:

linux/vboxsf: Implemented missing vbsf_splice_write to make it possible to splice() to a file on 2.6.23 - 2.6.30. bugref:9172

File:
1 edited

Legend:

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

    r77940 r77942  
    690690            if (cbRet == 0)
    691691                cbRet = -ERESTARTSYS;
    692             SFLOGFLOW(("vbsf_feed_pages_to_pipe: pending signal! (%d)\n", cbRet));
     692            SFLOGFLOW(("vbsf_feed_pages_to_pipe: pending signal! (%zd)\n", cbRet));
    693693            break;
    694694        } else {
     
    714714 * For splicing from a file to a pipe.
    715715 */
    716 static ssize_t vbsf_splice_read(struct file *in, loff_t * poffset, struct pipe_inode_info *pipe, size_t len, unsigned int flags)
    717 {
    718     struct inode           *inode = VBSF_GET_F_DENTRY(in)->d_inode;
     716static ssize_t vbsf_splice_read(struct file *file, loff_t *poffset, struct pipe_inode_info *pipe, size_t len, unsigned int flags)
     717{
     718    struct inode           *inode = VBSF_GET_F_DENTRY(file)->d_inode;
    719719    struct vbsf_super_info *sf_g  = VBSF_GET_SUPER_INFO(inode->i_sb);
    720720    ssize_t                 cbRet;
    721721
    722     SFLOGFLOW(("vbsf_splice_read: in=%p poffset=%p{%#RX64} pipe=%p len=%#zx flags=%#x\n", in, poffset, *poffset, pipe, len, flags));
    723     if (vbsf_should_use_cached_read(in, inode->i_mapping, sf_g)) {
    724         cbRet = generic_file_splice_read(in, poffset, pipe, len, flags);
     722    SFLOGFLOW(("vbsf_splice_read: file=%p poffset=%p{%#RX64} pipe=%p len=%#zx flags=%#x\n", file, poffset, *poffset, pipe, len, flags));
     723    if (vbsf_should_use_cached_read(file, inode->i_mapping, sf_g)) {
     724        cbRet = generic_file_splice_read(file, poffset, pipe, len, flags);
    725725    } else {
    726726        /*
     
    759759                 */
    760760                uint32_t const          cbToRead = RT_MIN((cPages << PAGE_SHIFT) - (offFile & PAGE_OFFSET_MASK), len);
    761                 struct vbsf_reg_info   *sf_r     = (struct vbsf_reg_info *)in->private_data;
     761                struct vbsf_reg_info   *sf_r     = (struct vbsf_reg_info *)file->private_data;
    762762                int vrc = VbglR0SfHostReqReadPgLst(sf_g->map.root, pReq, sf_r->Handle.hHost, offFile, cbToRead, cPages);
    763763                if (RT_SUCCESS(vrc)) {
     
    797797    }
    798798    SFLOGFLOW(("vbsf_splice_read: returns %zd (%#zx), *poffset=%#RX64\n", cbRet, cbRet, *poffset));
     799    return cbRet;
     800}
     801
     802
     803/**
     804 * For splicing from a pipe to a file.
     805 */
     806static ssize_t vbsf_splice_write(struct pipe_inode_info *pPipe, struct file *file, loff_t *poffset, size_t len, unsigned int flags)
     807{
     808    struct inode           *inode = VBSF_GET_F_DENTRY(file)->d_inode;
     809    struct vbsf_super_info *sf_g  = VBSF_GET_SUPER_INFO(inode->i_sb);
     810    ssize_t                 cbRet;
     811
     812    SFLOGFLOW(("vbsf_splice_write: pPipe=%p file=%p poffset=%p{%#RX64} len=%#zx flags=%#x\n", pPipe, file, poffset, *poffset, len, flags));
     813    if (false /** @todo  later */) {
     814        cbRet = generic_file_splice_write(pPipe, file, poffset, len, flags);
     815    } else {
     816        /*
     817         * Prepare a write request.
     818         */
     819        struct vbsf_reg_info *sf_r       = (struct vbsf_reg_info *)file->private_data;
     820        loff_t                offFile    = *poffset;
     821        uint32_t const        cMaxPages  = RT_MIN(PIPE_BUFFERS, RT_ALIGN_Z(len, PAGE_SIZE) >> PAGE_SHIFT);
     822        VBOXSFWRITEPGLSTREQ  *pReq       = (VBOXSFWRITEPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ,
     823                                                                                                       PgLst.aPages[cMaxPages]));
     824        if (pReq) {
     825            /*
     826             * Feed from the pipe.
     827             */
     828            bool fNeedWakeUp = false;
     829            cbRet = 0;
     830
     831            LOCK_PIPE(pPipe);
     832
     833            for (;;) {
     834                unsigned cBufs = pPipe->nrbufs;
     835                /*SFLOG2(("vbsf_splice_write: nrbufs=%#x curbuf=%#x\n", cBufs, pPipe->curbuf));*/
     836                if (cBufs) {
     837                    /*
     838                     * There is data available.  Write it to the file.
     839                     */
     840                    int                 vrc;
     841                    struct pipe_buffer *pPipeBuf      = &pPipe->bufs[pPipe->curbuf];
     842                    uint32_t            cPagesToWrite = 1;
     843                    uint32_t            cbToWrite     = pPipeBuf->len;
     844
     845                    Assert(pPipeBuf->offset < PAGE_SIZE);
     846                    Assert(pPipeBuf->offset + pPipeBuf->len <= PAGE_SIZE);
     847
     848                    pReq->PgLst.offFirstPage = pPipeBuf->offset & PAGE_OFFSET;
     849                    pReq->PgLst.aPages[0]    = page_to_phys(pPipeBuf->page);
     850
     851                    /* Add any adjacent page buffers: */
     852                    while (   cPagesToWrite < cBufs
     853                           && cPagesToWrite < cMaxPages
     854                           && ((pReq->PgLst.offFirstPage + cbToWrite) & PAGE_OFFSET_MASK) == 0) {
     855                        struct pipe_buffer *pPipeBuf2 = &pPipe->bufs[(pPipe->curbuf + cPagesToWrite) % PIPE_BUFFERS];
     856                        Assert(pPipeBuf2->len <= PAGE_SIZE);
     857                        Assert(pPipeBuf2->offset < PAGE_SIZE);
     858                        if (pPipeBuf2->offset != 0)
     859                            break;
     860                        pReq->PgLst.aPages[cPagesToWrite] = page_to_phys(pPipeBuf2->page);
     861                        cbToWrite     += pPipeBuf2->len;
     862                        cPagesToWrite += 1;
     863                    }
     864
     865                    vrc = VbglR0SfHostReqWritePgLst(sf_g->map.root, pReq, sf_r->Handle.hHost, offFile, cbToWrite, cPagesToWrite);
     866                    if (RT_SUCCESS(vrc)) {
     867                        /*
     868                         * Get the number of bytes actually written, update file position
     869                         * and return value, and advance the pipe buffer.
     870                         */
     871                        uint32_t cbActual = pReq->Parms.cb32Write.u.value32;
     872                        AssertStmt(cbActual <= cbToWrite, cbActual = cbToWrite);
     873                        SFLOG2(("vbsf_splice_write: write -> %#x bytes @ %#RX64\n", cbActual, offFile));
     874
     875                        cbRet   += cbActual;
     876                        offFile += cbActual;
     877                        *poffset = offFile;
     878
     879                        while (cbActual > 0) {
     880                            uint32_t cbAdvance = RT_MIN(pPipeBuf->len, cbActual);
     881                            cbActual         -= cbAdvance;
     882                            pPipeBuf->offset += cbAdvance;
     883                            pPipeBuf->len    -= cbAdvance;
     884                            if (!pPipeBuf->len) {
     885                                struct pipe_buf_operations *pOps = pPipeBuf->ops;
     886                                pPipeBuf->ops = NULL;
     887                                pOps->release(pPipe, pPipeBuf);
     888
     889                                pPipe->curbuf  = (pPipe->curbuf + 1) % PIPE_BUFFERS;
     890                                pPipe->nrbufs -= 1;
     891                                pPipeBuf = &pPipe->bufs[pPipe->curbuf];
     892
     893                                fNeedWakeUp |= pPipe->inode != NULL;
     894                            } else {
     895                                Assert(cbActual == 0);
     896                                break;
     897                            }
     898                        }
     899                    } else {
     900                        if (cbRet == 0)
     901                            cbRet = -RTErrConvertToErrno(vrc);
     902                        SFLOGFLOW(("vbsf_splice_write: Write failed: %Rrc -> %zd (cbRet=%#zx)\n",
     903                                   vrc, -RTErrConvertToErrno(vrc), cbRet));
     904                        break;
     905                    }
     906                } else {
     907                    /*
     908                     * Wait for data to become available, if there is chance that'll happen.
     909                     */
     910                    /* Quit if there are no writers (think EOF): */
     911                    if (pPipe->writers == 0) {
     912                        SFLOGFLOW(("vbsf_splice_write: No buffers. No writers. The show is done!\n"));
     913                        break;
     914                    }
     915
     916                    /* Quit if if we've written some and no writers waiting on the lock: */
     917                    if (cbRet > 0 && pPipe->waiting_writers == 0) {
     918                        SFLOGFLOW(("vbsf_splice_write: No waiting writers, returning what we've got.\n"));
     919                        break;
     920                    }
     921
     922                    /* Quit with EAGAIN if non-blocking: */
     923                    if (flags & SPLICE_F_NONBLOCK) {
     924                        if (cbRet == 0)
     925                            cbRet = -EAGAIN;
     926                        break;
     927                    }
     928
     929                    /* Quit if we've got pending signals: */
     930                    if (signal_pending(current)) {
     931                        if (cbRet == 0)
     932                            cbRet = -ERESTARTSYS;
     933                        SFLOGFLOW(("vbsf_splice_write: pending signal! (%zd)\n", cbRet));
     934                        break;
     935                    }
     936
     937                    /* Wake up writers before we start waiting: */
     938                    if (fNeedWakeUp) {
     939                        vbsf_wake_up_pipe(pPipe, false /*fReaders*/);
     940                        fNeedWakeUp = false;
     941                    }
     942                    vbsf_wait_pipe(pPipe);
     943                }
     944            } /* feed loop */
     945
     946            if (fNeedWakeUp)
     947                vbsf_wake_up_pipe(pPipe, false /*fReaders*/);
     948
     949            UNLOCK_PIPE(pPipe);
     950
     951            VbglR0PhysHeapFree(pReq);
     952        } else {
     953            cbRet = -ENOMEM;
     954        }
     955    }
     956    SFLOGFLOW(("vbsf_splice_write: returns %zd (%#zx), *poffset=%#RX64\n", cbRet, cbRet, *poffset));
    799957    return cbRet;
    800958}
     
    29713129#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
    29723130    .splice_read     = vbsf_splice_read,
    2973     /// @todo .splice_write    = vbsf_splice_write,
     3131    .splice_write    = vbsf_splice_write,
    29743132#endif
    29753133#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
Note: See TracChangeset for help on using the changeset viewer.

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