VirtualBox

Changeset 77561 in vbox for trunk/src/VBox/Additions/linux


Ignore:
Timestamp:
Mar 4, 2019 7:56:32 PM (6 years ago)
Author:
vboxsync
Message:

linux/vboxsf: Rewrote vbsf_inode_setattr() to use open file/dir handles when possible and avoid the extra stat() call at the end. Good speedups for chsize, fchmod and futimes. Let 2.4.x kernel change attributes too. bugref:9172

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

Legend:

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

    r77559 r77561  
    11171117#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 18)
    11181118    .getattr = vbsf_inode_getattr,
     1119#else
     1120    .revalidate = vbsf_inode_revalidate,
     1121#endif
    11191122    .setattr = vbsf_inode_setattr,
    1120 #else
    1121     .revalidate = vbsf_inode_revalidate
    1122 #endif
    11231123#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
    1124     .symlink = vbsf_ino_symlink
     1124    .symlink = vbsf_ino_symlink,
    11251125#endif
    11261126};
  • trunk/src/VBox/Additions/linux/sharedfolders/regops.c

    r77559 r77561  
    13611361#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 18)
    13621362    .getattr = vbsf_inode_getattr,
    1363     .setattr = vbsf_inode_setattr
    13641363#else
    1365     .revalidate = vbsf_inode_revalidate
    1366 #endif
     1364    .revalidate = vbsf_inode_revalidate,
     1365#endif
     1366    .setattr = vbsf_inode_setattr,
    13671367};
    13681368
  • trunk/src/VBox/Additions/linux/sharedfolders/utils.c

    r77559 r77561  
    571571
    572572        /* Add birth time. */
    573 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
     573# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
    574574        if (dentry->d_inode) {
    575575            struct vbsf_inode_info *pInodeInfo = VBSF_GET_INODE_INFO(dentry->d_inode);
     
    579579            }
    580580        }
    581 #endif
     581# endif
    582582
    583583        /*
     
    608608    return rc;
    609609}
    610 
    611 
     610#endif /* >= 2.5.18 */
     611
     612
     613/**
     614 * Modify inode attributes.
     615 */
    612616int vbsf_inode_setattr(struct dentry *dentry, struct iattr *iattr)
    613617{
    614     struct vbsf_super_info *sf_g;
    615     struct vbsf_inode_info *sf_i;
    616     union SetAttrReqs
    617     {
    618         VBOXSFCREATEREQ         Create;
    619         VBOXSFOBJINFOREQ        Info;
    620         VBOXSFSETFILESIZEREQ    SetSize;
    621         VBOXSFCLOSEREQ          Close;
    622     } *pReq;
    623     size_t cbReq;
    624     SHFLHANDLE hHostFile;
     618    struct inode           *pInode = dentry->d_inode;
     619    struct vbsf_super_info *sf_g   = VBSF_GET_SUPER_INFO(pInode->i_sb);
     620    struct vbsf_inode_info *sf_i   = VBSF_GET_INODE_INFO(pInode);
    625621    int vrc;
    626     int err = 0;
    627 
    628     TRACE();
    629 
    630     sf_g = VBSF_GET_SUPER_INFO(dentry->d_inode->i_sb);
    631     sf_i = VBSF_GET_INODE_INFO(dentry->d_inode);
    632     cbReq = RT_MAX(sizeof(pReq->Info), sizeof(pReq->Create) + SHFLSTRING_HEADER_SIZE + sf_i->path->u16Size);
    633     pReq = (union SetAttrReqs *)VbglR0PhysHeapAlloc(cbReq);
    634     if (!pReq) {
    635         LogFunc(("Failed to allocate %#x byte request buffer!\n", cbReq));
    636         return -ENOMEM;
    637     }
    638 
    639     RT_ZERO(pReq->Create.CreateParms);
    640     pReq->Create.CreateParms.Handle      = SHFL_HANDLE_NIL;
    641     pReq->Create.CreateParms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS
    642                                          | SHFL_CF_ACT_FAIL_IF_NEW
    643                                          | SHFL_CF_ACCESS_ATTR_WRITE;
    644 
    645     /* this is at least required for Posix hosts */
    646     if (iattr->ia_valid & ATTR_SIZE)
    647         pReq->Create.CreateParms.CreateFlags |= SHFL_CF_ACCESS_WRITE;
    648 
    649     memcpy(&pReq->Create.StrPath, sf_i->path, SHFLSTRING_HEADER_SIZE + sf_i->path->u16Size);
    650     vrc = VbglR0SfHostReqCreate(sf_g->map.root, &pReq->Create);
    651     if (RT_SUCCESS(vrc)) {
    652         hHostFile = pReq->Create.CreateParms.Handle;
    653     } else {
    654         err = -RTErrConvertToErrno(vrc);
    655         LogFunc(("VbglR0SfCreate(%s) failed vrc=%Rrc err=%d\n", sf_i->path->String.ach, vrc, err));
    656         goto fail2;
    657     }
    658     if (pReq->Create.CreateParms.Result != SHFL_FILE_EXISTS) {
    659         LogFunc(("file %s does not exist\n", sf_i->path->String.utf8));
    660         err = -ENOENT;
    661         goto fail1;
    662     }
    663 
    664     /* Setting the file size and setting the other attributes has to be
    665      * handled separately, see implementation of vbsfSetFSInfo() in
    666      * vbsf.cpp */
    667     if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) {
    668         RT_ZERO(pReq->Info.ObjInfo);
    669 
    670         if (iattr->ia_valid & ATTR_MODE) {
    671             pReq->Info.ObjInfo.Attr.fMode = sf_access_permissions_to_vbox(iattr->ia_mode);
    672             if (iattr->ia_mode & S_IFDIR)
    673                 pReq->Info.ObjInfo.Attr.fMode |= RTFS_TYPE_DIRECTORY;
    674             else if (iattr->ia_mode & S_IFLNK)
    675                 pReq->Info.ObjInfo.Attr.fMode |= RTFS_TYPE_SYMLINK;
    676             else
    677                 pReq->Info.ObjInfo.Attr.fMode |= RTFS_TYPE_FILE;
    678         }
    679 
    680         if (iattr->ia_valid & ATTR_ATIME)
    681             vbsf_time_to_vbox(&pReq->Info.ObjInfo.AccessTime, &iattr->ia_atime);
    682         if (iattr->ia_valid & ATTR_MTIME)
    683             vbsf_time_to_vbox(&pReq->Info.ObjInfo.ModificationTime, &iattr->ia_mtime);
    684         /* ignore ctime (inode change time) as it can't be set from userland anyway */
    685 
    686         vrc = VbglR0SfHostReqSetObjInfo(sf_g->map.root, &pReq->Info, hHostFile);
    687         if (RT_FAILURE(vrc)) {
    688             err = -RTErrConvertToErrno(vrc);
    689             LogFunc(("VbglR0SfHostReqSetObjInfo(%s) failed vrc=%Rrc err=%d\n", sf_i->path->String.ach, vrc, err));
    690             goto fail1;
    691         }
    692     }
    693 
    694     if (iattr->ia_valid & ATTR_SIZE) {
    695         vrc = VbglR0SfHostReqSetFileSize(sf_g->map.root, &pReq->SetSize, hHostFile, iattr->ia_size);
    696         /** @todo Implement fallback if host is < 6.0? */
    697         if (RT_FAILURE(vrc)) {
    698             err = -RTErrConvertToErrno(vrc);
    699             LogFunc(("VbglR0SfHostReqSetFileSize(%s, %#llx) failed vrc=%Rrc err=%d\n",
    700                      sf_i->path->String.ach, (unsigned long long)iattr->ia_size, vrc, err));
    701             goto fail1;
    702         }
    703     }
    704 
    705     vrc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, hHostFile);
    706     if (RT_FAILURE(vrc))
    707         LogFunc(("VbglR0SfHostReqClose(%s [%#llx]) failed vrc=%Rrc\n", sf_i->path->String.utf8, hHostFile, vrc));
    708     VbglR0PhysHeapFree(pReq);
    709 
    710     /** @todo r=bird: I guess we're calling revalidate here to update the inode
    711      * info.  However, due to the TTL optimization this is not guarenteed to happen.
    712      *
    713      * Also, we already have accurate stat information on the file, either from the
    714      * SHFL_FN_CREATE call or from SHFL_FN_INFORMATION, so there is no need to do a
    715      * slow stat()-like operation to retrieve the information again.
    716      *
    717      * What's more, given that the SHFL_FN_CREATE call succeeded, we know that the
    718      * dentry and all its parent entries are valid and could touch their timestamps
    719      * extending their TTL (CIFS does that). */
    720     return vbsf_inode_revalidate_worker(dentry, true /*fForced*/, true /*fInodeLocked*/);
    721 
    722  fail1:
    723     vrc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, hHostFile);
    724     if (RT_FAILURE(vrc))
    725         LogFunc(("VbglR0SfHostReqClose(%s [%#llx]) failed vrc=%Rrc; err=%d\n", sf_i->path->String.utf8, hHostFile, vrc, err));
    726 
    727  fail2:
    728     VbglR0PhysHeapFree(pReq);
    729     return err;
    730 }
    731 
    732 #endif /* >= 2.5.18 */
     622    int rc;
     623
     624    SFLOGFLOW(("vbsf_inode_setattr: dentry=%p inode=%p ia_valid=%#x %s\n",
     625               dentry, pInode, iattr->ia_valid, sf_i ? sf_i->path->String.ach : NULL));
     626    AssertReturn(sf_i, -EINVAL);
     627
     628    /*
     629     * Need to check whether the caller is allowed to modify the attributes or not.
     630     */
     631#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
     632    rc = setattr_prepare(dentry, iattr);
     633#else
     634    rc = inode_change_ok(pInode, iattr);
     635#endif
     636    if (rc == 0) {
     637        /*
     638         * We only implement a handful of attributes, so ignore any attempts
     639         * at setting bits we don't support.
     640         */
     641        if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME | ATTR_CTIME | ATTR_SIZE)) {
     642            /*
     643             * Try find a handle which allows us to modify the attributes, otherwise
     644             * open the file/dir/whatever.
     645             */
     646            union SetAttrReqs
     647            {
     648                VBOXSFCREATEREQ         Create;
     649                VBOXSFOBJINFOREQ        Info;
     650                VBOXSFSETFILESIZEREQ    SetSize;
     651                VBOXSFCLOSEREQ          Close;
     652            }                  *pReq;
     653            size_t              cbReq;
     654            SHFLHANDLE          hHostFile;
     655            struct vbsf_handle *pHandle = iattr->ia_valid & ATTR_SIZE
     656                                        ? vbsf_handle_find(sf_i, VBSF_HANDLE_F_WRITE, 0)
     657                                        : vbsf_handle_find(sf_i, 0, 0);
     658            if (pHandle) {
     659                hHostFile = pHandle->hHost;
     660                cbReq = RT_MAX(sizeof(VBOXSFOBJINFOREQ), sizeof(VBOXSFSETFILESIZEREQ));
     661                pReq  = (union SetAttrReqs *)VbglR0PhysHeapAlloc(cbReq);
     662                if (pReq) {
     663                    /* likely */
     664                } else
     665                    rc = -ENOMEM;
     666            } else {
     667                hHostFile = SHFL_HANDLE_NIL;
     668                cbReq = RT_MAX(sizeof(pReq->Info), sizeof(pReq->Create) + SHFLSTRING_HEADER_SIZE + sf_i->path->u16Size);
     669                pReq = (union SetAttrReqs *)VbglR0PhysHeapAlloc(cbReq);
     670                if (pReq) {
     671                    RT_ZERO(pReq->Create.CreateParms);
     672                    pReq->Create.CreateParms.Handle      = SHFL_HANDLE_NIL;
     673                    pReq->Create.CreateParms.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS
     674                                                         | SHFL_CF_ACT_FAIL_IF_NEW
     675                                                         | SHFL_CF_ACCESS_ATTR_WRITE;
     676                    if (iattr->ia_valid & ATTR_SIZE)
     677                        pReq->Create.CreateParms.CreateFlags |= SHFL_CF_ACCESS_WRITE;
     678                    memcpy(&pReq->Create.StrPath, sf_i->path, SHFLSTRING_HEADER_SIZE + sf_i->path->u16Size);
     679                    vrc = VbglR0SfHostReqCreate(sf_g->map.root, &pReq->Create);
     680                    if (RT_SUCCESS(vrc)) {
     681                        if (pReq->Create.CreateParms.Result == SHFL_FILE_EXISTS) {
     682                            hHostFile = pReq->Create.CreateParms.Handle;
     683                            Assert(hHostFile != SHFL_HANDLE_NIL);
     684                            vbsf_dentry_chain_increase_ttl(dentry);
     685                        } else {
     686                            LogFunc(("file %s does not exist\n", sf_i->path->String.utf8));
     687                            /** @todo    */
     688                            rc = -ENOENT;
     689                        }
     690                    } else {
     691                        rc = -RTErrConvertToErrno(vrc);
     692                        LogFunc(("VbglR0SfCreate(%s) failed vrc=%Rrc rc=%d\n", sf_i->path->String.ach, vrc, rc));
     693                    }
     694                } else
     695                    rc = -ENOMEM;
     696            }
     697            if (rc == 0) {
     698                /*
     699                 * Set mode and/or timestamps.
     700                 */
     701                if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME | ATTR_CTIME)) {
     702                    /* Fill in the attributes.  Start by setting all to zero
     703                       since the host will ignore zeroed fields. */
     704                    RT_ZERO(pReq->Info.ObjInfo);
     705
     706                    if (iattr->ia_valid & ATTR_MODE) {
     707                        pReq->Info.ObjInfo.Attr.fMode = sf_access_permissions_to_vbox(iattr->ia_mode);
     708                        if (iattr->ia_mode & S_IFDIR)
     709                            pReq->Info.ObjInfo.Attr.fMode |= RTFS_TYPE_DIRECTORY;
     710                        else if (iattr->ia_mode & S_IFLNK)
     711                            pReq->Info.ObjInfo.Attr.fMode |= RTFS_TYPE_SYMLINK;
     712                        else
     713                            pReq->Info.ObjInfo.Attr.fMode |= RTFS_TYPE_FILE;
     714                    }
     715                    if (iattr->ia_valid & ATTR_ATIME)
     716                        vbsf_time_to_vbox(&pReq->Info.ObjInfo.AccessTime, &iattr->ia_atime);
     717                    if (iattr->ia_valid & ATTR_MTIME)
     718                        vbsf_time_to_vbox(&pReq->Info.ObjInfo.ModificationTime, &iattr->ia_mtime);
     719                    if (iattr->ia_valid & ATTR_CTIME)
     720                        vbsf_time_to_vbox(&pReq->Info.ObjInfo.ChangeTime, &iattr->ia_ctime);
     721
     722                    /* Make the change. */
     723                    vrc = VbglR0SfHostReqSetObjInfo(sf_g->map.root, &pReq->Info, hHostFile);
     724                    if (RT_SUCCESS(vrc)) {
     725                        vbsf_update_inode(pInode, sf_i, &pReq->Info.ObjInfo, sf_g, true /*fLocked*/);
     726                    } else {
     727                        rc = -RTErrConvertToErrno(vrc);
     728                        LogFunc(("VbglR0SfHostReqSetObjInfo(%s) failed vrc=%Rrc rc=%d\n", sf_i->path->String.ach, vrc, rc));
     729                    }
     730                }
     731
     732                /*
     733                 * Change the file size.
     734                 * Note! Old API is more convenient here as it gives us up to date
     735                 *       inode info back.
     736                 */
     737                if ((iattr->ia_valid & ATTR_SIZE) && rc == 0) {
     738                    /*vrc = VbglR0SfHostReqSetFileSize(sf_g->map.root, &pReq->SetSize, hHostFile, iattr->ia_size);
     739                    if (RT_SUCCESS(vrc)) {
     740                        i_size_write(pInode, iattr->ia_size);
     741                    } else if (vrc == VERR_NOT_IMPLEMENTED)*/ {
     742                        /* Fallback for pre 6.0 hosts: */
     743                        RT_ZERO(pReq->Info.ObjInfo);
     744                        pReq->Info.ObjInfo.cbObject = iattr->ia_size;
     745                        vrc = VbglR0SfHostReqSetFileSizeOld(sf_g->map.root, &pReq->Info, hHostFile);
     746                        if (RT_SUCCESS(vrc))
     747                            vbsf_update_inode(pInode, sf_i, &pReq->Info.ObjInfo, sf_g, true /*fLocked*/);
     748                    }
     749                    if (RT_SUCCESS(vrc)) {
     750                        /** @todo there is potentially more to be done here if there are mappings of
     751                         *        the lovely file. */
     752                    } else {
     753                        rc = -RTErrConvertToErrno(vrc);
     754                        LogFunc(("VbglR0SfHostReqSetFileSize(%s, %#llx) failed vrc=%Rrc rc=%d\n",
     755                                 sf_i->path->String.ach, (unsigned long long)iattr->ia_size, vrc, rc));
     756                    }
     757                }
     758
     759                /*
     760                 * Clean up.
     761                 */
     762                if (!pHandle) {
     763                    vrc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, hHostFile);
     764                    if (RT_FAILURE(vrc))
     765                        LogFunc(("VbglR0SfHostReqClose(%s [%#llx]) failed vrc=%Rrc\n", sf_i->path->String.utf8, hHostFile, vrc));
     766                }
     767            }
     768            if (pReq)
     769                VbglR0PhysHeapFree(pReq);
     770            if (pHandle)
     771                vbsf_handle_release(pHandle, sf_g, "vbsf_inode_setattr");
     772        } else
     773            SFLOGFLOW(("vbsf_inode_setattr: Notthing to do here (%#x).\n", iattr->ia_valid));
     774    }
     775    return rc;
     776}
     777
    733778
    734779static int vbsf_make_path(const char *caller, struct vbsf_inode_info *sf_i,
  • trunk/src/VBox/Additions/linux/sharedfolders/vfsmod.h

    r77559 r77561  
    221221extern int  vbsf_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *kstat);
    222222# endif
    223 extern int  vbsf_inode_setattr(struct dentry *dentry, struct iattr *iattr);
    224223#else  /* < 2.5.44 */
    225224extern int  vbsf_inode_revalidate(struct dentry *dentry);
    226225#endif /* < 2.5.44 */
     226extern int  vbsf_inode_setattr(struct dentry *dentry, struct iattr *iattr);
    227227
    228228
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