VirtualBox

Changeset 77626 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Mar 8, 2019 9:44:49 PM (6 years ago)
Author:
vboxsync
Message:

linux/vboxsf: Early implementation of file_operations::read_iter to make loop back mounting work of shared folders. 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

    r77561 r77626  
    2929 */
    3030
     31
     32/*********************************************************************************************************************************
     33*   Header Files                                                                                                                 *
     34*********************************************************************************************************************************/
    3135#include "vfsmod.h"
    3236#include <linux/uio.h>
     
    5256
    5357
     58/*********************************************************************************************************************************
     59*   Structures and Typedefs                                                                                                      *
     60*********************************************************************************************************************************/
     61#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
     62/** Used by vbsf_iter_lock_pages() to keep the first page of the next segment. */
     63struct vbsf_iter_stash {
     64    struct page    *pPage;
     65    size_t          off;
     66    size_t          cb;
     67# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
     68    size_t          offFromEnd;
     69    struct iov_iter Copy;
     70# endif
     71};
     72#endif /* >= 3.16.0 */
     73/** Initializer for struct vbsf_iter_stash. */
     74#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
     75# define VBSF_ITER_STASH_INITIALIZER    { NULL, 0 }
     76#else
     77# define VBSF_ITER_STASH_INITIALIZER    { NULL, 0, ~(size_t)0 }
     78#endif
     79
     80
     81
    5482/**
    5583 * Called when an inode is released to unlink all handles that might impossibly
     
    348376#endif /* 2.6.23 <= LINUX_VERSION_CODE < 2.6.31 */
    349377
     378/**
     379 * Helper for deciding wheter we should do a read via the page cache or not.
     380 *
     381 * By default we will only use the page cache if there is a writable memory
     382 * mapping of the file with a chance that it may have modified any of the pages
     383 * already.
     384 */
     385DECLINLINE(bool) vbsf_should_use_cached_read(struct file *file, struct address_space *mapping, struct vbsf_super_info *sf_g)
     386{
     387    return mapping
     388        && mapping->nrpages > 0
     389        && mapping_writably_mapped(mapping)
     390        && !(file->f_flags & O_DIRECT)
     391        && 1 /** @todo make this behaviour configurable at mount time (sf_g) */;
     392}
     393
    350394/** Wrapper around put_page / page_cache_release.  */
    351395DECLINLINE(void) vbsf_put_page(struct page *pPage)
     
    384428        vbsf_put_page(pPage);
    385429    }
     430}
     431
     432
     433/**
     434 * Worker for vbsf_lock_user_pages_failed_check_kernel() and
     435 * vbsf_iter_lock_pages().
     436 */
     437static int vbsf_lock_kernel_pages(uint8_t *pbStart, bool fWrite, size_t cPages, struct page **papPages)
     438{
     439    uintptr_t const uPtrFrom = (uintptr_t)pbStart;
     440    uintptr_t const uPtrLast = (uPtrFrom & ~(uintptr_t)PAGE_OFFSET_MASK) + (cPages << PAGE_SHIFT) - 1;
     441    uint8_t        *pbPage   = (uint8_t *)uPtrLast;
     442    size_t          iPage    = cPages;
     443
     444    /*
     445     * Touch the pages first (paranoia^2).
     446     */
     447    if (fWrite) {
     448        uint8_t volatile *pbProbe = (uint8_t volatile *)uPtrFrom;
     449        while (iPage-- > 0) {
     450            *pbProbe = *pbProbe;
     451            pbProbe += PAGE_SIZE;
     452        }
     453    } else {
     454        uint8_t const *pbProbe = (uint8_t const *)uPtrFrom;
     455        while (iPage-- > 0) {
     456            ASMProbeReadByte(pbProbe);
     457            pbProbe += PAGE_SIZE;
     458        }
     459    }
     460
     461    /*
     462     * Get the pages.
     463     * Note! Fixes here probably applies to rtR0MemObjNativeLockKernel as well.
     464     */
     465    iPage = cPages;
     466    if (   uPtrFrom >= (unsigned long)__va(0)
     467        && uPtrLast <  (unsigned long)high_memory) {
     468        /* The physical page mapping area: */
     469        while (iPage-- > 0) {
     470            struct page *pPage = papPages[iPage] = virt_to_page(pbPage);
     471            vbsf_get_page(pPage);
     472            pbPage -= PAGE_SIZE;
     473        }
     474    } else {
     475        /* This is vmalloc or some such thing, so go thru page tables: */
     476        while (iPage-- > 0) {
     477            struct page *pPage = rtR0MemObjLinuxVirtToPage(pbPage);
     478            if (pPage) {
     479                papPages[iPage] = pPage;
     480                vbsf_get_page(pPage);
     481                pbPage -= PAGE_SIZE;
     482            } else {
     483                while (++iPage < cPages) {
     484                    pPage = papPages[iPage];
     485                    vbsf_put_page(pPage);
     486                }
     487                return -EFAULT;
     488            }
     489        }
     490    }
     491    return 0;
    386492}
    387493
     
    415521#endif
    416522    {
    417         uintptr_t const uPtrLast = (uPtrFrom & ~(uintptr_t)PAGE_OFFSET_MASK) + (cPages << PAGE_SHIFT) - 1;
    418         uint8_t        *pbPage   = (uint8_t *)uPtrLast;
    419         size_t          iPage    = cPages;
    420 
    421         /*
    422          * Touch the pages first (paranoia^2).
    423          */
    424         if (fWrite) {
    425             uint8_t volatile *pbProbe = (uint8_t volatile *)uPtrFrom;
    426             while (iPage-- > 0) {
    427                 *pbProbe = *pbProbe;
    428                 pbProbe += PAGE_SIZE;
    429             }
    430         } else {
    431             uint8_t const *pbProbe = (uint8_t const *)uPtrFrom;
    432             while (iPage-- > 0) {
    433                 ASMProbeReadByte(pbProbe);
    434                 pbProbe += PAGE_SIZE;
    435             }
    436         }
    437 
    438         /*
    439          * Get the pages.
    440          * Note! Fixes here probably applies to rtR0MemObjNativeLockKernel as well.
    441          */
    442         iPage = cPages;
    443         if (   uPtrFrom >= (unsigned long)__va(0)
    444             && uPtrLast <  (unsigned long)high_memory)
    445         {
    446             /* The physical page mapping area: */
    447             while (iPage-- > 0)
    448             {
    449                 struct page *pPage = papPages[iPage] = virt_to_page(pbPage);
    450                 vbsf_get_page(pPage);
    451                 pbPage -= PAGE_SIZE;
    452             }
    453         }
    454         else
    455         {
    456             /* This is vmalloc or some such thing, so go thru page tables: */
    457             while (iPage-- > 0)
    458             {
    459                 struct page *pPage = rtR0MemObjLinuxVirtToPage(pbPage);
    460                 if (pPage) {
    461                     papPages[iPage] = pPage;
    462                     vbsf_get_page(pPage);
    463                     pbPage -= PAGE_SIZE;
    464                 } else {
    465                     while (++iPage < cPages) {
    466                         pPage = papPages[iPage];
    467                         vbsf_put_page(pPage);
    468                     }
    469                     return rcFailed;
    470                 }
    471             }
    472         }
    473         *pfLockPgHack = true;
    474         return 0;
     523        int rc = vbsf_lock_kernel_pages((uint8_t *)uPtrFrom, fWrite, cPages, papPages);
     524        if (rc == 0) {
     525            *pfLockPgHack = true;
     526            return 0;
     527        }
    475528    }
    476529
     
    585638        pReq = (VBOXSFREADPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cMaxPages]));
    586639    }
    587     if (pReq && cPages > RT_ELEMENTS(apPagesStack))
     640    if (pReq && cMaxPages > RT_ELEMENTS(apPagesStack))
    588641        papPagesFree = papPages = kmalloc(cMaxPages * sizeof(sizeof(papPages[0])), GFP_KERNEL);
    589642    if (pReq && papPages) {
     
    610663                    pReq->PgLst.aPages[iPage] = page_to_phys(papPages[iPage]);
    611664            } else {
    612                 /** @todo may need fallback here for kernel addresses during exec. sigh.   */
    613665                cbRet = rc;
    614666                break;
     
    702754     * mappings around with any kind of pages loaded.
    703755     */
    704     if (   mapping
    705         && mapping->nrpages > 0
    706         && mapping_writably_mapped(mapping)
    707         && !(file->f_flags & O_DIRECT)
    708         && 1 /** @todo make this behaviour configurable */ )
     756    if (vbsf_should_use_cached_read(file, mapping, sf_g))
    709757        return vbsf_reg_read_mapped(file, buf, size, off);
    710758
     
    716764        uint32_t const         cbReq = RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0]) + size;
    717765        VBOXSFREADEMBEDDEDREQ *pReq  = (VBOXSFREADEMBEDDEDREQ *)VbglR0PhysHeapAlloc(cbReq);
    718         if (   pReq
    719             && (PAGE_SIZE - ((uintptr_t)pReq & PAGE_OFFSET_MASK)) >= cbReq) {
    720             ssize_t cbRet;
    721             int vrc = VbglR0SfHostReqReadEmbedded(sf_g->map.root, pReq, sf_r->Handle.hHost, *off, (uint32_t)size);
    722             if (RT_SUCCESS(vrc)) {
    723                 cbRet = pReq->Parms.cb32Read.u.value32;
    724                 AssertStmt(cbRet <= (ssize_t)size, cbRet = size);
    725                 if (copy_to_user(buf, pReq->abData, cbRet) == 0)
    726                     *off += cbRet;
    727                 else
    728                     cbRet = -EFAULT;
    729             } else
    730                 cbRet = -EPROTO;
     766        if (pReq) {
     767            if ((PAGE_SIZE - ((uintptr_t)pReq & PAGE_OFFSET_MASK)) >= cbReq) {
     768                ssize_t cbRet;
     769                int vrc = VbglR0SfHostReqReadEmbedded(sf_g->map.root, pReq, sf_r->Handle.hHost, *off, (uint32_t)size);
     770                if (RT_SUCCESS(vrc)) {
     771                    cbRet = pReq->Parms.cb32Read.u.value32;
     772                    AssertStmt(cbRet <= (ssize_t)size, cbRet = size);
     773                    if (copy_to_user(buf, pReq->abData, cbRet) == 0)
     774                        *off += cbRet;
     775                    else
     776                        cbRet = -EFAULT;
     777                } else
     778                    cbRet = -EPROTO;
     779                VbglR0PhysHeapFree(pReq);
     780                return cbRet;
     781            }
    731782            VbglR0PhysHeapFree(pReq);
    732             return cbRet;
    733         }
    734         if (pReq)
    735             VbglR0PhysHeapFree(pReq);
     783        }
    736784    }
    737785
     
    826874        pReq = (VBOXSFWRITEPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cMaxPages]));
    827875    }
    828     if (pReq && cPages > RT_ELEMENTS(apPagesStack))
     876    if (pReq && cMaxPages > RT_ELEMENTS(apPagesStack))
    829877        papPagesFree = papPages = kmalloc(cMaxPages * sizeof(sizeof(papPages[0])), GFP_KERNEL);
    830878    if (pReq && papPages) {
     
    926974    struct vbsf_inode_info *sf_i    = VBSF_GET_INODE_INFO(inode);
    927975    struct vbsf_super_info *sf_g    = VBSF_GET_SUPER_INFO(inode->i_sb);
    928     struct vbsf_reg_info     *sf_r    = file->private_data;
     976    struct vbsf_reg_info   *sf_r    = file->private_data;
    929977    struct address_space   *mapping = inode->i_mapping;
    930978    loff_t                  pos;
     
    934982    BUG_ON(!sf_g);
    935983    BUG_ON(!sf_r);
    936 
    937     if (!S_ISREG(inode->i_mode)) {
    938         LogFunc(("write to non regular file %d\n", inode->i_mode));
    939         return -EINVAL;
    940     }
     984    AssertReturn(S_ISREG(inode->i_mode), -EINVAL);
    941985
    942986    pos = *off;
     
    10441088}
    10451089
     1090#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
     1091
     1092/**
     1093 * Companion to vbsf_iter_lock_pages().
     1094 */
     1095DECLINLINE(void) vbsf_iter_unlock_pages(struct iov_iter *iter, struct page **papPages, size_t cPages, bool fSetDirty)
     1096{
     1097    /* We don't mark kernel pages dirty: */
     1098    if (iter->type & ITER_KVEC)
     1099        fSetDirty = false;
     1100
     1101    while (cPages-- > 0)
     1102    {
     1103        struct page *pPage = papPages[cPages];
     1104        if (fSetDirty && !PageReserved(pPage))
     1105            SetPageDirty(pPage);
     1106        vbsf_put_page(pPage);
     1107    }
     1108}
     1109
     1110
     1111/**
     1112 * Locks up to @a cMaxPages from the I/O vector iterator, advancing the
     1113 * iterator.
     1114 *
     1115 * @returns 0 on success, negative errno value on failure.
     1116 * @param   iter        The iterator to lock pages from.
     1117 * @param   fWrite      Whether to write (true) or read (false) lock the pages.
     1118 * @param   pStash      Where we stash peek results.
     1119 * @param   cMaxPages   The maximum number of pages to get.
     1120 * @param   papPages    Where to return the locked pages.
     1121 * @param   pcPages     Where to return the number of pages.
     1122 * @param   poffPage0   Where to return the offset into the first page.
     1123 * @param   pcbChunk    Where to return the number of bytes covered.
     1124 */
     1125static int vbsf_iter_lock_pages(struct iov_iter *iter, bool fWrite, struct vbsf_iter_stash *pStash, size_t cMaxPages,
     1126                                struct page **papPages, size_t *pcPages, size_t *poffPage0, size_t *pcbChunk)
     1127{
     1128    size_t cbChunk  = 0;
     1129    size_t cPages   = 0;
     1130    size_t offPage0 = 0;
     1131    int    rc       = 0;
     1132
     1133    Assert(iov_iter_count(iter) > 0);
     1134    if (!(iter->type & ITER_KVEC)) {
     1135        /*
     1136         * Do we have a stashed page?
     1137         */
     1138        if (pStash->pPage) {
     1139            papPages[0] = pStash->pPage;
     1140            offPage0    = pStash->off;
     1141            cbChunk     = pStash->cb;
     1142            cPages      = 1;
     1143            pStash->pPage = NULL;
     1144            pStash->off   = 0;
     1145            pStash->cb    = 0;
     1146            if (   offPage0 + cbChunk < PAGE_SIZE
     1147                || iov_iter_count(iter) == 0) {
     1148                *poffPage0 = offPage0;
     1149                *pcbChunk  = cbChunk;
     1150                *pcPages   = cPages;
     1151                return 0;
     1152            }
     1153            cMaxPages -= 1;
     1154        } else {
     1155# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
     1156            /*
     1157             * Copy out our starting point to assist rewinding.
     1158             */
     1159            pStash->offFromEnd = iov_iter_count(iter);
     1160            pStash->Copy       = *iter;
     1161# endif
     1162        }
     1163
     1164        /*
     1165         * Get pages segment by segment.
     1166         */
     1167        do {
     1168            /*
     1169             * Make a special case of the first time thru here, since that's
     1170             * the most typical scenario.
     1171             */
     1172            ssize_t cbSegRet;
     1173            if (cPages == 0) {
     1174                cbSegRet = iov_iter_get_pages(iter, papPages, iov_iter_count(iter), cMaxPages, &offPage0);
     1175                if (cbSegRet > 0) {
     1176                    iov_iter_advance(iter, cbSegRet);
     1177                    cbChunk    = (size_t)cbSegRet;
     1178                    cPages     = RT_ALIGN_Z(offPage0 + cbSegRet, PAGE_SIZE) >> PAGE_SHIFT;
     1179                    cMaxPages -= cPages;
     1180                    if (   cMaxPages == 0
     1181                        || ((offPage0 + (size_t)cbSegRet) & PAGE_OFFSET_MASK))
     1182                        break;
     1183                } else {
     1184                    AssertStmt(cbSegRet < 0, cbSegRet = -EFAULT);
     1185                    rc = (int)cbSegRet;
     1186                    break;
     1187                }
     1188            } else {
     1189                /*
     1190                 * Probe first page of new segment to check that we've got a zero offset and
     1191                 * can continue on the current chunk. Stash the page if the offset isn't zero.
     1192                 */
     1193                size_t offPgProbe;
     1194                size_t cbSeg = iov_iter_single_seg_count(iter);
     1195                while (!cbSeg) {
     1196                    iov_iter_advance(iter, 0);
     1197                    cbSeg = iov_iter_single_seg_count(iter);
     1198                }
     1199                cbSegRet = iov_iter_get_pages(iter, &papPages[cPages], iov_iter_count(iter), 1, &offPgProbe);
     1200                if (cbSegRet > 0) {
     1201                    iov_iter_advance(iter, cbSegRet); /** @todo maybe not do this if we stash the page? */
     1202                    Assert(cbSegRet <= PAGE_SIZE);
     1203                    if (offPgProbe == 0) {
     1204                        cbChunk   += cbSegRet;
     1205                        cPages    += 1;
     1206                        cMaxPages -= 1;
     1207                        if (   cMaxPages == 0
     1208                            || cbSegRet != PAGE_SIZE)
     1209                            break;
     1210
     1211                        /*
     1212                         * Get the rest of the segment (if anything remaining).
     1213                         */
     1214                        cbSeg -= cbSegRet;
     1215                        if (cbSeg > 0) {
     1216                            cbSegRet = iov_iter_get_pages(iter, &papPages[cPages], iov_iter_count(iter), cMaxPages, &offPgProbe);
     1217                            if (cbSegRet > 0) {
     1218                                size_t const cSegsRet = RT_ALIGN_Z((size_t)cbSegRet, PAGE_SIZE) >> PAGE_SHIFT;
     1219                                Assert(offPgProbe == 0);
     1220                                iov_iter_advance(iter, cbSegRet);
     1221                                cPages    += cSegsRet;
     1222                                cMaxPages -= cSegsRet;
     1223                                cbChunk   += cbSegRet;
     1224                                if (   cMaxPages == 0
     1225                                    || ((size_t)cbSegRet & PAGE_OFFSET_MASK))
     1226                                    break;
     1227                            } else {
     1228                                AssertStmt(cbSegRet < 0, cbSegRet = -EFAULT);
     1229                                rc = (int)cbSegRet;
     1230                                break;
     1231                            }
     1232                        }
     1233                    } else {
     1234                        /* The segment didn't start at a page boundrary, so stash it for
     1235                           the next round: */
     1236                        Assert(papPages[cPages]);
     1237                        pStash->pPage = papPages[cPages];
     1238                        pStash->off   = offPage0;
     1239                        pStash->cb    = cbSegRet;
     1240                        break;
     1241                    }
     1242                } else {
     1243                    AssertStmt(cbSegRet < 0, cbSegRet = -EFAULT);
     1244                    rc = (int)cbSegRet;
     1245                    break;
     1246                }
     1247            }
     1248            Assert(cMaxPages > 0);
     1249        } while (iov_iter_count(iter) > 0);
     1250
     1251    } else {
     1252        /*
     1253         * The silly iov_iter_get_pages_alloc() function doesn't handle KVECs,
     1254         * so everyone needs to do that by themselves.
     1255         *
     1256         * Note! Fixes here may apply to rtR0MemObjNativeLockKernel()
     1257         *       and vbsf_lock_user_pages_failed_check_kernel() as well.
     1258         */
     1259# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
     1260        pStash->offFromEnd = iov_iter_count(iter);
     1261        pStash->Copy       = *iter;
     1262# endif
     1263        do {
     1264            uint8_t *pbBuf;
     1265            size_t   offStart;
     1266            size_t   cPgSeg;
     1267
     1268            size_t   cbSeg = iov_iter_single_seg_count(iter);
     1269            while (!cbSeg) {
     1270                iov_iter_advance(iter, 0);
     1271                cbSeg = iov_iter_single_seg_count(iter);
     1272            }
     1273
     1274# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
     1275            pbBuf    = iter->kvec->iov_base + iter->iov_offset;
     1276# else
     1277            pbBuf    = iter->iov->iov_base  + iter->iov_offset;
     1278# endif
     1279            offStart = (uintptr_t)pbBuf & PAGE_OFFSET_MASK;
     1280            if (!cPages)
     1281                offPage0 = offStart;
     1282            else if (offStart)
     1283                break;
     1284
     1285            cPgSeg = RT_ALIGN_Z(cbSeg, PAGE_SIZE) >> PAGE_SHIFT;
     1286            if (cPgSeg > cMaxPages) {
     1287                cPgSeg = cMaxPages;
     1288                cbSeg  = (cPgSeg << PAGE_SHIFT) - offStart;
     1289            }
     1290
     1291            rc = vbsf_lock_kernel_pages(pbBuf, fWrite, cPgSeg, &papPages[cPages]);
     1292            if (rc == 0) {
     1293                iov_iter_advance(iter, cbSeg);
     1294                cbChunk   += cbSeg;
     1295                cPages    += cPgSeg;
     1296                cMaxPages -= cPgSeg;
     1297                if (   cMaxPages == 0
     1298                    || ((offStart + cbSeg) & PAGE_OFFSET_MASK) != 0)
     1299                    break;
     1300            } else
     1301                break;
     1302        } while (iov_iter_count(iter) > 0);
     1303    }
     1304
     1305    /*
     1306     * Clean up if we failed; set return values.
     1307     */
     1308    if (rc == 0) {
     1309        /* likely */
     1310    } else {
     1311        if (cPages > 0)
     1312            vbsf_iter_unlock_pages(iter, papPages, cPages, false /*fSetDirty*/);
     1313        offPage0 = cbChunk = cPages = 0;
     1314    }
     1315    *poffPage0 = offPage0;
     1316    *pcbChunk  = cbChunk;
     1317    *pcPages   = cPages;
     1318    return rc;
     1319}
     1320
     1321
     1322/**
     1323 * Rewinds the I/O vector.
     1324 */
     1325static bool vbsf_iter_rewind(struct iov_iter *iter, struct vbsf_iter_stash *pStash, size_t cbToRewind, size_t cbChunk)
     1326{
     1327    size_t cbExtra;
     1328    if (!pStash->pPage) {
     1329        cbExtra = 0;
     1330    } else {
     1331        cbExtra = pStash->cb;
     1332        vbsf_put_page(pStash->pPage);
     1333        pStash->pPage = NULL;
     1334        pStash->cb    = 0;
     1335        pStash->off   = 0;
     1336    }
     1337
     1338# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
     1339    iov_iter_revert(iter, cbToRewind + cbExtra);
     1340    return true;
     1341# else
     1342    /** @todo impl this   */
     1343    return false;
     1344# endif
     1345}
     1346
     1347
     1348/**
     1349 * Cleans up the page locking stash.
     1350 */
     1351DECLINLINE(void) vbsf_iter_cleanup_stash(struct iov_iter *iter, struct vbsf_iter_stash *pStash)
     1352{
     1353    if (pStash->pPage)
     1354        vbsf_iter_rewind(iter, pStash, 0, 0);
     1355}
     1356
     1357
     1358/**
     1359 * Calculates the longest span of pages we could transfer to the host in a
     1360 * single request.
     1361 *
     1362 * @returns Page count, non-zero.
     1363 * @param   iter        The I/O vector iterator to inspect.
     1364 */
     1365static size_t vbsf_iter_max_span_of_pages(struct iov_iter *iter)
     1366{
     1367    size_t cPages;
     1368    if (iter->type & (ITER_IOVEC | ITER_KVEC)) {
     1369        const struct iovec *pCurIov    = iter->iov;
     1370        size_t              cLeft      = iter->nr_segs;
     1371        size_t              cPagesSpan = 0;
     1372
     1373        AssertCompileMembersSameSizeAndOffset(struct iovec, iov_base, struct kvec, iov_base);
     1374        AssertCompileMembersSameSizeAndOffset(struct iovec, iov_len,  struct kvec, iov_len);
     1375        AssertCompile(sizeof(struct iovec) == sizeof(struct kvec));
     1376
     1377        cPages = 1;
     1378        AssertReturn(cLeft > 0, cPages);
     1379
     1380        /* Special case: segment offset. */
     1381        if (iter->iov_offset > 0) {
     1382            if (iter->iov_offset < pCurIov->iov_len) {
     1383                size_t const cbSegLeft = pCurIov->iov_len - iter->iov_offset;
     1384                size_t const offPage0  = ((uintptr_t)pCurIov->iov_base + iter->iov_offset) & PAGE_OFFSET_MASK;
     1385                cPages = cPagesSpan = RT_ALIGN_Z(offPage0 + cbSegLeft, PAGE_SIZE) >> PAGE_SHIFT;
     1386                if ((offPage0 + cbSegLeft) & PAGE_OFFSET_MASK)
     1387                    cPagesSpan = 0;
     1388            }
     1389            pCurIov++;
     1390            cLeft--;
     1391        }
     1392
     1393        /* Full segments. */
     1394        while (cLeft-- > 0) {
     1395            if (pCurIov->iov_len > 0) {
     1396                size_t const offPage0 = (uintptr_t)pCurIov->iov_base & PAGE_OFFSET_MASK;
     1397                if (offPage0 == 0) {
     1398                    if (!(pCurIov->iov_len & PAGE_OFFSET_MASK)) {
     1399                        cPagesSpan += pCurIov->iov_len >> PAGE_SHIFT;
     1400                    } else {
     1401                        cPagesSpan += RT_ALIGN_Z(pCurIov->iov_len, PAGE_SIZE) >> PAGE_SHIFT;
     1402                        if (cPagesSpan > cPages)
     1403                            cPages = cPagesSpan;
     1404                        cPagesSpan = 0;
     1405                    }
     1406                } else {
     1407                    if (cPagesSpan > cPages)
     1408                        cPages = cPagesSpan;
     1409                    if (!((offPage0 + pCurIov->iov_len) & PAGE_OFFSET_MASK)) {
     1410                        cPagesSpan = pCurIov->iov_len >> PAGE_SHIFT;
     1411                    } else {
     1412                        cPagesSpan += RT_ALIGN_Z(offPage0 + pCurIov->iov_len, PAGE_SIZE) >> PAGE_SHIFT;
     1413                        if (cPagesSpan > cPages)
     1414                            cPages = cPagesSpan;
     1415                        cPagesSpan = 0;
     1416                    }
     1417                }
     1418            }
     1419            pCurIov++;
     1420        }
     1421        if (cPagesSpan > cPages)
     1422            cPages = cPagesSpan;
     1423    } else  {
     1424        /* Won't bother with accurate counts for the next two types, just make
     1425           some rough estimates (does pipes have segments?): */
     1426        size_t cSegs = iter->type & ITER_BVEC ? RT_MAX(1, iter->nr_segs) : 1;
     1427        cPages = (iov_iter_count(iter) + (PAGE_SIZE * 2 - 2) * cSegs) >> PAGE_SHIFT;
     1428    }
     1429    return cPages;
     1430}
     1431
     1432
     1433/**
     1434 * Worker for vbsf_reg_read_iter() that deals with larger reads using page
     1435 * locking.
     1436 */
     1437static ssize_t vbsf_reg_read_iter_locking(struct kiocb *kio, struct iov_iter *iter, size_t cbToRead,
     1438                                          struct vbsf_super_info *sf_g, struct vbsf_reg_info *sf_r)
     1439{
     1440    /*
     1441     * Estimate how many pages we may possible submit in a single request so
     1442     * that we can allocate matching request buffer and page array.
     1443     */
     1444    struct page        *apPagesStack[16];
     1445    struct page       **papPages     = &apPagesStack[0];
     1446    struct page       **papPagesFree = NULL;
     1447    VBOXSFREADPGLSTREQ *pReq;
     1448    ssize_t             cbRet        = 0;
     1449    size_t              cMaxPages    = vbsf_iter_max_span_of_pages(iter);
     1450    cMaxPages = RT_MIN(RT_MAX(sf_g->cMaxIoPages, 2), cMaxPages);
     1451
     1452    pReq = (VBOXSFREADPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cMaxPages]));
     1453    while (!pReq && cMaxPages > 4) {
     1454        cMaxPages /= 2;
     1455        pReq = (VBOXSFREADPGLSTREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cMaxPages]));
     1456    }
     1457    if (pReq && cMaxPages > RT_ELEMENTS(apPagesStack))
     1458        papPagesFree = papPages = kmalloc(cMaxPages * sizeof(sizeof(papPages[0])), GFP_KERNEL);
     1459    if (pReq && papPages) {
     1460
     1461        /*
     1462         * The read loop.
     1463         */
     1464        struct vbsf_iter_stash Stash = VBSF_ITER_STASH_INITIALIZER;
     1465        do {
     1466            /*
     1467             * Grab as many pages as we can.  This means that if adjacent
     1468             * segments both starts and ends at a page boundrary, we can
     1469             * do them both in the same transfer from the host.
     1470             */
     1471            size_t cPages   = 0;
     1472            size_t cbChunk  = 0;
     1473            size_t offPage0 = 0;
     1474            int rc = vbsf_iter_lock_pages(iter, true /*fWrite*/, &Stash, cMaxPages, papPages, &cPages, &offPage0, &cbChunk);
     1475            if (rc == 0) {
     1476                size_t iPage = cPages;
     1477                while (iPage-- > 0)
     1478                    pReq->PgLst.aPages[iPage] = page_to_phys(papPages[iPage]);
     1479                pReq->PgLst.offFirstPage = (uint16_t)offPage0;
     1480                AssertStmt(cbChunk <= cbToRead, cbChunk = cbToRead);
     1481            } else {
     1482                cbRet = rc;
     1483                break;
     1484            }
     1485
     1486            /*
     1487             * Issue the request and unlock the pages.
     1488             */
     1489            rc = VbglR0SfHostReqReadPgLst(sf_g->map.root, pReq, sf_r->Handle.hHost, kio->ki_pos, cbChunk, cPages);
     1490            SFLOGFLOW(("vbsf_reg_read_iter_locking: VbglR0SfHostReqReadPgLst -> %d (cbActual=%#x cbChunk=%#zx of %#zx cPages=%#zx offPage0=%#x\n",
     1491                       rc, pReq->Parms.cb32Read.u.value32, cbChunk, cbToRead, cPages, offPage0));
     1492
     1493            vbsf_iter_unlock_pages(iter, papPages, cPages, true /*fSetDirty*/);
     1494
     1495            if (RT_SUCCESS(rc)) {
     1496                /*
     1497                 * Success, advance position and buffer.
     1498                 */
     1499                uint32_t cbActual = pReq->Parms.cb32Read.u.value32;
     1500                AssertStmt(cbActual <= cbChunk, cbActual = cbChunk);
     1501                cbRet       += cbActual;
     1502                kio->ki_pos += cbActual;
     1503                cbToRead    -= cbActual;
     1504
     1505                /*
     1506                 * Are we done already?
     1507                 */
     1508                if (!cbToRead)
     1509                    break;
     1510                if (cbActual < cbChunk) { /* We ASSUME end-of-file here. */
     1511                    if (vbsf_iter_rewind(iter, &Stash, cbChunk - cbActual, cbActual))
     1512                        iov_iter_truncate(iter, 0);
     1513                    break;
     1514                }
     1515            } else {
     1516                /*
     1517                 * Try rewind the iter structure.
     1518                 */
     1519                bool const fRewindOkay = vbsf_iter_rewind(iter, &Stash, cbChunk, cbChunk);
     1520                if (rc == VERR_NO_MEMORY && cMaxPages > 4 && fRewindOkay) {
     1521                    /*
     1522                     * The host probably doesn't have enough heap to handle the
     1523                     * request, reduce the page count and retry.
     1524                     */
     1525                    cMaxPages /= 4;
     1526                    Assert(cMaxPages > 0);
     1527                } else {
     1528                    /*
     1529                     * If we've successfully read stuff, return it rather than
     1530                     * the error.  (Not sure if this is such a great idea...)
     1531                     */
     1532                    if (cbRet <= 0)
     1533                        cbRet = -EPROTO;
     1534                    break;
     1535                }
     1536            }
     1537        } while (cbToRead > 0);
     1538
     1539        vbsf_iter_cleanup_stash(iter, &Stash);
     1540    }
     1541    else
     1542        cbRet = -ENOMEM;
     1543    if (papPagesFree)
     1544        kfree(papPages);
     1545    if (pReq)
     1546        VbglR0PhysHeapFree(pReq);
     1547    SFLOGFLOW(("vbsf_reg_read_iter_locking: returns %#zx (%zd)\n", cbRet, cbRet));
     1548    return cbRet;
     1549}
     1550
     1551
     1552/**
     1553 * Read into I/O vector iterator.
     1554 *
     1555 * @returns Number of bytes read on success, negative errno on error.
     1556 * @param   kio         The kernel I/O control block (or something like that).
     1557 * @param   iter        The I/O vector iterator describing the buffer.
     1558 */
     1559static ssize_t vbsf_reg_read_iter(struct kiocb *kio, struct iov_iter *iter)
     1560{
     1561    size_t                  cbToRead = iov_iter_count(iter);
     1562    struct inode           *inode    = VBSF_GET_F_DENTRY(kio->ki_filp)->d_inode;
     1563    struct address_space   *mapping  = inode->i_mapping;
     1564
     1565    struct vbsf_reg_info   *sf_r     = kio->ki_filp->private_data;
     1566    struct vbsf_super_info *sf_g     = VBSF_GET_SUPER_INFO(inode->i_sb);
     1567
     1568    SFLOGFLOW(("vbsf_reg_read_iter: inode=%p file=%p size=%#zx off=%#llx type=%#x\n",
     1569               inode, kio->ki_filp, cbToRead, kio->ki_pos, iter->type));
     1570    AssertReturn(S_ISREG(inode->i_mode), -EINVAL);
     1571
     1572    /*
     1573     * Do we have anything at all to do here?
     1574     */
     1575    if (!cbToRead)
     1576        return 0;
     1577
     1578    /*
     1579     * If there is a mapping and O_DIRECT isn't in effect, we must at a
     1580     * heed dirty pages in the mapping and read from them.  For simplicity
     1581     * though, we just do page cache reading when there are writable
     1582     * mappings around with any kind of pages loaded.
     1583     */
     1584    if (vbsf_should_use_cached_read(kio->ki_filp, mapping, sf_g))
     1585        return generic_file_read_iter(kio, iter);
     1586
     1587    /*
     1588     * Now now we reject async I/O requests.
     1589     */
     1590    if (!is_sync_kiocb(kio)) {
     1591        SFLOGFLOW(("vbsf_reg_read_iter: async I/O not yet supported\n")); /** @todo extend FsPerf with AIO tests. */
     1592        return -EOPNOTSUPP;
     1593    }
     1594
     1595    /*
     1596     * For small requests, try use an embedded buffer provided we get a heap block
     1597     * that does not cross page boundraries (see host code).
     1598     */
     1599    if (cbToRead <= PAGE_SIZE / 4 * 3 - RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0]) /* see allocator */) {
     1600        uint32_t const         cbReq = RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0]) + cbToRead;
     1601        VBOXSFREADEMBEDDEDREQ *pReq  = (VBOXSFREADEMBEDDEDREQ *)VbglR0PhysHeapAlloc(cbReq);
     1602        if (pReq) {
     1603            if ((PAGE_SIZE - ((uintptr_t)pReq & PAGE_OFFSET_MASK)) >= cbReq) {
     1604                ssize_t cbRet;
     1605                int vrc = VbglR0SfHostReqReadEmbedded(sf_g->map.root, pReq, sf_r->Handle.hHost, kio->ki_pos, (uint32_t)cbToRead);
     1606                if (RT_SUCCESS(vrc)) {
     1607                    cbRet = pReq->Parms.cb32Read.u.value32;
     1608                    AssertStmt(cbRet <= (ssize_t)cbToRead, cbRet = cbToRead);
     1609                    if (copy_to_iter(pReq->abData, cbRet, iter) == cbRet) {
     1610                        kio->ki_pos += cbRet;
     1611                        if (cbRet < cbToRead)
     1612                            iov_iter_truncate(iter, 0);
     1613                    } else
     1614                        cbRet = -EFAULT;
     1615                } else
     1616                    cbRet = -EPROTO;
     1617                VbglR0PhysHeapFree(pReq);
     1618                SFLOGFLOW(("vbsf_reg_read_iter: returns %#zx (%zd)\n", cbRet, cbRet));
     1619                return cbRet;
     1620            }
     1621            VbglR0PhysHeapFree(pReq);
     1622        }
     1623    }
     1624
     1625    /*
     1626     * Otherwise do the page locking thing.
     1627     */
     1628    return vbsf_reg_read_iter_locking(kio, iter, cbToRead, sf_g, sf_r);
     1629}
     1630
     1631
     1632static ssize_t vbsf_reg_write_iter(struct kiocb *kio, struct iov_iter *iter)
     1633{
     1634    SFLOGFLOW(("vbsf_reg_write_iter: -> EINVAL\n"));
     1635    return -EINVAL;
     1636}
     1637
     1638#endif /* >= 3.16.0 */
    10461639
    10471640/**
     
    13361929 */
    13371930struct file_operations vbsf_reg_fops = {
    1338     .read = vbsf_reg_read,
    1339     .open = vbsf_reg_open,
    1340     .write = vbsf_reg_write,
    1341     .release = vbsf_reg_release,
    1342     .mmap = generic_file_mmap,
     1931    .open        = vbsf_reg_open,
     1932    .read        = vbsf_reg_read,
     1933    .write       = vbsf_reg_write,
     1934#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
     1935    .read_iter   = vbsf_reg_read_iter,
     1936    .write_iter  = vbsf_reg_write_iter,
     1937#endif
     1938    .release     = vbsf_reg_release,
     1939    .mmap        = generic_file_mmap,
    13431940#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
    13441941# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
     
    13481945    .splice_read = vbsf_splice_read,
    13491946# else
    1350     .sendfile = generic_file_sendfile,
     1947    .sendfile    = generic_file_sendfile,
    13511948# endif
    1352     .aio_read = generic_file_aio_read,
    1353     .aio_write = generic_file_aio_write,
     1949    .aio_read    = generic_file_aio_read,
     1950    .aio_write   = generic_file_aio_write,
    13541951# endif
    13551952#endif
    1356     .llseek = vbsf_reg_llseek,
    1357     .fsync = vbsf_reg_fsync,
     1953    .llseek      = vbsf_reg_llseek,
     1954    .fsync       = vbsf_reg_fsync,
    13581955};
    13591956
  • trunk/src/VBox/Additions/linux/sharedfolders/vfsmod.c

    r77542 r77626  
    120120       happens, which isn't too efficient. */
    121121    sf_g->cMaxIoPages = RT_MIN(_16K / sizeof(RTGCPHYS64) /* => 8MB buffer */,
    122                    VMMDEV_MAX_HGCM_DATA_SIZE >> PAGE_SHIFT);
     122                               VMMDEV_MAX_HGCM_DATA_SIZE >> PAGE_SHIFT);
    123123    if (   (unsigned)info->length >= sizeof(struct vbsf_mount_info_new)
    124         && info->cMaxIoPages != 0) {
     124        && info->cMaxIoPages > 0) {
    125125        if (info->cMaxIoPages <= VMMDEV_MAX_HGCM_DATA_SIZE >> PAGE_SHIFT)
    126             sf_g->cMaxIoPages = info->cMaxIoPages;
     126            sf_g->cMaxIoPages = RT_MAX(info->cMaxIoPages, 2); /* read_iter/write_iter requires a minimum of 2. */
    127127        else
    128128            printk(KERN_WARNING "vboxsf: max I/O page count (%#x) is out of range, using default (%#x) instead.\n",
    129                     info->cMaxIoPages, sf_g->cMaxIoPages);
     129                   info->cMaxIoPages, sf_g->cMaxIoPages);
    130130    }
    131131}
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