VirtualBox

Changeset 2084 in vbox for trunk/src


Ignore:
Timestamp:
Apr 13, 2007 11:50:25 PM (18 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
20393
Message:

claim+unmount mounted dvds on darwin.

Location:
trunk/src/VBox/Devices
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Makefile

    r1965 r2084  
    122122VBoxDD_LIBS.darwin      = \
    123123        $(LIB_REM)
    124 VBoxDD_LDFLAGS.darwin   = -install_name @executable_path/VBoxDD.dylib -framework CoreAudio -framework IOKit -framework Carbon
     124VBoxDD_LDFLAGS.darwin   = -install_name @executable_path/VBoxDD.dylib \
     125        -framework CoreAudio \
     126        -framework IOKit \
     127        -framework Carbon \
     128        -framework DiskArbitration
    125129VBoxDD_LDFLAGS.linux    = -Wl,--no-undefined
    126130VBoxDD_LDFLAGS.l4       = -Wl,--no-undefined
  • trunk/src/VBox/Devices/Storage/DrvHostBase.cpp

    r1967 r2084  
    3333# include <IOKit/scsi-commands/SCSITaskLib.h>
    3434# include <IOKit/scsi-commands/SCSICommandOperationCodes.h>
     35# include <IOKit/IOBSD.h>
     36# include <DiskArbitration/DiskArbitration.h>
    3537# include <mach/mach_error.h>
    3638# include <VBox/scsi.h>
     
    558560
    559561/* -=-=-=-=- poller thread -=-=-=-=- */
     562
     563#ifdef __DARWIN__
     564/** The runloop input source name for the disk arbitration events. */
     565#define MY_RUN_LOOP_MODE    CFSTR("drvHostBaseDA")
     566
     567/**
     568 * Gets the BSD Name (/dev/disc[0-9]+) for the service.
     569 *
     570 * This is done by recursing down the I/O registry until we hit upon an entry
     571 * with a BSD Name. Usually we find it two levels down. (Further down under
     572 * the IOCDPartitionScheme, the volume (slices) BSD Name is found. We don't
     573 * seem to have to go this far fortunately.)
     574 *
     575 * @return  VINF_SUCCESS if found, VERR_FILE_NOT_FOUND otherwise.
     576 * @param   Entry       The current I/O registry entry reference.
     577 * @param   pszName     Where to store the name. 128 bytes.
     578 * @param   cRecursions Number of recursions. This is used as an precation
     579 *                      just to limit the depth and avoid blowing the stack
     580 *                      should we hit a bug or something.
     581 */
     582static int drvHostBaseGetBSDName(io_registry_entry_t Entry, char *pszName, unsigned cRecursions)
     583{
     584    int rc = VERR_FILE_NOT_FOUND;
     585    io_iterator_t Children = 0;
     586    kern_return_t krc = IORegistryEntryGetChildIterator(Entry, kIOServicePlane, &Children);
     587    if (krc == KERN_SUCCESS)
     588    {
     589        io_object_t Child;
     590        while (     rc == VERR_FILE_NOT_FOUND
     591               &&   (Child = IOIteratorNext(Children)) != 0)
     592        {
     593            CFStringRef BSDNameStrRef = (CFStringRef)IORegistryEntryCreateCFProperty(Child, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
     594            if (BSDNameStrRef)
     595            {
     596                if (CFStringGetCString(BSDNameStrRef, pszName, 128, kCFStringEncodingUTF8))
     597                    rc = VINF_SUCCESS;
     598                else
     599                    AssertFailed();
     600                CFRelease(BSDNameStrRef);
     601            }
     602            if (rc == VERR_FILE_NOT_FOUND && cRecursions < 10)
     603                rc = drvHostBaseGetBSDName(Child, pszName, cRecursions + 1);
     604            IOObjectRelease(Child);
     605        }
     606        IOObjectRelease(Children);
     607    }
     608    return rc;
     609}
     610
     611
     612/**
     613 * Callback notifying us that the async DADiskClaim()/DADiskUnmount call has completed.
     614 *
     615 * @param   DiskRef         The disk that was attempted claimed / unmounted.
     616 * @param   DissenterRef    NULL on success, contains details on failure.
     617 * @param   pvContext       Pointer to the return code variable.
     618 */
     619static void drvHostBaseDADoneCallback(DADiskRef DiskRef, DADissenterRef DissenterRef, void *pvContext)
     620{
     621    int *prc = (int *)pvContext;
     622    if (!DissenterRef)
     623        *prc = 0;
     624    else
     625        *prc = DADissenterGetStatus(DissenterRef) ? DADissenterGetStatus(DissenterRef) : -1;
     626    CFRunLoopStop(CFRunLoopGetCurrent());
     627}
     628
     629
     630/**
     631 * Obtain exclusive access to the DVD device, umount it if necessary.
     632 *
     633 * @return  VBox status code.
     634 * @param   pThis       The driver instance.
     635 * @param   DVDService  The DVD service object.
     636 */
     637static int drvHostBaseObtainExclusiveAccess(PDRVHOSTBASE pThis, io_object_t DVDService)
     638{
     639    PPDMDRVINS pDrvIns = pThis->pDrvIns; NOREF(pDrvIns);
     640
     641    for (unsigned iTry = 0;; iTry++)
     642    {
     643        IOReturn irc = (*pThis->ppScsiTaskDI)->ObtainExclusiveAccess(pThis->ppScsiTaskDI);
     644        if (irc == kIOReturnSuccess)
     645        {
     646            /*
     647             * This is a bit weird, but if we unmounted the DVD drive we also need to
     648             * unlock it afterwards or the guest won't be able to eject it later on.
     649             */
     650            if (pThis->pDADisk)
     651            {
     652                uint8_t abCmd[16] =
     653                {
     654                    SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, false, 0,
     655                    0,0,0,0,0,0,0,0,0,0
     656                };
     657                DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, NULL, 0, 0);
     658            }
     659            return VINF_SUCCESS;
     660        }
     661        if (irc == kIOReturnExclusiveAccess)
     662            return VERR_SHARING_VIOLATION;      /* already used exclusivly. */
     663        if (irc != kIOReturnBusy)
     664            return VERR_GENERAL_FAILURE;        /* not mounted */
     665
     666        /*
     667         * Attempt to the unmount all volumes of the device.
     668         * It seems we can can do this all in one go without having to enumerate the
     669         * volumes (sessions) and deal with them one by one. This is very fortuitous
     670         * as the disk arbitration API is a bit cumbersome to deal with.
     671         */
     672        if (iTry > 2)
     673            return VERR_DRIVE_LOCKED;
     674        char szName[128];
     675        int rc = drvHostBaseGetBSDName(DVDService, &szName[0], 0);
     676        if (VBOX_SUCCESS(rc))
     677        {
     678            pThis->pDASession = DASessionCreate(kCFAllocatorDefault);
     679            if (pThis->pDASession)
     680            {
     681                DASessionScheduleWithRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);
     682                pThis->pDADisk = DADiskCreateFromBSDName(kCFAllocatorDefault, pThis->pDASession, szName);
     683                if (pThis->pDADisk)
     684                {
     685                    /*
     686                     * Try claim the device.
     687                     */
     688                    Log(("%s-%d: calling DADiskClaim on '%s'.\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, szName));
     689                    int rcDA = -2;
     690                    DADiskClaim(pThis->pDADisk, kDADiskClaimOptionDefault, NULL, NULL, drvHostBaseDADoneCallback, &rcDA);
     691                    SInt32 rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE);
     692                    AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32));
     693                    if (    rc32 == kCFRunLoopRunStopped
     694                        &&  !rcDA)
     695                    {
     696                        /*
     697                         * Try unmount the device.
     698                         */
     699                        Log(("%s-%d: calling DADiskUnmount on '%s'.\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, szName));
     700                        rcDA = -2;
     701                        DADiskUnmount(pThis->pDADisk, kDADiskUnmountOptionWhole, drvHostBaseDADoneCallback, &rcDA);
     702                        SInt32 rc32 = CFRunLoopRunInMode(MY_RUN_LOOP_MODE, 120.0, FALSE);
     703                        AssertMsg(rc32 == kCFRunLoopRunStopped, ("rc32=%RI32 (%RX32)\n", rc32, rc32));
     704                        if (    rc32 == kCFRunLoopRunStopped
     705                            &&  !rcDA)
     706                        {
     707                            iTry = 99;
     708                            DASessionUnscheduleFromRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);
     709                            Log(("%s-%d: unmount succeed - retrying.\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance));
     710                            continue;
     711                        }
     712                        Log(("%s-%d: umount => rc32=%d & rcDA=%#x\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc32, rcDA));
     713
     714                        /* failed - cleanup */
     715                        DADiskUnclaim(pThis->pDADisk);
     716                    }
     717                    else
     718                        Log(("%s-%d: claim => rc32=%d & rcDA=%#x\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, rc32, rcDA));
     719                   
     720                    CFRelease(pThis->pDADisk);
     721                    pThis->pDADisk = NULL;
     722                }
     723                else
     724                    Log(("%s-%d: failed to open disk '%s'!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, szName));
     725
     726                DASessionUnscheduleFromRunLoop(pThis->pDASession, CFRunLoopGetCurrent(), MY_RUN_LOOP_MODE);
     727                CFRelease(pThis->pDASession);
     728                pThis->pDASession = NULL;
     729            }
     730            else
     731                Log(("%s-%d: failed to create DA session!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance));
     732        }
     733        RTThreadSleep(10);
     734    }
     735}
     736#endif /* __DARWIN__ */
     737
    560738
    561739/**
     
    710888                        rc = VERR_GENERAL_FAILURE;//RTErrConvertFromDarwinKern(krc);
    711889
    712                     /*
    713                      * Obtain exclusive access to the device
    714                      * (to prevent the host and/or user from interfering).
    715                      */
     890                    /* Obtain exclusive access to the device so we can send SCSI commands. */
    716891                    if (VBOX_SUCCESS(rc))
    717                     {
    718                         irc = (*pThis->ppScsiTaskDI)->ObtainExclusiveAccess(pThis->ppScsiTaskDI);
    719                         if (irc == kIOReturnSuccess)
    720                             rc = VINF_SUCCESS;
    721                         else if (irc == kIOReturnBusy)
    722                             rc = VERR_DRIVE_LOCKED;         /* mounted. */
    723                         else if (irc == kIOReturnExclusiveAccess)
    724                             rc = VERR_SHARING_VIOLATION;    /* already used exclusivly. */
    725                         else
    726                             rc = VERR_GENERAL_FAILURE;
    727                     }
     892                        rc = drvHostBaseObtainExclusiveAccess(pThis, DVDService);
    728893
    729894                    /* Cleanup on failure. */
     
    12991464
    13001465    /*
    1301      * Unlock the drive if we've locked it.
    1302      */
     1466     * Unlock the drive if we've locked it or we're in passthru mode.
     1467     */
     1468#ifdef __DARWIN__
     1469    if (    (   pThis->fLocked
     1470             || pThis->IBlock.pfnSendCmd)
     1471        &&  pThis->ppScsiTaskDI
     1472#else /** @todo Check if the other guys can mix pfnDoLock with scsi passthru.
     1473       * (We're currently not unlocking the device after use. See todo in DevATA.cpp.) */
    13031474    if (    pThis->fLocked
    1304 #ifdef __DARWIN__
    1305         &&  pThis->ppScsiTaskDI
    1306 #else
    13071475        &&  pThis->FileDevice != NIL_RTFILE
    13081476#endif
     
    13331501
    13341502#ifdef __DARWIN__
     1503    /*
     1504     * The unclaiming doesn't seem to mean much, the DVD is actaully
     1505     * remounted when we release exclusive access. I'm not quite sure
     1506     * if I should put the unclaim first or not...
     1507     *
     1508     * Anyway, that it's automatically remounted very good news for us,
     1509     * because that means we don't have to mess with that ourselves. Of
     1510     * course there is the unlikely scenario that we've succeeded in claiming
     1511     * and umount the DVD but somehow failed to gain exclusive scsi access...
     1512     */
    13351513    if (pThis->ppScsiTaskDI)
    13361514    {
     1515        LogFlow(("%s-%d: releasing exclusive scsi access!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance));
    13371516        (*pThis->ppScsiTaskDI)->ReleaseExclusiveAccess(pThis->ppScsiTaskDI);
    13381517        (*pThis->ppScsiTaskDI)->Release(pThis->ppScsiTaskDI);
    13391518        pThis->ppScsiTaskDI = NULL;
    13401519    }
     1520    if (pThis->pDADisk)
     1521    {
     1522        LogFlow(("%s-%d: unclaiming the disk!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance));
     1523        DADiskUnclaim(pThis->pDADisk);
     1524        CFRelease(pThis->pDADisk);
     1525        pThis->pDADisk = NULL;
     1526    }
    13411527    if (pThis->ppMMCDI)
    13421528    {
     1529        LogFlow(("%s-%d: releasing the MMC object!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance));
    13431530        (*pThis->ppMMCDI)->Release(pThis->ppMMCDI);
    13441531        pThis->ppMMCDI = NULL;
     
    13481535        mach_port_deallocate(mach_task_self(), pThis->MasterPort);
    13491536        pThis->MasterPort = NULL;
     1537    }
     1538    if (pThis->pDASession)
     1539    {
     1540        LogFlow(("%s-%d: releasing the DA session!\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance));
     1541        CFRelease(pThis->pDASession);
     1542        pThis->pDASession = NULL;
    13501543    }
    13511544#else
     
    13721565    if (RTCritSectIsInitialized(&pThis->CritSect))
    13731566        RTCritSectDelete(&pThis->CritSect);
     1567    LogFlow(("%s-%d: drvHostBaseDestruct completed\n", pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance));
    13741568}
    13751569
     
    14031597    pThis->ppScsiTaskDI                     = NULL;
    14041598    pThis->cbBlock                          = 0;
     1599    pThis->pDADisk                          = NULL;
     1600    pThis->pDASession                       = NULL;
    14051601#else
    14061602    pThis->FileDevice                       = NIL_RTFILE;
  • trunk/src/VBox/Devices/Storage/DrvHostBase.h

    r1965 r2084  
    113113    /** The block size. Set when querying the media size. */
    114114    uint32_t                cbBlock;
     115    /** The disk arbitration session reference. NULL if we didn't have to claim & unmount the device. */
     116    DASessionRef            pDASession;
     117    /** The disk arbritation disk reference. NULL if we didn't have to claim & unmount the device. */
     118    DADiskRef               pDADisk;
    115119#endif
    116120
  • trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp

    r1965 r2084  
    174174{
    175175#ifdef __DARWIN__
    176 # if 0 /// @todo dig up the specification for this command and implement it. (not important on mac)
    177176    uint8_t abCmd[16] =
    178177    {
    179         SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0,
     178        SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, 0, 0, 0, fLock, 0,
    180179        0,0,0,0,0,0,0,0,0,0
    181180    };
    182181    int rc = DRVHostBaseScsiCmd(pThis, abCmd, 6, PDMBLOCKTXDIR_NONE, NULL, NULL, NULL, 0, 0);
    183 # else
    184     int rc = VINF_SUCCESS;
    185 # endif
    186182
    187183#elif defined(__LINUX__)
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