VirtualBox

Changeset 77539 in vbox


Ignore:
Timestamp:
Mar 2, 2019 8:47:13 PM (6 years ago)
Author:
vboxsync
Message:

linux/vboxsf: Protect our vboxsf_dir_info structure with a semaphore against concurrent threads accessing it when we now implement .iterate_shared rather than .iterate on 4.7+ kernels. Merged vbsf_dir_open_worker() into vbsf_dir_open. bugref:9172

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

Legend:

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

    r77538 r77539  
    3434
    3535/**
    36  * Reads or re-reads a directory.
    37  *
    38  * @note As suggested a couple of other places, we should probably stop
    39  *       reading in the whole directory on open.
    40  *
    41  * @todo merge with caller now that the VBSF_BUFFER_DIRS code is gonne.
    42  */
    43 static int vbsf_dir_open_worker(struct dentry *pDirEntry, struct inode *pInode, struct vbsf_inode_info *sf_i,
    44                                 struct vbsf_dir_info *sf_d, struct vbsf_super_info *sf_g, const char *pszCaller)
    45 {
    46     union SfDirOpenCloseReq
    47     {
    48         VBOXSFCREATEREQ Create;
    49         VBOXSFCLOSEREQ  Close;
    50     } *pReq;
    51     int err;
    52 
    53     pReq = (union SfDirOpenCloseReq *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + sf_i->path->u16Size);
    54     if (pReq) {
    55         int rc;
    56 
    57         memcpy(&pReq->Create.StrPath, sf_i->path, SHFLSTRING_HEADER_SIZE + sf_i->path->u16Size);
    58         RT_ZERO(pReq->Create.CreateParms);
    59         pReq->Create.CreateParms.Handle      = SHFL_HANDLE_NIL;
    60         pReq->Create.CreateParms.CreateFlags = SHFL_CF_DIRECTORY
    61                                              | SHFL_CF_ACT_OPEN_IF_EXISTS
    62                                              | SHFL_CF_ACT_FAIL_IF_NEW
    63                                              | SHFL_CF_ACCESS_READ;
    64 
    65         LogFunc(("calling VbglR0SfHostReqCreate on folder %s, flags %#x [caller: %s]\n",
    66                  sf_i->path->String.utf8, pReq->Create.CreateParms.CreateFlags, pszCaller));
    67         rc = VbglR0SfHostReqCreate(sf_g->map.root, &pReq->Create);
    68         if (RT_SUCCESS(rc)) {
    69             if (pReq->Create.CreateParms.Result == SHFL_FILE_EXISTS) {
    70                 Assert(pReq->Create.CreateParms.Handle != SHFL_HANDLE_NIL);
    71 
    72                 /*
    73                  * Update the inode info with fresh stats and increase the TTL for the
    74                  * dentry cache chain that got us here.
    75                  */
    76                 vbsf_update_inode(pInode, sf_i, &pReq->Create.CreateParms.Info, sf_g, true /*fLocked*/ /** @todo inode locking */);
    77                 vbsf_dentry_chain_increase_ttl(pDirEntry);
    78 
    79                 sf_d->Handle.hHost  = pReq->Create.CreateParms.Handle;
    80                 sf_d->Handle.cRefs  = 1;
    81                 sf_d->Handle.fFlags = VBSF_HANDLE_F_READ | VBSF_HANDLE_F_DIR | VBSF_HANDLE_F_MAGIC;
    82                 vbsf_handle_append(sf_i, &sf_d->Handle);
    83 
    84                 VbglR0PhysHeapFree(pReq);
    85                 return 0;
    86             }
    87 
    88             /*
    89              * Directory does not exist, so we probably got some invalid
    90              * dir cache and inode info.
    91              */
    92             /** @todo do more to invalidate dentry and inode here. */
    93             vbsf_dentry_set_update_jiffies(pDirEntry, jiffies + INT_MAX / 2);
    94             sf_i->force_restat = true;
    95             err = -ENOENT;
    96 
    97             AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
    98             if (pReq->Create.CreateParms.Handle != SHFL_HANDLE_NIL) {
    99                 rc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, pReq->Create.CreateParms.Handle);
    100                 if (RT_FAILURE(rc))
    101                     LogFunc(("VbglR0SfHostReqCloseSimple(%s) after err=%d failed rc=%Rrc caller=%s\n",
    102                              sf_i->path->String.utf8, err, rc, pszCaller));
    103             }
    104         } else
    105             err = -EPERM;
    106 
    107         VbglR0PhysHeapFree(pReq);
    108     } else {
    109         LogRelMaxFunc(64, ("failed to allocate %zu bytes for '%s' [caller: %s]\n",
    110                            RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + sf_i->path->u16Size,
    111                            sf_i->path->String.ach, pszCaller));
    112         err = -ENOMEM;
    113     }
    114     return err;
    115 }
    116 
    117 /**
    118  * Open a directory. Read the complete content into a buffer.
     36 * Open a directory.
    11937 *
    12038 * @param inode     inode
     
    14159    sf_d = kmalloc(sizeof(*sf_d), GFP_KERNEL);
    14260    if (sf_d) {
     61        VBOXSFCREATEREQ *pReq;
    14362        RT_ZERO(*sf_d);
    14463        sf_d->u32Magic = VBSF_DIR_INFO_MAGIC;
     64        sema_init(&sf_d->Lock, 1);
    14565
    14666        /*
    14767         * Try open the directory.
    14868         */
    149         rc = vbsf_dir_open_worker(dentry, inode, sf_i, sf_d, sf_g, "vbsf_dir_open");
    150         if (!rc)
    151             file->private_data = sf_d;
    152         else {
    153             sf_d->u32Magic = VBSF_DIR_INFO_MAGIC_DEAD;
    154             kfree(sf_d);
    155         }
     69        pReq = (VBOXSFCREATEREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + sf_i->path->u16Size);
     70        if (pReq) {
     71            memcpy(&pReq->StrPath, sf_i->path, SHFLSTRING_HEADER_SIZE + sf_i->path->u16Size);
     72            RT_ZERO(pReq->CreateParms);
     73            pReq->CreateParms.Handle      = SHFL_HANDLE_NIL;
     74            pReq->CreateParms.CreateFlags = SHFL_CF_DIRECTORY
     75                                          | SHFL_CF_ACT_OPEN_IF_EXISTS
     76                                          | SHFL_CF_ACT_FAIL_IF_NEW
     77                                          | SHFL_CF_ACCESS_READ;
     78
     79            LogFunc(("calling VbglR0SfHostReqCreate on folder %s, flags %#x\n",
     80                     sf_i->path->String.utf8, pReq->CreateParms.CreateFlags));
     81            rc = VbglR0SfHostReqCreate(sf_g->map.root, pReq);
     82            if (RT_SUCCESS(rc)) {
     83                if (pReq->CreateParms.Result == SHFL_FILE_EXISTS) {
     84                    Assert(pReq->CreateParms.Handle != SHFL_HANDLE_NIL);
     85
     86                    /*
     87                     * Update the inode info with fresh stats and increase the TTL for the
     88                     * dentry cache chain that got us here.
     89                     */
     90                    vbsf_update_inode(inode, sf_i, &pReq->CreateParms.Info, sf_g, true /*fLocked*/ /** @todo inode locking */);
     91                    vbsf_dentry_chain_increase_ttl(dentry);
     92
     93                    sf_d->Handle.hHost  = pReq->CreateParms.Handle;
     94                    sf_d->Handle.cRefs  = 1;
     95                    sf_d->Handle.fFlags = VBSF_HANDLE_F_READ | VBSF_HANDLE_F_DIR | VBSF_HANDLE_F_MAGIC;
     96                    vbsf_handle_append(sf_i, &sf_d->Handle);
     97
     98                    file->private_data = sf_d;
     99                    VbglR0PhysHeapFree(pReq);
     100                    return 0;
     101
     102                }
     103                Assert(pReq->CreateParms.Handle == SHFL_HANDLE_NIL);
     104
     105                /*
     106                 * Directory does not exist, so we probably got some invalid
     107                 * dir cache and inode info.
     108                 */
     109                /** @todo do more to invalidate dentry and inode here. */
     110                vbsf_dentry_set_update_jiffies(dentry, jiffies + INT_MAX / 2);
     111                sf_i->force_restat = true;
     112                rc = -ENOENT;
     113            } else
     114                rc = -EPERM;
     115            VbglR0PhysHeapFree(pReq);
     116        } else {
     117            LogRelMaxFunc(64, ("failed to allocate %zu bytes for '%s'\n",
     118                               RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + sf_i->path->u16Size, sf_i->path->String.ach));
     119            rc = -ENOMEM;
     120        }
     121        sf_d->u32Magic = VBSF_DIR_INFO_MAGIC_DEAD;
     122        kfree(sf_d);
    156123    } else
    157124        rc = -ENOMEM;
    158125    return rc;
    159126}
     127
    160128
    161129/**
     
    355323    struct vbsf_dir_info   *sf_d    = (struct vbsf_dir_info *)dir->private_data;
    356324    struct vbsf_super_info *sf_g    = VBSF_GET_SUPER_INFO(VBSF_GET_F_DENTRY(dir)->d_sb);
     325    int                     rc;
     326
     327    /*
     328     * Lock the directory info structures.
     329     */
     330    if (RT_LIKELY(down_interruptible(&sf_d->Lock) == 0)) {
     331        /* likely */
     332    } else
     333        return -ERESTARTSYS;
    357334
    358335    /*
     
    362339        /* likely */
    363340    } else {
    364         int rc;
    365 
    366341        /* Restart the search if iPos is lower than the current buffer position. */
    367342        loff_t offCurEntry = sf_d->offPos;
     
    370345            if (rc == 0)
    371346                offCurEntry = 0;
    372             else
     347            else {
     348                up(&sf_d->Lock);
    373349                return rc;
     350            }
    374351        }
    375352
     
    383360                sf_d->cEntriesLeft = 0;
    384361                rc = vbsf_dir_read_more(sf_d, sf_g, false /*fRestart*/);
    385                 if (rc != 0 || sf_d->cEntriesLeft == 0)
     362                if (rc != 0 || sf_d->cEntriesLeft == 0) {
     363                    up(&sf_d->Lock);
    386364                    return rc;
     365                }
    387366            } else {
    388367                do
     
    411390            if (dir_emit_dot(dir, ctx))
    412391                dir->f_pos = ctx->pos = sf_d->offPos = offPos = 1;
    413             else
     392            else {
     393                up(&sf_d->Lock);
    414394                return 0;
     395            }
    415396        }
    416397        if (offPos == 1) {
    417398            if (dir_emit_dotdot(dir, ctx))
    418399                dir->f_pos = ctx->pos = sf_d->offPos = offPos = 2;
    419             else
     400            else {
     401                up(&sf_d->Lock);
    420402                return 0;
     403            }
    421404        }
    422405#else
    423406        if (offPos == 0) {
    424             int rc = filldir(opaque, ".", 1, 0, VBSF_GET_F_DENTRY(dir)->d_inode->i_ino, DT_DIR);
     407            rc = filldir(opaque, ".", 1, 0, VBSF_GET_F_DENTRY(dir)->d_inode->i_ino, DT_DIR);
    425408            if (!rc)
    426409                dir->f_pos = sf_d->offPos = offPos = 1;
    427             else
     410            else {
     411                up(&sf_d->Lock);
    428412                return 0;
     413            }
    429414        }
    430415        if (offPos == 1) {
    431416# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5)
    432             int rc = filldir(opaque, "..", 2, 1, parent_ino(VBSF_GET_F_DENTRY(dir)), DT_DIR);
     417            rc = filldir(opaque, "..", 2, 1, parent_ino(VBSF_GET_F_DENTRY(dir)), DT_DIR);
    433418# else
    434             int rc = filldir(opaque, "..", 2, 1, VBSF_GET_F_DENTRY(dir)->d_parent->d_inode->i_ino, DT_DIR);
     419            rc = filldir(opaque, "..", 2, 1, VBSF_GET_F_DENTRY(dir)->d_parent->d_inode->i_ino, DT_DIR);
    435420# endif
    436421            if (!rc)
    437422                dir->f_pos = sf_d->offPos = offPos = 2;
    438             else
     423            else {
     424                up(&sf_d->Lock);
    439425                return 0;
     426            }
    440427        }
    441428#endif
     
    456443        uint32_t cEntriesLeft = sf_d->cEntriesLeft;
    457444        if (!cEntriesLeft) {
    458             int rc = vbsf_dir_read_more(sf_d, sf_g, false /*fRestart*/);
     445            rc = vbsf_dir_read_more(sf_d, sf_g, false /*fRestart*/);
    459446            if (rc == 0) {
    460447                cEntriesLeft = sf_d->cEntriesLeft;
    461                 if (!cEntriesLeft)
     448                if (!cEntriesLeft) {
     449                    up(&sf_d->Lock);
    462450                    return 0;
     451                }
    463452                cbValid = sf_d->cbValid;
    464             }
    465             else
     453            } else {
     454                up(&sf_d->Lock);
    466455                return rc;
     456            }
    467457        }
    468458
     
    518508                    sf_d->pEntry       = pEntry;
    519509                    sf_d->offPos       = offPos;
     510                    up(&sf_d->Lock);
    520511                    return 0;
    521512                }
     
    547538    .open = vbsf_dir_open,
    548539#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
    549     .iterate = vbsf_dir_iterate, /** @todo Consider .iterate_shared (shared vs exclusive inode lock) here.  Need to consider
    550                                   * whether struct vbsf_dir_info is safe in multithreaded apps doing readdir in parallel on
    551                                   * the same handle.  */
     540    .iterate_shared = vbsf_dir_iterate,
    552541#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
    553542    .iterate = vbsf_dir_iterate,
  • trunk/src/VBox/Additions/linux/sharedfolders/vfsmod.h

    r77538 r77539  
    273273     * @note Must be first!  */
    274274    struct vbsf_handle  Handle;
     275    /** Semaphore protecting everything below. */
     276    struct semaphore    Lock;
    275277    /** A magic number (VBSF_DIR_INFO_MAGIC). */
    276278    uint32_t            u32Magic;
     
    283285    /** Number of entries left in the buffer.   */
    284286    uint32_t            cEntriesLeft;
    285     /** The position of the next entry.  Incremented by one for each entry.  */
     287    /** The position of the next entry.  Incremented by one for each entry. */
    286288    loff_t              offPos;
    287289    /** The next entry. */
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