/** * Helper function for vboxvfs_vnode_lookup(): create new vnode. */ static int vboxvfs_vnode_lookup_instantinate_vnode(vnode_t parent_vnode, char *entry_name, vnode_t *result_vnode) { /* We need to construct full path to vnode in order to get * vboxvfs_get_info_internal() to understand us! */ char *pszCurDirPath; int cbCurDirPath = MAXPATHLEN; mount_t mp = vnode_mount(parent_vnode); AssertReturn(mp, EINVAL); vnode_t vnode; int rc; pszCurDirPath = (char *)RTMemAllocZ(cbCurDirPath); if (pszCurDirPath) { rc = vn_getpath(parent_vnode, pszCurDirPath, &cbCurDirPath); if (rc == 0 && cbCurDirPath < MAXPATHLEN) { SHFLFSOBJINFO Info; PSHFLSTRING pSHFLPath; /* Add '/' between path parts and truncate name if it is too long */ strncat(pszCurDirPath, "/", 1); strncat(pszCurDirPath, entry_name, MAXPATHLEN - cbCurDirPath - 1); rc = vboxvfs_guest_path_to_shflstring_path_internal(mp, pszCurDirPath, strlen(pszCurDirPath) + 1, &pSHFLPath); if (rc == 0) { rc = vboxvfs_get_info_internal(mp, pSHFLPath, (PSHFLFSOBJINFO)&Info); if (rc == 0) { enum vtype type; if (RTFS_IS_DIRECTORY(Info.Attr.fMode)) type = VDIR; else if (RTFS_IS_FILE (Info.Attr.fMode)) type = VREG; else { PDEBUG("Not supported VFS object (%s) type: mode 0x%X", entry_name, Info.Attr.fMode); RTMemFree(pszCurDirPath); vboxvfs_put_path_internal((void **)&pSHFLPath); return ENOENT; } /* Create new vnode */ rc = vboxvfs_create_vnode_internal(mp, type, parent_vnode, FALSE, pSHFLPath, &vnode); if (rc == 0) { PDEBUG("new vnode object '%s' has been created", entry_name); *result_vnode = vnode; RTMemFree(pszCurDirPath); return 0; } else PDEBUG("Unable to create vnode: %d", rc); } else PDEBUG("Unable to get host object info: %d", rc); vboxvfs_put_path_internal((void **)&pSHFLPath); } else PDEBUG("Unable to convert guest<->host path"); } else PDEBUG("Unable to construct vnode path: %d", rc); RTMemFree(pszCurDirPath); } else { PDEBUG("Unable to allocate memory for path buffer"); rc = ENOMEM; } return rc; }
/** * Get VBoxVFS root vnode. * * Handle three cases here: * - vnode does not exist yet: create a new one * - currently creating vnode: wait till the end, increment usage count and return existing one * - vnode already created: increment usage count and return existing one * - vnode was failed to create: give a chance to try to re-create it later * * @param mp Mount data provided by VFS layer. * @param ppVnode vnode to return. * @param pContext kAuth context needed in order to authentificate mount operation. * * @return 0 on success or BSD error code otherwise. */ static int vboxvfs_root(struct mount *mp, struct vnode **ppVnode, vfs_context_t pContext) { NOREF(pContext); vboxvfs_mount_t *pMount; int rc = 0; uint32_t vid; PDEBUG("Getting root vnode..."); AssertReturn(mp, EINVAL); AssertReturn(ppVnode, EINVAL); pMount = (vboxvfs_mount_t *)vfs_fsprivate(mp); AssertReturn(pMount, EINVAL); /* Check case when vnode does not exist yet */ if (ASMAtomicCmpXchgU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_INITIALIZING, VBOXVFS_OBJECT_UNINITIALIZED)) { PDEBUG("Create new root vnode"); /* Allocate empty SHFLSTRING to indicate path to root vnode within Shared Folder */ char szEmpty[1]; SHFLSTRING *pSFVnodePath; pSFVnodePath = vboxvfs_construct_shflstring((char *)szEmpty, 0); if (pSFVnodePath) { int rc2; rc2 = vboxvfs_create_vnode_internal(mp, VDIR, NULL, TRUE, pSFVnodePath, &pMount->pRootVnode); if (rc2 != 0) { RTMemFree(pSFVnodePath); rc = ENOTSUP; } } else rc = ENOMEM; /* Notify other threads about result */ if (rc == 0) ASMAtomicWriteU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_INITIALIZED); else ASMAtomicWriteU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_INVALID); } else { /* Check case if we are currently creating vnode. Wait while other thread to finish allocation. */ uint8_t fRootVnodeState = VBOXVFS_OBJECT_UNINITIALIZED; while (fRootVnodeState != VBOXVFS_OBJECT_INITIALIZED && fRootVnodeState != VBOXVFS_OBJECT_INVALID) { /* @todo: Currently, we are burning CPU cycles while waiting. This is for a short * time but we should relax here! */ fRootVnodeState = ASMAtomicReadU8(&pMount->fRootVnodeState); } /* Check if the other thread initialized root vnode and it is ready to be returned */ if (fRootVnodeState == VBOXVFS_OBJECT_INITIALIZED) { /* Take care about iocount */ vid = vnode_vid(pMount->pRootVnode); rc = vnode_getwithvid(pMount->pRootVnode, vid); } else { /* Other thread reported initialization failure. * Set vnode state VBOXVFS_OBJECT_UNINITIALIZED in order to try recreate root * vnode in other attempt */ ASMAtomicWriteU8(&pMount->fRootVnodeState, VBOXVFS_OBJECT_UNINITIALIZED); } } /* Only return vnode if we got success */ if (rc == 0) { PDEBUG("Root vnode can be returned"); *ppVnode = pMount->pRootVnode; } else PDEBUG("Root vnode cannot be returned: 0x%X", rc); return rc; }