Annotation of XNU/iokit/Families/IOStorage/IOMediaBSDClient.cpp, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: 
                     23: #include <dev/disk.h>                        // (DKIOCGETBLOCKSIZE, ...)
                     24: #include <mach/vm_types.h>                   // (mach/vm_region.h, ...)
                     25: #include <mach/vm_region.h>                  // (VM_REGION_BASIC_INFO, ...)
                     26: #include <miscfs/devfs/devfs.h>              // (devfs_make_node, ...)
                     27: #include <sys/buf.h>                         // (struct buf, ...)
                     28: #include <sys/conf.h>                        // (bdevsw_add, ...)
                     29: #include <sys/fcntl.h>                       // (FWRITE, ...)
                     30: #include <sys/ioccom.h>                      // (IOCGROUP, ...)
                     31: #include <sys/stat.h>                        // (S_ISBLK, ...)
                     32: #include <sys/uio.h>                         // (struct uio, ...)
                     33: #include <IOKit/assert.h>
                     34: #include <IOKit/IOBSD.h>
                     35: #include <IOKit/IODeviceTreeSupport.h>
                     36: #include <IOKit/IOLib.h>
                     37: #include <IOKit/IOMemoryDescriptor.h>
                     38: #include <IOKit/IOMessage.h>
                     39: #include <IOKit/storage/IODrive.h>
                     40: #include <IOKit/storage/IOMedia.h>
                     41: #include <IOKit/storage/IOMediaBSDClient.h>
                     42: 
                     43: #define super IOService
                     44: OSDefineMetaClassAndStructors(IOMediaBSDClient, IOService)
                     45: 
                     46: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     47: 
                     48: static IOMediaBSDClient * gIOMediaBSDClient = 0;
                     49: 
                     50: const   signed kMajor            = 14;       // (bsd interface [b|c]devsw major)
                     51: const unsigned kMinorsGrowCount  = 16;       // (entries to add on table growth)
                     52: const unsigned kMinorsMaxCount   = 1 << 24;  // (maximum entries;  24-bit minor)
                     53: const unsigned kAnchorsGrowCount = 2;        // (entries to add on table growth)
                     54: const unsigned kAnchorsMaxCount  = kMinorsMaxCount;         // (maximum entries)
                     55: 
                     56: #define kMsgBadWhole   "%s: Peer whole media \"%s\" is not allowed.",  getName()
                     57: #define kMsgNoWhole    "%s: No whole media found for media \"%s\".\n", getName()
                     58: #define kMsgNoLocation "%s: No location is found for media \"%s\".\n", getName()
                     59: 
                     60: #define IOMEDIABSDCLIENT_IOSTAT_SUPPORT       // (enable iostat support for bsd)
                     61: 
                     62: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     63: 
                     64: extern "C"
                     65: {
                     66:     int  dkclose(dev_t dev, int flags, int devtype, struct proc *);
                     67:     int  dkioctl(dev_t dev, u_long cmd, caddr_t data, int, struct proc *);
                     68:     int  dkioctl_bdev(dev_t dev, u_long cmd, caddr_t data, int, struct proc *);
                     69:     int  dkopen(dev_t dev, int flags, int devtype, struct proc *);
                     70:     int  dkread(dev_t dev, struct uio * uio, int flags);
                     71:     int  dksize(dev_t dev);    
                     72:     void dkstrategy(struct buf * bp);
                     73:     int  dkwrite(dev_t dev, struct uio * uio, int flags);
                     74: } // extern "C"
                     75: 
                     76: static struct bdevsw bdevswFunctions =
                     77: {
                     78:     /* d_open     */ dkopen,
                     79:     /* d_close    */ dkclose,
                     80:     /* d_strategy */ dkstrategy,
                     81:     /* d_ioctl    */ dkioctl_bdev,
                     82:     /* d_dump     */ eno_dump,
                     83:     /* d_psize    */ dksize,
                     84:     /* d_type     */ D_DISK
                     85: };
                     86: 
                     87: struct cdevsw cdevswFunctions =
                     88: {
                     89:     /* d_open     */ dkopen,
                     90:     /* d_close    */ dkclose,
                     91:     /* d_read     */ dkread,
                     92:     /* d_write    */ dkwrite,
                     93:     /* d_ioctl    */ dkioctl,
                     94:     /* d_stop     */ eno_stop,
                     95:     /* d_reset    */ eno_reset,
                     96:     /* d_ttys     */ 0,
                     97:     /* d_select   */ eno_select,
                     98:     /* d_mmap     */ eno_mmap,
                     99:     /* d_strategy */ eno_strat,
                    100:     /* d_getc     */ eno_getc,
                    101:     /* d_putc     */ eno_putc,
                    102:     /* d_type     */ D_TAPE
                    103: };
                    104: 
                    105: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    106: 
                    107: struct dio { dev_t dev; struct uio * uio; };
                    108: 
                    109: typedef void *                            dkr_t;       /* dkreadwrite request */
                    110: typedef enum { DKRTYPE_BUF, DKRTYPE_DIO } dkrtype_t;
                    111: 
                    112: int  dkreadwrite(dkr_t dkr, dkrtype_t dkrtype);
                    113: void dkreadwritecompletion(void *, void *, IOReturn, UInt64);
                    114: 
                    115: #define get_kernel_task() kernel_task
                    116: #define get_user_task()   current_task()
                    117: 
                    118: #ifdef IOMEDIABSDCLIENT_IOSTAT_SUPPORT
                    119: #include <sys/dkstat.h>
                    120: IODrive * dk_drive[DK_NDRIVE];
                    121: #endif IOMEDIABSDCLIENT_IOSTAT_SUPPORT
                    122: 
                    123: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    124: 
                    125: const UInt32 kInvalidAnchorID = (UInt32) (-1);
                    126: 
                    127: struct AnchorSlot
                    128: {
                    129:     UInt32       isAssigned:1, // (anchor slot is occupied)
                    130:                  isObsolete:1; // (anchor slot is to be removed once refs gone)
                    131: 
                    132:     IOService *  anchor;       // (anchor object)
                    133:     IONotifier * notifier;     // (anchor termination notification, post-stop)
                    134: };
                    135: 
                    136: class AnchorTable
                    137: {
                    138: protected:
                    139:     AnchorSlot * _table;
                    140:     UInt32       _tableCount;
                    141:     UInt32       _tableGrowCount;
                    142:     UInt32       _tableMaxCount;
                    143: 
                    144:     static IOReturn anchorChange(void *, void *, UInt32,
                    145:                                  IOService *, void *, vm_size_t);
                    146: 
                    147: public:
                    148:     AnchorTable(UInt32 growCount, UInt32 maxCount);
                    149:     ~AnchorTable();
                    150: 
                    151:     UInt32 insert(IOService * anchor);
                    152:     UInt32 locate(IOService * anchor);
                    153:     void   obsolete(UInt32 anchorID);
                    154:     void   remove(UInt32 anchorID);
                    155: 
                    156:     bool   isObsolete(UInt32 anchorID);
                    157: };
                    158: 
                    159: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    160: 
                    161: const UInt32 kInvalidMinorID = (UInt32) (-1);
                    162: 
                    163: struct MinorSlot
                    164: {
                    165:     UInt32       isAssigned:1,  // (minor slot is occupied)
                    166:                  isEjecting:1,  // (minor slot is in eject flux, needs close)
                    167:                  isObsolete:1;  // (minor slot is in eject flux, needs removal)
                    168: 
                    169:     UInt32       anchorID;      // (minor's associated anchor ID)
                    170:     IOMedia *    media;         // (minor's media object)
                    171:     char *       name;          // (minor's name, private allocation space)
                    172: 
                    173:     UInt64       bdevBlockSize; // (block device's preferred block size)
                    174:     void *       bdevNode;      // (block device's devfs node)
                    175:     UInt32       bdevOpen:1,    // (block device's open flag)
                    176:                  bdevWriter:1;  // (block device's open writer flag)
                    177: 
                    178:     void *       cdevNode;      // (character device's devfs node)
                    179:     UInt32       cdevOpen:1,    // (character device's open flag)
                    180:                  cdevWriter:1;  // (character device's open writer flag)
                    181: };
                    182: 
                    183: class MinorTable
                    184: {
                    185: protected:
                    186:     MinorSlot * _table;
                    187:     UInt32      _tableCount;
                    188:     UInt32      _tableGrowCount;
                    189:     UInt32      _tableMaxCount;
                    190: 
                    191: public:
                    192:     MinorTable(UInt32 growCount, UInt32 maxCount);
                    193:     ~MinorTable();
                    194: 
                    195:     UInt32      insert(IOMedia * media, UInt32 anchorID, char * slicePath);
                    196:     UInt32      locate(IOMedia * media);
                    197:     void        obsolete(UInt32 minorID);
                    198:     void        remove(UInt32 minorID);
                    199: 
                    200:     bool        isObsolete(UInt32 minorID);
                    201: 
                    202:     MinorSlot * getMinor(UInt32 minorID);
                    203: 
                    204:     UInt32      getOpenCountForAnchorID(UInt32 anchorID);
                    205:     IOMedia *   getWholeMediaAtAnchorID(UInt32 anchorID);
                    206:     bool        hasReferencesToAnchorID(UInt32 anchorID);
                    207: };
                    208: 
                    209: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    210: 
                    211: bool IOMediaBSDClient::init(OSDictionary * properties = 0)
                    212: {
                    213:     //
                    214:     // Initialize this object's minimal state.
                    215:     //
                    216: 
                    217:     if ( super::init(properties) == false )  return false;
                    218: 
                    219:     _anchors         = new AnchorTable(kAnchorsGrowCount, kAnchorsMaxCount);
                    220:     _bdevswInstalled = false;
                    221:     _cdevswInstalled = false;
                    222:     _minors          = new MinorTable(kMinorsGrowCount, kMinorsMaxCount);
                    223:     _notifier        = 0;
                    224: 
                    225:     if ( _anchors == 0 || _minors == 0 )  return false;
                    226: 
                    227:     return true;
                    228: }
                    229: 
                    230: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    231: 
                    232: void IOMediaBSDClient::free()
                    233: {
                    234:     //
                    235:     // Free all of this object's outstanding resources.
                    236:     //
                    237: 
                    238:     if ( _notifier )         _notifier->remove();
                    239:     if ( _cdevswInstalled )  cdevsw_remove(kMajor, &cdevswFunctions); 
                    240:     if ( _bdevswInstalled )  bdevsw_remove(kMajor, &bdevswFunctions);
                    241:     if ( _minors )           delete _minors;
                    242:     if ( _anchors )          delete _anchors;
                    243: 
                    244:     super::free();
                    245: }
                    246: 
                    247: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    248: 
                    249: bool IOMediaBSDClient::start(IOService * provider)
                    250: {
                    251:     //
                    252:     // This method is called once we have been attached to the provider object.
                    253:     //
                    254: 
                    255:     assert(gIOMediaBSDClient == 0);
                    256: 
                    257:     // Ask our superclass' opinion.
                    258: 
                    259:     if ( super::start(provider) == false )  return false;
                    260: 
                    261:     // Establish a global reference to this instance.
                    262: 
                    263:     gIOMediaBSDClient = this;
                    264: 
                    265:     // Install bdevsw and cdevsw functions.
                    266: 
                    267:     _bdevswInstalled = (bdevsw_add(kMajor, &bdevswFunctions) == kMajor);
                    268:     _cdevswInstalled = (cdevsw_add(kMajor, &cdevswFunctions) == kMajor);
                    269: 
                    270:     if ( _bdevswInstalled == false && _cdevswInstalled == false )  return false;
                    271: 
                    272:     // Create a notification handler for media arrival.  We ask for a priority
                    273:     // of ten to ensure that we are notified ahead of other interested clients
                    274:     // (with a default priority of zero), so that we can place the BSD-related
                    275:     // properties on the media object that they might need in time.
                    276: 
                    277:     _notifier = addNotification( /* type        */ gIOFirstPublishNotification,
                    278:                                  /* description */ serviceMatching("IOMedia"),
                    279:                                  /* action      */ mediaHasArrived,
                    280:                                  /* target      */ this,
                    281:                                  /* parameter   */ 0,
                    282:                                  /* priority    */ 10 );
                    283: 
                    284:     if ( _notifier == 0 )  return false;
                    285: 
                    286:     // Register this object so it can be found via notification requests. It is
                    287:     // not being registered to have I/O Kit attempt to have drivers match on it,
                    288:     // which is the reason most other services are registered -- that's not the
                    289:     // intention of this registerService call.
                    290: 
                    291:     registerService();
                    292: 
                    293:     return true;
                    294: }
                    295: 
                    296: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    297: 
                    298: void IOMediaBSDClient::stop(IOService * provider)
                    299: {
                    300:     //
                    301:     // This method is called before we are detached from the provider object.
                    302:     //
                    303: 
                    304:     IOMedia * media   = (IOMedia *) provider;
                    305:     UInt32    minorID = 0;
                    306: 
                    307:     // Disable access to tables, matching, opens, closes, and terminations.
                    308: 
                    309:     gIOMediaBSDClient->lockForArbitration();
                    310: 
                    311:     // Find the minor assigned to this media.
                    312: 
                    313:     minorID = _minors->locate(media);
                    314:     assert(minorID != kInvalidMinorID);
                    315: 
                    316:     // State our assumptions.
                    317: 
                    318:     assert(media->isOpen() == false);
                    319: 
                    320:     // Remove the minor from the minor table, unless it's still in flux (which
                    321:     // means an open on the bdevsw/cdevsw switch is still outstanding: the one
                    322:     // that sent the eject ioctl), in which case we mark the minor as obsolete
                    323:     // for later removal.
                    324: 
                    325:     if ( _minors->getMinor(minorID)->isEjecting )         // (is minor in flux?)
                    326:     {
                    327:         assert(_minors->isObsolete(minorID) == false);
                    328: 
                    329:         _minors->obsolete(minorID);
                    330:     }
                    331:     else
                    332:     {
                    333:         assert(_minors->getMinor(minorID)->bdevOpen == false);
                    334:         assert(_minors->getMinor(minorID)->cdevOpen == false);
                    335: 
                    336:         _minors->remove(minorID);
                    337:     }
                    338:    
                    339:     // Enable access to tables, matching, opens, closes, and terminations.
                    340: 
                    341:     gIOMediaBSDClient->unlockForArbitration();
                    342: 
                    343:     // Call upon the superclass to finish its work.
                    344: 
                    345:     super::stop(media);
                    346: }
                    347: 
                    348: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    349: 
                    350: bool IOMediaBSDClient::mediaHasArrived( void *      /* target */,
                    351:                                         void *      /* parameter */,
                    352:                                         IOService * service )
                    353: {
                    354:     //
                    355:     // Notification handler for media arrivals.
                    356:     //
                    357: 
                    358:     IOMedia * media   = OSDynamicCast(IOMedia, service);
                    359:     bool      success = false;
                    360: 
                    361:     assert(gIOMediaBSDClient);
                    362: 
                    363:     // Attach the media-bsd-client object as a client of the new media object.
                    364: 
                    365:     if ( media && gIOMediaBSDClient->attach(media) )
                    366:     {
                    367:         // Disable access to tables, matching, opens, closes, and terminations.
                    368: 
                    369:         gIOMediaBSDClient->lockForArbitration();
                    370: 
                    371:         // Create bdevsw and cdevsw nodes for the new media object.
                    372: 
                    373:         success = gIOMediaBSDClient->createNodes(media);
                    374: 
                    375:         // Enable access to tables, matching, opens, closes, and terminations.
                    376: 
                    377:         gIOMediaBSDClient->unlockForArbitration();
                    378: 
                    379:         // Detach the media-bsd-client object from the media object on error.
                    380: 
                    381:         if (success == false)  gIOMediaBSDClient->detach(media);
                    382:     }
                    383: 
                    384:     return true; // (meaningless return value)
                    385: }
                    386: 
                    387: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    388: 
                    389: IOMedia * IOMediaBSDClient::getWholeMedia( IOMedia * media,
                    390:                                            UInt32 *  slicePathSize = 0,
                    391:                                            char *    slicePath     = 0 )
                    392: {
                    393:     //
                    394:     // Find the whole media that roots this media tree.  A null return value
                    395:     // indicates no whole media was found or a malformed tree was detected.
                    396:     //
                    397:     // If slicePathSize is non-zero, the size required to fit the slice path
                    398:     // (including the zero terminator) is passed back as a result.
                    399:     //
                    400:     // If slicePathSize and slicePath are both non-zero, the slice path will
                    401:     // be written into the slicePath buffer.  The value slicePathSize points
                    402:     // to must be the size of the slicePath buffer, which is used for sanity
                    403:     // checking in this method.
                    404:     //
                    405: 
                    406:     UInt32      depth    = 1;
                    407:     UInt32      position = sizeof('\0');
                    408:     IOService * service  = 0;
                    409: 
                    410:     assert(slicePath == 0 || slicePathSize != 0);
                    411: 
                    412:     // Search the registry for the parent whole media for this media.
                    413: 
                    414:     for ( service = media; service; service = service->getProvider() )
                    415:     {
                    416:         if ( OSDynamicCast(IOMedia, service) )               // (is it a media?)
                    417:         {
                    418:             if ( ((IOMedia *)service)->isWhole() )     // (is it a whole media?)
                    419:             {
                    420:                 if ( slicePath )            // (are we building the slice path?)
                    421:                 {
                    422:                     slicePath[*slicePathSize - 1] = 0;  // (zero terminate path)
                    423: 
                    424:                     if ( position < *slicePathSize )     // (need to move path?)
                    425:                     {
                    426:                         memmove( slicePath,    // (move path to start of buffer)
                    427:                                  slicePath + (*slicePathSize - position),
                    428:                                  position );
                    429:                     }
                    430:                 }
                    431:                 else if ( slicePathSize ) // (report size req'd for slice path?)
                    432:                 {
                    433:                     *slicePathSize = position;
                    434:                 }
                    435: 
                    436:                 return (IOMedia *)service;           // (return the whole media)
                    437:             }
                    438: 
                    439:             // Determine whether this non-whole media has a location value.  It
                    440:             // must, by definition of a non-whole media, but if it does not, we
                    441:             // should return an error condition.
                    442: 
                    443:             const char * location = service->getLocation();
                    444: 
                    445:             if ( location == 0 )            // (no location on non-whole media?)
                    446:             {
                    447:                 if ( service == media ) IOLog(kMsgNoLocation, media->getName());
                    448:                 return 0;
                    449:             }
                    450: 
                    451:             // Otherwise, it's a valid non-whole media: we compute the required
                    452:             // size for the slice path or build the slice path, if so requested.
                    453:             // Note that the slice path is built backwards from the ends of the
                    454:             // supplied buffer to the beginning of the buffer.
                    455: 
                    456:             position += sizeof('s') + strlen(location);
                    457: 
                    458:             if ( slicePath )                          // (build the slice path?)
                    459:             {
                    460:                 char * path = slicePath + *slicePathSize - position;
                    461: 
                    462:                 if ( position > *slicePathSize )  { assert(0);  return 0; }
                    463: 
                    464:                 *path = 's';
                    465:                 strncpy(path + sizeof('s'), location, strlen(location));
                    466:             }
                    467: 
                    468:             depth += 1;
                    469:         }
                    470:     }
                    471: 
                    472:     // If we've fallen through, then the whole media was never found.
                    473: 
                    474:     if ( depth == 1 ) IOLog(kMsgNoWhole, media->getName());
                    475:     return 0;
                    476: }
                    477: 
                    478: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    479: 
                    480: bool IOMediaBSDClient::createNodes(IOMedia * media)
                    481: {
                    482:     //
                    483:     // Create bdevsw and cdevsw nodes for the given media object.
                    484:     //
                    485:     // This method assumes that the arbitration lock is held.
                    486:     //
                    487: 
                    488:     IOService * anchor;
                    489:     UInt32      anchorID;
                    490:     bool        anchorNew = false;
                    491:     UInt32      minorID;
                    492:     char *      slicePath = 0;
                    493:     UInt32      slicePathSize;
                    494:     IOMedia *   whole;
                    495: 
                    496:     //
                    497:     // Find the anchor that roots this media tree.  The anchor is defined as the
                    498:     // parent of the whole media that roots this media tree.  It is an important
                    499:     // object to us because this object stays in place when media is ejected, so
                    500:     // we can continue to maintain the "unit number" of the "drive" such that if
                    501:     // media is re-inserted, it will show up under the same "unit number".   You
                    502:     // can think of the typical anchor as being the drive, if it helps, although
                    503:     // it could be one of many other kinds of objects (eg. a RAID scheme).
                    504:     //
                    505: 
                    506:     whole = getWholeMedia(media, &slicePathSize);
                    507:     if ( whole == 0 )  return false;
                    508: 
                    509:     anchor = whole->getProvider();
                    510:     if ( anchor == 0 )  return false;
                    511: 
                    512:     //
                    513:     // Determine whether the anchor already exists in the anchor table (obsolete
                    514:     // occurences are skipped in the search, as appropriate,  since those anchor
                    515:     // IDs are to be removed soon). If the anchor does not exist, insert it into
                    516:     // anchor table.
                    517:     //
                    518: 
                    519:     anchorID = _anchors->locate(anchor);
                    520: 
                    521:     if ( anchorID != kInvalidAnchorID )
                    522:     {
                    523:         //
                    524:         // The anchor does exist in the table, however we've got more to check.
                    525:         //
                    526:         // We need to ensure that the whole media associated with this anchor is
                    527:         // the same as ours.  If it is, all is well.  If it isn't, then there is
                    528:         // still a chance all is well.  It is possible to have an old media tree
                    529:         // still associated with the anchor: the tree would be inactive, but not
                    530:         // yet terminated (this can happen on forced termination of a media tree
                    531:         // with oustanding opens, since the close must come before the terminate
                    532:         // can proceed; it can happen even in normal eject conditions should the
                    533:         // media be immediately reinserted when the termination on the old tree,
                    534:         // which is asynchronous, is still chugging along on another thread). In
                    535:         // case the tree is inactive, we mark the anchorID as obsolete and use a
                    536:         // new anchorID.  In the case the tree is not inactive, then we've got a
                    537:         // problem and we must bail out.
                    538:         //
                    539:         // A few additional notes:
                    540:         //
                    541:         //  o if the whole media is indeed the same as the one in our tables, we
                    542:         //    need not check that it is active, because by virtue of the fact we
                    543:         //    got a new media notification on the same tree, we know for sure it
                    544:         //    cannot be in the inactive state.
                    545:         //
                    546:         //  o if the whole media is not in our tables, it is quite possible that
                    547:         //    some child non-whole media from the old media tree is still around
                    548:         //    as terminations work from the bottom (whole media) up (to leaves),
                    549:         //    and the asynchronous termination thread is still not done chugging
                    550:         //    through the medias on the old tree.  We use a new anchorID in this
                    551:         //    case.
                    552:         //
                    553: 
                    554:         IOMedia * wholeInTable = _minors->getWholeMediaAtAnchorID(anchorID);
                    555: 
                    556:         if ( wholeInTable == 0 )  // (is an existing whole media in our tables?)
                    557:         {
                    558:             if ( _minors->hasReferencesToAnchorID(anchorID) )   // (any medias?)
                    559:             {
                    560:                 _anchors->obsolete(anchorID);        // (obsolete old anchor ID)
                    561:                 anchorID = kInvalidAnchorID;         // ( request new anchor ID)
                    562:             }                                             // (else, all is well)
                    563:         }
                    564:         else if ( whole != wholeInTable )  // (old whole media not same as new?)
                    565:         {
                    566:             if ( wholeInTable->isInactive() )   // (is it inactive/terminating?)
                    567:             {
                    568:                 _anchors->obsolete(anchorID);        // (obsolete old anchor ID)
                    569:                 anchorID = kInvalidAnchorID;         // ( request new anchor ID)
                    570:             }
                    571:             else               // (peer active whole medias detected, log error)
                    572:             {
                    573:                 if ( whole == media )  IOLog(kMsgBadWhole, whole->getName());
                    574:                 return false;
                    575:             }
                    576:         }                                                 // (else, all is well)
                    577:     }
                    578: 
                    579:     if ( anchorID == kInvalidAnchorID )
                    580:     {
                    581:         anchorID = _anchors->insert(anchor);              // (get new anchor ID)
                    582:         if ( anchorID == kInvalidAnchorID )  return false;
                    583:         anchorNew = true;
                    584:     }
                    585: 
                    586:     //
                    587:     // Allocate space for and build the slice path for the device node names.
                    588:     //
                    589: 
                    590:     slicePath = (char *) IOMalloc(slicePathSize);
                    591:     if ( slicePath == 0 )  goto createNodesErr;
                    592: 
                    593:     whole = getWholeMedia(media, &slicePathSize, slicePath);
                    594:     assert(whole);
                    595: 
                    596:     //
                    597:     // Insert the new media into our minor table (we're almost done :-).
                    598:     //
                    599: 
                    600:     minorID = _minors->insert(media, anchorID, slicePath);
                    601:     if ( minorID == kInvalidMinorID )  goto createNodesErr;
                    602: 
                    603:     //
                    604:     // Create the required properties on the media.
                    605:     //
                    606: 
                    607:     media->setProperty(kIOBSDName,  _minors->getMinor(minorID)->name);
                    608:     media->setProperty(kIOBSDUnit,  anchorID, 32);              // ("BSD Unit" )
                    609:     media->setProperty(kIOBSDMajor, kMajor,   32);              // ("BSD Major")
                    610:     media->setProperty(kIOBSDMinor, minorID,  32);              // ("BSD Minor")
                    611: 
                    612:     //
                    613:     // Clean up outstanding resources.
                    614:     //
                    615: 
                    616:     IOFree(slicePath, slicePathSize);
                    617: 
                    618:     return true; // (success)
                    619: 
                    620: createNodesErr:
                    621: 
                    622:     if (anchorNew)  _anchors->remove(anchorID);
                    623:     if (slicePath)  IOFree(slicePath, slicePathSize);
                    624: 
                    625:     return false; // (failure)
                    626: }
                    627: 
                    628: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    629: 
                    630: AnchorTable * IOMediaBSDClient::getAnchors()
                    631: {
                    632:     //
                    633:     // Obtain the table of anchors.
                    634:     //
                    635: 
                    636:     return _anchors;
                    637: }
                    638: 
                    639: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    640: 
                    641: MinorTable * IOMediaBSDClient::getMinors()
                    642: {
                    643:     //
                    644:     // Obtain the table of anchors.
                    645:     //
                    646: 
                    647:     return _minors;
                    648: }
                    649: 
                    650: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    651: 
                    652: MinorSlot * IOMediaBSDClient::getMinor(UInt32 minorID)
                    653: {
                    654:     //
                    655:     // Obtain information for the specified minor ID.
                    656:     //
                    657: 
                    658:     return _minors->getMinor(minorID);
                    659: }
                    660: 
                    661: // =============================================================================
                    662: // BSD Functions
                    663: 
                    664: int dkopen(dev_t dev, int flags, int devtype, struct proc *)
                    665: {
                    666:     //
                    667:     // dkopen opens the device (called on each open).
                    668:     //
                    669: 
                    670:     int             error;
                    671:     IOStorageAccess level;
                    672:     MinorSlot *     minor;
                    673: 
                    674:     assert(gIOMediaBSDClient);
                    675:     assert(S_ISBLK(devtype) || S_ISCHR(devtype));
                    676: 
                    677:     gIOMediaBSDClient->lockForArbitration();                 // (disable access)
                    678: 
                    679:     assert(gIOMediaBSDClient->getMinors());
                    680: 
                    681:     error = 0;
                    682:     level = (flags & FWRITE) ? kAccessReaderWriter : kAccessReader;
                    683:     minor = gIOMediaBSDClient->getMinor(minor(dev));
                    684: 
                    685:     //
                    686:     // Process the open.
                    687:     //
                    688: 
                    689:     if ( minor == 0 )                                       // (is minor valid?)
                    690:     {
                    691:         error = ENXIO;
                    692:     }
                    693:     else if ( minor->isEjecting )                         // (is minor in flux?)
                    694:     {
                    695:         error = EBUSY;
                    696:     }
                    697:     else if ( (flags & FWRITE) )                        // (is client a writer?)
                    698:     {
                    699:         if ( minor->bdevWriter || minor->cdevWriter )  level = kAccessNone;
                    700:     }
                    701:     else                                                // (is client a reader?)
                    702:     {
                    703:         if ( minor->bdevOpen || minor->cdevOpen )  level = kAccessNone;
                    704:     }
                    705: 
                    706:     if ( error == 0 && level != kAccessNone )  // (issue the open (or upgrade)?)
                    707:     {
                    708:         if ( minor->media->open(gIOMediaBSDClient, 0, level) == false )  // (go)
                    709:         {
                    710:             error = EBUSY;
                    711:         }
                    712:     }
                    713: 
                    714:     if ( error == 0 )                                          // (update state)
                    715:     {
                    716:         if ( S_ISBLK(devtype) )
                    717:         {
                    718:             minor->bdevOpen = true;
                    719:             if ( (flags & FWRITE) )  minor->bdevWriter = true;
                    720:         }
                    721:         else
                    722:         {
                    723:             minor->cdevOpen = true;
                    724:             if ( (flags & FWRITE) )  minor->cdevWriter = true;
                    725:         }
                    726:     }
                    727: 
                    728:     gIOMediaBSDClient->unlockForArbitration();                // (enable access)
                    729: 
                    730:     return error;
                    731: }
                    732: 
                    733: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    734: 
                    735: int dkclose(dev_t dev, int /* flags */, int devtype, struct proc *)
                    736: {
                    737:     //
                    738:     // dkclose closes the device (called on last close).
                    739:     //
                    740: 
                    741:     MinorSlot * minor;
                    742:     bool        wasWriter;
                    743: 
                    744:     assert(S_ISBLK(devtype) || S_ISCHR(devtype));
                    745: 
                    746:     gIOMediaBSDClient->lockForArbitration();                 // (disable access)
                    747: 
                    748:     minor     = gIOMediaBSDClient->getMinor(minor(dev));
                    749:     wasWriter = (minor->bdevWriter || minor->cdevWriter); 
                    750: 
                    751:     if ( S_ISBLK(devtype) )                                    // (update state)
                    752:     {
                    753:         minor->bdevBlockSize = minor->media->getPreferredBlockSize();
                    754:         minor->bdevOpen      = false;
                    755:         minor->bdevWriter    = false;
                    756:     }
                    757:     else
                    758:     {
                    759:         minor->cdevOpen      = false;
                    760:         minor->cdevWriter    = false;
                    761:     }
                    762: 
                    763:     if ( minor->isEjecting )                              // (is minor in flux?)
                    764:     {
                    765:         //
                    766:         // We've determined that the specified minor is in ejection flux.  This
                    767:         // means we are in a state where the media object has been closed, only
                    768:         // the device node is still open.  This happens to the minor subsequent
                    769:         // to a DKIOCEJECT ioctl -- this close resets the flux state to normal.
                    770:         //
                    771: 
                    772:         minor->isEjecting = false;
                    773: 
                    774:         // If this minor is marked as obsolete, then we've already received the
                    775:         // media's termination notification (stop method), but the minor is yet
                    776:         // to be removed from the table -- remove it now.
                    777: 
                    778:         assert(minor->bdevOpen == false);
                    779:         assert(minor->cdevOpen == false);
                    780: 
                    781:         if ( minor->isObsolete )
                    782:             gIOMediaBSDClient->getMinors()->remove(minor(dev));
                    783:     }
                    784:     else if ( !minor->bdevOpen && !minor->cdevOpen )
                    785:     {
                    786:         //
                    787:         // We communicate the close down to the media object once all opens are
                    788:         // gone, on both the block and character device nodes.
                    789:         //
                    790: 
                    791:         minor->media->close(gIOMediaBSDClient);                          // (go)
                    792:     }
                    793:     else if ( !minor->bdevWriter && !minor->cdevWriter && wasWriter )
                    794:     {
                    795:         //
                    796:         // We communicate a downgrade down to the media object once all writers
                    797:         // are gone and while readers still exist. 
                    798:         //
                    799: 
                    800:         bool success;
                    801:         success = minor->media->open(gIOMediaBSDClient, 0, kAccessReader);
                    802:         assert(success);         // (should never fail, unless avoided deadlock)
                    803:     }
                    804: 
                    805:     gIOMediaBSDClient->unlockForArbitration();                // (enable access)
                    806: 
                    807:     return 0;
                    808: }
                    809: 
                    810: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    811: 
                    812: int dkread(dev_t dev, struct uio * uio, int /* flags */)
                    813: {
                    814:     //
                    815:     // dkread reads data from a device.
                    816:     //
                    817: 
                    818:     struct dio dio = { dev, uio };
                    819: 
                    820:     return dkreadwrite(&dio, DKRTYPE_DIO);
                    821: }
                    822: 
                    823: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    824: 
                    825: int dkwrite(dev_t dev, struct uio * uio, int /* flags */)
                    826: {
                    827:     //
                    828:     // dkwrite writes data to a device.
                    829:     //
                    830: 
                    831:     struct dio dio = { dev, uio };
                    832: 
                    833:     return dkreadwrite(&dio, DKRTYPE_DIO);
                    834: }
                    835: 
                    836: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    837: 
                    838: void dkstrategy(struct buf * bp)
                    839: {
                    840:     //
                    841:     // dkstrategy starts an asynchronous read or write operation.  It returns
                    842:     // to the caller as soon as the operation is queued, and completes it via
                    843:     // the biodone function.
                    844:     //
                    845: 
                    846:     dkreadwrite(bp, DKRTYPE_BUF);
                    847: }
                    848: 
                    849: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    850: 
                    851: int dkioctl(dev_t dev, u_long cmd, caddr_t data, int, struct proc *)
                    852: {
                    853:     //
                    854:     // dkioctl performs operations other than a read or write.
                    855:     //
                    856: 
                    857:     int         error = 0;
                    858:     MinorSlot * minor = gIOMediaBSDClient->getMinor(minor(dev));
                    859: 
                    860:     if ( minor->isEjecting )  return EBADF;               // (is minor in flux?)
                    861: 
                    862:     //
                    863:     // Process the ioctl.
                    864:     //
                    865: 
                    866:     switch ( cmd )
                    867:     {
                    868:         case DKIOCGETBLOCKSIZE:                      // getBlockSize(int * out);
                    869:         {
                    870:             //
                    871:             // This ioctl returns the preferred block size of the media object.
                    872:             //
                    873: 
                    874:             *(int *)data = (int) minor->media->getPreferredBlockSize();
                    875: 
                    876:         } break;
                    877: 
                    878:         case DKIOCGETBLOCKCOUNT:                    // getBlockCount(int * out);
                    879:         {
                    880:             //
                    881:             // This ioctl returns the size of the media object in blocks.  The
                    882:             // implied block size is returned by DKIOCGETBLOCKSIZE.
                    883:             //
                    884: 
                    885:             if ( minor->media->getPreferredBlockSize() )
                    886:                 *(int *)data = (int) ( minor->media->getSize()               / 
                    887:                                        minor->media->getPreferredBlockSize() );
                    888:             else
                    889:                 *(int *)data = 0;
                    890: 
                    891:         } break;
                    892: 
                    893:         case DKIOCISFORMATTED:                        // isFormatted(int * out);
                    894:         {
                    895:             //
                    896:             // This ioctl returns truth if the media object is formatted.
                    897:             //
                    898: 
                    899:             *(int *)data = (int) minor->media->isFormatted();
                    900: 
                    901:         } break;
                    902: 
                    903:         case DKIOCGETLOCATION:                    // getLocation(char[128] out);
                    904:         {
                    905:             //
                    906:             // This ioctl returns the open firmware path for this media object.
                    907:             //
                    908: 
                    909:             int    l = sizeof(((struct drive_location *)data)->location);
                    910:             char * p = ((struct drive_location *)data)->location;
                    911: 
                    912:             if ( minor->media->getPath(p, &l, gIODTPlane) && strchr(p, ':') )
                    913:                 strcpy(p, strchr(p, ':') + 1);         // (strip the plane name)
                    914:             else
                    915:                 error = EINVAL;
                    916: 
                    917:         } break;
                    918: 
                    919:         case DKIOCEJECT:                                         // eject(void);
                    920:         {
                    921:             //
                    922:             // This ioctl asks that the media object be ejected from the drive.
                    923:             //
                    924: 
                    925:             IODrive *    drive;
                    926:             MinorTable * minors;
                    927: 
                    928:             drive  = OSDynamicCast(IODrive, minor->media->getProvider());
                    929:             minors = gIOMediaBSDClient->getMinors();
                    930: 
                    931:             // Determine whether this media has a drive object as its parent.
                    932: 
                    933:             if ( drive == 0 )  { error = ENOTTY; break; }
                    934: 
                    935:             // Disable access to tables, matching, opens, closes, terminations.
                    936: 
                    937:             gIOMediaBSDClient->lockForArbitration();
                    938: 
                    939:             // Determine whether there are other opens on the device nodes that
                    940:             // are associated with this anchor -- the one valid open is the one
                    941:             // that issued this eject.
                    942: 
                    943:             if ( minors->getOpenCountForAnchorID(minor->anchorID) > 1 )
                    944:             {
                    945:                 error = EBUSY;
                    946: 
                    947:                 // Enable access to tables, matching, opens, closes, and so on.
                    948: 
                    949:                 gIOMediaBSDClient->unlockForArbitration();
                    950:             }
                    951:             else
                    952:             {
                    953:                 // Mark this minor as being in ejection flux (which means are in
                    954:                 // a state where the media object has been closed but the device
                    955:                 // node is still open; we must reject all future accesses to the
                    956:                 // device node until it is closed;  note that we do this both on
                    957:                 // success and failure of the ejection call).
                    958: 
                    959:                 minor->isEjecting = true;
                    960: 
                    961:                 // Enable access to tables, matching, opens, closes, and so on.
                    962: 
                    963:                 gIOMediaBSDClient->unlockForArbitration();
                    964: 
                    965:                 // Close the media object, since IODrive semantics require that
                    966:                 // no opens exist when the ejection request in made.
                    967: 
                    968:                 minor->media->close(gIOMediaBSDClient);
                    969: 
                    970:                 // Eject the media.
                    971: 
                    972:                 error = gIOMediaBSDClient->errnoFromReturn(drive->ejectMedia());
                    973:             }
                    974: 
                    975:         } break;
                    976: 
                    977:         default:
                    978:         {
                    979:             //
                    980:             // A foreign ioctl was received.  Log an error to the console.
                    981:             //
                    982: 
                    983:             IOLog( "%s: ioctl(%s\'%c\',%d,%d) is unsupported.\n",
                    984:                    minor->name,
                    985:                    ((cmd & IOC_INOUT) == IOC_INOUT) ? ("_IOWR,") :
                    986:                      ( ((cmd & IOC_OUT) == IOC_OUT) ? ("_IOR,") :
                    987:                        ( ((cmd & IOC_IN) == IOC_IN) ? ("_IOW,") :
                    988:                          ( ((cmd & IOC_VOID) == IOC_VOID) ? ("_IO,") : "" ) ) ),
                    989:                    (char) IOCGROUP(cmd),
                    990:                    (int)  (cmd & 0xff),
                    991:                    (int)  IOCPARM_LEN(cmd) );
                    992: 
                    993:             error = ENOTTY;
                    994: 
                    995:         } break;
                    996:     }
                    997: 
                    998:     return error;                                       // (return error status)
                    999: }
                   1000: 
                   1001: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1002: 
                   1003: int dkioctl_bdev(dev_t dev, u_long cmd, caddr_t data, int f, struct proc * proc)
                   1004: {
                   1005:     //
                   1006:     // dkioctl_bdev performs operations other than a read or write, specific to
                   1007:     // the block device.
                   1008:     //
                   1009: 
                   1010:     int         error = 0;
                   1011:     MinorSlot * minor = gIOMediaBSDClient->getMinor(minor(dev));
                   1012: 
                   1013:     if ( minor->isEjecting )  return EBADF;               // (is minor in flux?)
                   1014: 
                   1015:     //
                   1016:     // Process the ioctl.
                   1017:     //
                   1018: 
                   1019:     switch ( cmd )
                   1020:     {
                   1021:         case DKIOCGETBLOCKSIZE:                      // getBlockSize(int * out);
                   1022:         {
                   1023:             //
                   1024:             // This ioctl returns the preferred (or overrided) block size of the
                   1025:             // media object.
                   1026:             //
                   1027: 
                   1028:             *(int *)data = (int) minor->bdevBlockSize;
                   1029: 
                   1030:         } break;
                   1031: 
                   1032:         case DKIOCSETBLOCKSIZE:                       // setBlockSize(int * in);
                   1033:         {
                   1034:             //
                   1035:             // This ioctl overrides the block size for the media object, for the
                   1036:             // duration of all block device opens at this minor.
                   1037:             //
                   1038: 
                   1039:             if ( *(int *)data > 0 )
                   1040:                 minor->bdevBlockSize = (UInt64) (*(int *)data);
                   1041:             else
                   1042:                 error = EINVAL;
                   1043: 
                   1044:         } break;
                   1045: 
                   1046:         case DKIOCGETBLOCKCOUNT:                    // getBlockCount(int * out);
                   1047:         {
                   1048:             //
                   1049:             // This ioctl returns the size of the media object in blocks.  The
                   1050:             // implied block size is returned by DKIOCGETBLOCKSIZE.
                   1051:             //
                   1052: 
                   1053:             if ( minor->bdevBlockSize )
                   1054:                 *(int *)data = (int) ( minor->media->getSize() /
                   1055:                                        minor->bdevBlockSize    );
                   1056:             else
                   1057:                 *(int *)data = 0;
                   1058: 
                   1059:         } break;
                   1060: 
                   1061:         default:
                   1062:         {
                   1063:             //
                   1064:             // Call the common ioctl handler for all other ioctls.
                   1065:             //
                   1066: 
                   1067:             error = dkioctl(dev, cmd, data, f, proc);
                   1068: 
                   1069:         } break;
                   1070:     }
                   1071: 
                   1072:     return error;                                       // (return error status)
                   1073: }
                   1074: 
                   1075: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1076: 
                   1077: int dksize(dev_t dev)
                   1078: {
                   1079:     //
                   1080:     // dksize returns the block size of the media.
                   1081:     //
                   1082:     // This is a departure from BSD 4.4's definition of this function, that is,
                   1083:     // it will not return the size of the disk partition, as would be expected
                   1084:     // in a BSD 4.4 implementation.
                   1085:     //
                   1086: 
                   1087:     MinorSlot * minor = gIOMediaBSDClient->getMinor(minor(dev));
                   1088: 
                   1089:     if ( minor->isEjecting )  return 0;                   // (is minor in flux?)
                   1090: 
                   1091:     return (int) minor->bdevBlockSize;                    // (return block size)
                   1092: }
                   1093: 
                   1094: // =============================================================================
                   1095: // Support For BSD Functions
                   1096: 
                   1097: inline dev_t DKR_GET_DEV(dkr_t dkr, dkrtype_t dkrtype)
                   1098: {
                   1099:     return (dkrtype == DKRTYPE_BUF)
                   1100:            ? ((struct buf *)dkr)->b_dev
                   1101:            : ((struct dio *)dkr)->dev;
                   1102: }
                   1103: 
                   1104: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1105: 
                   1106: inline UInt64 DKR_GET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype)
                   1107: {
                   1108:     return (dkrtype == DKRTYPE_BUF)
                   1109:            ? ((struct buf *)dkr)->b_bcount
                   1110:            : ((struct dio *)dkr)->uio->uio_resid;
                   1111: }
                   1112: 
                   1113: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1114: 
                   1115: inline UInt64 DKR_GET_BYTE_START(dkr_t dkr, dkrtype_t dkrtype)
                   1116: {
                   1117:     if (dkrtype == DKRTYPE_BUF)
                   1118:     {
                   1119:         struct buf * bp    = (struct buf *)dkr;
                   1120:         MinorSlot *  minor = gIOMediaBSDClient->getMinor(minor(bp->b_dev));
                   1121: 
                   1122:         return bp->b_blkno * minor->bdevBlockSize;
                   1123:     }
                   1124:     return ((struct dio *)dkr)->uio->uio_offset;
                   1125: }
                   1126: 
                   1127: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1128: 
                   1129: inline bool DKR_IS_READ(dkr_t dkr, dkrtype_t dkrtype)
                   1130: {
                   1131:     return (dkrtype == DKRTYPE_BUF)
                   1132:            ? ((((struct buf *)dkr)->b_flags & B_READ) == B_READ)
                   1133:            : ((((struct dio *)dkr)->uio->uio_rw) == UIO_READ);
                   1134: }
                   1135: 
                   1136: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1137: 
                   1138: inline bool DKR_IS_ASYNCHRONOUS(dkr_t dkr, dkrtype_t dkrtype)
                   1139: {
                   1140:     return (dkrtype == DKRTYPE_BUF)
                   1141:            ? true
                   1142:            : false;
                   1143: }
                   1144: 
                   1145: 
                   1146: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1147: 
                   1148: inline bool DKR_IS_RAW(dkr_t dkr, dkrtype_t dkrtype)
                   1149: {
                   1150:     return (dkrtype == DKRTYPE_BUF)
                   1151:            ? false
                   1152:            : true;
                   1153: }
                   1154: 
                   1155: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1156: 
                   1157: inline void DKR_SET_BYTE_COUNT(dkr_t dkr, dkrtype_t dkrtype, UInt64 bcount)
                   1158: {
                   1159:     if (dkrtype == DKRTYPE_BUF)
                   1160:         ((struct buf *)dkr)->b_resid = ((struct buf *)dkr)->b_bcount - bcount;
                   1161:     else
                   1162:         ((struct dio *)dkr)->uio->uio_resid -= bcount;
                   1163: }
                   1164: 
                   1165: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1166: 
                   1167: inline void DKR_RUN_COMPLETION(dkr_t dkr, dkrtype_t dkrtype, IOReturn status)
                   1168: {
                   1169:     if (dkrtype == DKRTYPE_BUF)
                   1170:     {
                   1171:         struct buf * bp = (struct buf *)dkr;
                   1172: 
                   1173:         bp->b_error  = gIOMediaBSDClient->errnoFromReturn(status);   // (error?)
                   1174:         bp->b_flags |= (status != kIOReturnSuccess) ? B_ERROR : 0;   // (error?)
                   1175:         biodone(bp);                                       // (complete request)
                   1176:     }
                   1177: }
                   1178: 
                   1179: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1180: 
                   1181: inline IOMemoryDescriptor * DKR_GET_BUFFER(dkr_t dkr, dkrtype_t dkrtype)
                   1182: {
                   1183:     if (dkrtype == DKRTYPE_BUF)
                   1184:     {
                   1185:         struct buf * bp = (struct buf *)dkr;
                   1186: 
                   1187:         return IOMemoryDescriptor::withAddress(                // (single-range)
                   1188:           (vm_address_t) bp->b_data,
                   1189:           (vm_size_t)    bp->b_bcount,
                   1190:           (bp->b_flags & B_READ) ? kIODirectionIn : kIODirectionOut,
                   1191:           (bp->b_flags & B_PHYS) ? get_user_task() : get_kernel_task() );
                   1192:     }
                   1193:     else
                   1194:     {
                   1195:         struct uio * uio = ((struct dio *)dkr)->uio;
                   1196: 
                   1197:         assert( sizeof(IOVirtualRange         ) == sizeof(iovec          ) ); 
                   1198:         assert( sizeof(IOVirtualRange::address) == sizeof(iovec::iov_base) );
                   1199:         assert( sizeof(IOVirtualRange::length ) == sizeof(iovec::iov_len ) );
                   1200: 
                   1201:         return IOMemoryDescriptor::withRanges(               // (multiple-range)
                   1202:         (IOVirtualRange *) uio->uio_iov,
                   1203:         (UInt32)           uio->uio_iovcnt,
                   1204:         (uio->uio_rw     == UIO_READ    ) ? kIODirectionIn  : kIODirectionOut,
                   1205:         (uio->uio_segflg != UIO_SYSSPACE) ? get_user_task() : get_kernel_task(),
                   1206:         true );
                   1207:     }
                   1208: }
                   1209: 
                   1210: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1211: 
                   1212: int dkreadwrite(dkr_t dkr, dkrtype_t dkrtype)
                   1213: {
                   1214:     //
                   1215:     // dkreadwrite performs a read or write operation.
                   1216:     //
                   1217: 
                   1218:     IOMemoryDescriptor * buffer;
                   1219:     register UInt64      byteCount;
                   1220:     register UInt64      byteStart;
                   1221:     UInt64               mediaSize;
                   1222:     MinorSlot *          minor;
                   1223:     IOReturn             status;
                   1224: 
                   1225:     minor = gIOMediaBSDClient->getMinor(minor(DKR_GET_DEV(dkr, dkrtype)));
                   1226: 
                   1227:     if ( minor->isEjecting )                              // (is minor in flux?)
                   1228:     {
                   1229:         status = kIOReturnNoMedia;
                   1230:         goto dkreadwriteErr;
                   1231:     }
                   1232: 
                   1233:     if ( minor->media->isFormatted() == false )       // (is media unformatted?)
                   1234:     {
                   1235:         status = kIOReturnUnformattedMedia;
                   1236:         goto dkreadwriteErr;
                   1237:     }
                   1238: 
                   1239:     byteCount = DKR_GET_BYTE_COUNT(dkr, dkrtype);            // (get byte count)
                   1240:     byteStart = DKR_GET_BYTE_START(dkr, dkrtype);            // (get byte start)
                   1241:     mediaSize = minor->media->getSize();                     // (get media size)
                   1242: 
                   1243:     //
                   1244:     // We must reject non-block-aligned requests to conform to BSD semantics.
                   1245:     //
                   1246: 
                   1247:     if ( DKR_IS_RAW(dkr, dkrtype) )
                   1248:     {
                   1249:         UInt64 mediaBlockSize = minor->media->getPreferredBlockSize();
                   1250: 
                   1251:         if ( (byteStart % mediaBlockSize) || (byteCount % mediaBlockSize) )
                   1252:         {
                   1253:             status = kIOReturnNotAligned;
                   1254:             goto dkreadwriteErr;
                   1255:         }
                   1256:     }
                   1257: 
                   1258:     //
                   1259:     // We must take in account that short reads and writes are not considered
                   1260:     // errors under BSD semantics.  We're to transfer as many bytes as can be
                   1261:     // read or written from the medium and return no error.  Also, reads that
                   1262:     // start at (or perhaps past) the end-of-media are not considered errors,
                   1263:     // even though no data is transferred, while writes at (or past) the end-
                   1264:     // of-media do indeed return errors.  This differs from IOMedia semantics
                   1265:     // which is to fail the entire request without transferring a single byte
                   1266:     // should it include for something past the end-of-media.   We must adapt
                   1267:     // the IOMedia semantics to look like BSD semantics here.
                   1268:     // 
                   1269: 
                   1270:     if ( byteStart >= mediaSize )     // (is start at or past the end-of-media?)
                   1271:     {
                   1272:         status = DKR_IS_READ(dkr,dkrtype) ? kIOReturnSuccess : kIOReturnIOError;
                   1273:         goto dkreadwriteErr;
                   1274:     }
                   1275: 
                   1276:     //
                   1277:     // Build a descriptor which describes the buffer involved in the transfer.
                   1278:     //
                   1279: 
                   1280:     buffer = DKR_GET_BUFFER(dkr, dkrtype);
                   1281: 
                   1282:     if ( buffer == 0 )                                           // (no buffer?)
                   1283:     {
                   1284:         status = kIOReturnNoMemory;
                   1285:         goto dkreadwriteErr;
                   1286:     }
                   1287: 
                   1288:     //
                   1289:     // Clip the transfer buffer should this be a short read or write request.
                   1290:     //
                   1291: 
                   1292:     if ( byteCount > mediaSize - byteStart )           // (clip at end-of-media)
                   1293:     {
                   1294:         IOMemoryDescriptor * originalBuffer = buffer;
                   1295: 
                   1296:         buffer = IOMemoryDescriptor::withSubRange(
                   1297:                            /* descriptor    */ originalBuffer,
                   1298:                            /* withOffset    */ 0,
                   1299:                            /* withLength    */ mediaSize - byteStart,
                   1300:                            /* withDirection */ originalBuffer->getDirection() );
                   1301: 
                   1302:         originalBuffer->release();   // (either retained above or about to fail)
                   1303: 
                   1304:         if ( buffer == 0 )                                      // (no buffer?)
                   1305:         {
                   1306:             status = kIOReturnNoMemory;
                   1307:             goto dkreadwriteErr;
                   1308:         }
                   1309:     }
                   1310: 
                   1311:     //
                   1312:     // Execute the transfer. 
                   1313:     //
                   1314: 
                   1315:     if ( DKR_IS_ASYNCHRONOUS(dkr, dkrtype) )       // (an asynchronous request?)
                   1316:     {
                   1317:         IOStorageCompletion completion;
                   1318: 
                   1319:         completion.target    = dkr;
                   1320:         completion.action    = dkreadwritecompletion;
                   1321:         completion.parameter = (void *) dkrtype;
                   1322: 
                   1323:         if ( DKR_IS_READ(dkr, dkrtype) )                            // (a read?)
                   1324:         {
                   1325:             minor->media->read(  /* client     */ gIOMediaBSDClient,
                   1326:                                  /* byteStart  */ byteStart,
                   1327:                                  /* buffer     */ buffer,
                   1328:                                  /* completion */ completion );          // (go)
                   1329:         }
                   1330:         else                                                       // (a write?)
                   1331:         {
                   1332:             minor->media->write( /* client     */ gIOMediaBSDClient,
                   1333:                                  /* byteStart  */ byteStart,
                   1334:                                  /* buffer     */ buffer,
                   1335:                                  /* completion */ completion );          // (go)
                   1336:         }
                   1337:         status = kIOReturnSuccess;
                   1338:     }
                   1339:     else                                     // (is this a synchronous request?)
                   1340:     {
                   1341:         if ( DKR_IS_READ(dkr, dkrtype) )                            // (a read?)
                   1342:         {
                   1343:             status = minor->media->read(
                   1344:                                  /* client          */ gIOMediaBSDClient,
                   1345:                                  /* byteStart       */ byteStart,
                   1346:                                  /* buffer          */ buffer,
                   1347:                                  /* actualByteCount */ &byteCount );     // (go)
                   1348:         }
                   1349:         else                                                       // (a write?)
                   1350:         {
                   1351:             status = minor->media->write(
                   1352:                                  /* client          */ gIOMediaBSDClient,
                   1353:                                  /* byteStart       */ byteStart,
                   1354:                                  /* buffer          */ buffer,
                   1355:                                  /* actualByteCount */ &byteCount );     // (go)
                   1356:         }
                   1357: 
                   1358:         dkreadwritecompletion(dkr, (void *)dkrtype, status, byteCount);
                   1359:     }
                   1360: 
                   1361:     //
                   1362:     // We release our retain on the buffer now, even though in the asynchronous
                   1363:     // case, the object needs to exist for the duration of the transfer.  While
                   1364:     // this might appear to be a mistake, it is not.   The layers below us will
                   1365:     // have retained the buffer themselves.  On the last release, the buffer is
                   1366:     // complete()'d appropriately.
                   1367:     //
                   1368: 
                   1369:     buffer->release();                     // (release our retain on the buffer)
                   1370: 
                   1371:     return gIOMediaBSDClient->errnoFromReturn(status);  // (return error status)
                   1372: 
                   1373: dkreadwriteErr:
                   1374: 
                   1375:     dkreadwritecompletion(dkr, (void *)dkrtype, status, 0);
                   1376: 
                   1377:     return gIOMediaBSDClient->errnoFromReturn(status);  // (return error status)
                   1378: }
                   1379: 
                   1380: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1381: 
                   1382: void dkreadwritecompletion( void *   target,
                   1383:                             void *   parameter,
                   1384:                             IOReturn status,
                   1385:                             UInt64   actualByteCount )
                   1386: {
                   1387:     //
                   1388:     // dkreadwritecompletion cleans up after a read or write operation.
                   1389:     //
                   1390: 
                   1391:     dkr_t     dkr      = (dkr_t) target;
                   1392:     dkrtype_t dkrtype  = (dkrtype_t) (int) parameter;
                   1393:     dev_t     dev      = DKR_GET_DEV(dkr, dkrtype);
                   1394: 
                   1395: #ifdef IOMEDIABSDCLIENT_IOSTAT_SUPPORT
                   1396:     UInt32    anchorID = gIOMediaBSDClient->getMinor(minor(dev))->anchorID;
                   1397: 
                   1398:     if ( anchorID < DK_NDRIVE )
                   1399:     {
                   1400:         IODrive * drive = dk_drive[anchorID];
                   1401: 
                   1402:         if ( drive )
                   1403:         {
                   1404:             dk_xfer[anchorID] = (long)
                   1405:               ( drive->getStatistic(IODrive::kStatisticsReads ) +
                   1406:                 drive->getStatistic(IODrive::kStatisticsWrites) );
                   1407:             dk_wds[anchorID] = (long) ( 8 *
                   1408:               ( drive->getStatistic(IODrive::kStatisticsBytesRead   ) +
                   1409:                 drive->getStatistic(IODrive::kStatisticsBytesWritten) ) );
                   1410:         }
                   1411:     }
                   1412: #endif IOMEDIABSDCLIENT_IOSTAT_SUPPORT
                   1413: 
                   1414:     if ( status != kIOReturnSuccess )             // (log errors to the console)
                   1415:     {
                   1416:         IOLog( "%s: %s.\n",
                   1417:                gIOMediaBSDClient->getMinor(minor(dev))->name,
                   1418:                gIOMediaBSDClient->stringFromReturn(status) );
                   1419:     }
                   1420: 
                   1421:     DKR_SET_BYTE_COUNT(dkr, dkrtype, actualByteCount);       // (set byte count)
                   1422:     DKR_RUN_COMPLETION(dkr, dkrtype, status);                // (run completion)
                   1423: }
                   1424: 
                   1425: // =============================================================================
                   1426: // AnchorTable Class
                   1427: 
                   1428: AnchorTable::AnchorTable(UInt32 growCount, UInt32 maxCount)
                   1429: {
                   1430:     //
                   1431:     // Initialize this object's minimal state.
                   1432:     //
                   1433: 
                   1434:     _table          = 0;
                   1435:     _tableCount     = 0;
                   1436:     _tableGrowCount = growCount;
                   1437:     _tableMaxCount  = maxCount;
                   1438: }
                   1439: 
                   1440: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1441: 
                   1442: AnchorTable::~AnchorTable()
                   1443: {
                   1444:     //
                   1445:     // Free all of this object's outstanding resources.
                   1446:     //
                   1447: 
                   1448:     for ( UInt32 anchorID = 0; anchorID < _tableCount; anchorID++ )
                   1449:         if ( _table[anchorID].isAssigned )  remove(anchorID);
                   1450: 
                   1451:     if ( _table )  IODelete(_table, AnchorSlot, _tableCount);
                   1452: }
                   1453: 
                   1454: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1455: 
                   1456: UInt32 AnchorTable::insert(IOService * anchor)
                   1457: {
                   1458:     //
                   1459:     // This method inserts the specified anchor into an unassigned slot in the
                   1460:     // anchor table and returns its ID (or kInvalidAnchorID on a failure).
                   1461:     //
                   1462:     // Note that the anchor is transparently removed from the table should the
                   1463:     // anchor terminate (or it is at least marked obsolete,  should references
                   1464:     // to the anchor still exist in the minor table).
                   1465:     //
                   1466: 
                   1467:     UInt32       anchorID;
                   1468:     IONotifier * notifier;
                   1469: 
                   1470:     // Search for an unassigned slot in the anchor table.
                   1471: 
                   1472:     for ( anchorID = 0; anchorID < _tableCount; anchorID++ )
                   1473:         if ( _table[anchorID].isAssigned == false )  break;
                   1474: 
                   1475:     // Was an unassigned slot found?  If not, grow the table.
                   1476: 
                   1477:     if ( anchorID == _tableCount )
                   1478:     {
                   1479:         AnchorSlot * newTable;
                   1480:         UInt32       newTableCount;
                   1481: 
                   1482:         // We must expand the anchor table since no more slots are available.
                   1483: 
                   1484:         if ( _tableCount >= _tableMaxCount )  return kInvalidAnchorID;
                   1485: 
                   1486:         newTableCount = min(_tableGrowCount + _tableCount, _tableMaxCount);
                   1487:         newTable      = IONew(AnchorSlot, newTableCount);
                   1488: 
                   1489:         if ( newTable == 0 )  return kInvalidAnchorID;
                   1490: 
                   1491:         bzero(newTable, newTableCount * sizeof(AnchorSlot));
                   1492: 
                   1493:         // Copy over the old table's entries, then free the old table.
                   1494: 
                   1495:         if ( _table )
                   1496:         {
                   1497:             bcopy(_table, newTable, _tableCount * sizeof(AnchorSlot));
                   1498:             IODelete(_table, AnchorSlot, _tableCount);
                   1499:         }
                   1500:     
                   1501:         // Obtain the next unassigned index (simple since we know the size of
                   1502:         // the old table),  then update our instance variables to reflect the
                   1503:         // new tables.
                   1504: 
                   1505:         anchorID    = _tableCount;
                   1506:         _table      = newTable;
                   1507:         _tableCount = newTableCount;
                   1508:     }
                   1509: 
                   1510:     // Create a notification handler for the anchor's termination (post-stop);
                   1511:     // the handler will remove the anchor transparently from the table if the
                   1512:     // anchor terminates (or at least marks it obsolete, if references to the
                   1513:     // anchor still exist in the minor table).
                   1514: 
                   1515:     notifier = anchor->registerInterest(
                   1516:                           /* type        */ gIOGeneralInterest,
                   1517:                           /* action      */ anchorChange,
                   1518:                           /* target      */ (void *) this,
                   1519:                           /* parameter   */ 0 );
                   1520:   
                   1521:     if ( notifier == 0 )  return kInvalidAnchorID;
                   1522: 
                   1523:     // Zero the new slot, fill it in, and retain the anchor object.
                   1524: 
                   1525:     bzero(&_table[anchorID], sizeof(AnchorSlot)); // (zero slot)
                   1526: 
                   1527:     _table[anchorID].isAssigned = true;           // (fill in slot)
                   1528:     _table[anchorID].isObsolete = false;
                   1529:     _table[anchorID].anchor     = anchor;
                   1530:     _table[anchorID].notifier   = notifier;
                   1531: 
                   1532:     _table[anchorID].anchor->retain();            // (retain anchor)
                   1533: 
                   1534: #ifdef IOMEDIABSDCLIENT_IOSTAT_SUPPORT
                   1535:     if ( anchorID < DK_NDRIVE )
                   1536:     {
                   1537:         dk_drive[anchorID] = OSDynamicCast(IODrive, anchor);
                   1538:         if ( anchorID + 1 > (UInt32) dk_ndrive )  dk_ndrive = anchorID + 1;
                   1539:     }
                   1540: #endif IOMEDIABSDCLIENT_IOSTAT_SUPPORT
                   1541: 
                   1542:     return anchorID;
                   1543: }
                   1544: 
                   1545: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1546: 
                   1547: void AnchorTable::remove(UInt32 anchorID)
                   1548: {
                   1549:     //
                   1550:     // This method removes the specified anchor from the anchor table.
                   1551:     //
                   1552: 
                   1553:     assert(anchorID < _tableCount);
                   1554:     assert(_table[anchorID].isAssigned);
                   1555: 
                   1556:     // Release the resources retained in the anchor slot and zero it.
                   1557: 
                   1558:     _table[anchorID].notifier->remove();
                   1559:     _table[anchorID].anchor->release();           // (release anchor)
                   1560: 
                   1561:     bzero(&_table[anchorID], sizeof(AnchorSlot)); // (zero slot)
                   1562: 
                   1563: #ifdef IOMEDIABSDCLIENT_IOSTAT_SUPPORT
                   1564:     if ( anchorID < DK_NDRIVE )
                   1565:     {
                   1566:         dk_drive[anchorID] = 0;
                   1567:         for (dk_ndrive = DK_NDRIVE; dk_ndrive; dk_ndrive--)
                   1568:         {
                   1569:            if ( dk_drive[dk_ndrive - 1] )  break;
                   1570:         }
                   1571:     }
                   1572: #endif IOMEDIABSDCLIENT_IOSTAT_SUPPORT
                   1573: }
                   1574: 
                   1575: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1576: 
                   1577: void AnchorTable::obsolete(UInt32 anchorID)
                   1578: {
                   1579:     //
                   1580:     // This method obsoletes the specified anchor, that is, the slot is marked
                   1581:     // as obsolete and will be removed later via the minor table remove method
                   1582:     // once it detects references to the anchor ID drop to 0.   Once obsoleted,
                   1583:     // the anchor can be considered to be removed, since it will not appear in
                   1584:     // locate searches, even though behind the scenes it still occupies a slot.
                   1585:     //
                   1586: 
                   1587:     assert(anchorID < _tableCount);
                   1588:     assert(_table[anchorID].isAssigned);
                   1589: 
                   1590:     // Mark the anchor as obsolete so that it can be removed from the table as
                   1591:     // soon as all its references go away (minor table's responsibility).
                   1592: 
                   1593:     _table[anchorID].isObsolete = true;
                   1594: }
                   1595: 
                   1596: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1597: 
                   1598: UInt32 AnchorTable::locate(IOService * anchor)
                   1599: {
                   1600:     //
                   1601:     // This method searches for the specified anchor in the anchor table and
                   1602:     // returns its ID (or kInvalidAnchorID on a failure).   It ignores slots
                   1603:     // marked as obsolete.
                   1604:     //
                   1605: 
                   1606:     for (UInt32 anchorID = 0; anchorID < _tableCount; anchorID++)
                   1607:     {
                   1608:         if ( _table[anchorID].isAssigned != false  &&
                   1609:              _table[anchorID].isObsolete == false  &&
                   1610:              _table[anchorID].anchor     == anchor )  return anchorID;
                   1611:     }
                   1612: 
                   1613:     return kInvalidAnchorID;
                   1614: }
                   1615: 
                   1616: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1617: 
                   1618: bool AnchorTable::isObsolete(UInt32 anchorID)
                   1619: {
                   1620:     //
                   1621:     // Determine whether the specified anchor ID is marked as obsolete.
                   1622:     //
                   1623: 
                   1624:     assert(anchorID < _tableCount);
                   1625:     assert(_table[anchorID].isAssigned);
                   1626: 
                   1627:     return _table[anchorID].isObsolete ? true : false;
                   1628: }
                   1629: 
                   1630: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1631: 
                   1632: IOReturn AnchorTable::anchorChange(    void *      /* target */,
                   1633:                                        void *      /* parameter */,
                   1634:                                        UInt32      messageType,
                   1635:                                        IOService * anchor,
                   1636:                                        void *      /* messageArgument */,
                   1637:                                        vm_size_t   /* argSize */ )
                   1638: {
                   1639:     if ( messageType != kIOMessageServiceIsTerminated )
                   1640:         return kIOReturnSuccess;
                   1641: 
                   1642:     //
                   1643:     // Notification handler for anchor termination (post-stop).
                   1644:     //
                   1645:     
                   1646:     UInt32 anchorID;
                   1647: 
                   1648:     assert(gIOMediaBSDClient);
                   1649: 
                   1650:     // Disable access to tables, matching, opens, closes, and terminations.
                   1651: 
                   1652:     gIOMediaBSDClient->lockForArbitration();
                   1653: 
                   1654:     // Determine whether this anchor is in the anchor table (obsolete occurences
                   1655:     // are skipped in the search, as appropriate, since those anchor IDs will be
                   1656:     // removed as it is).
                   1657: 
                   1658:     anchorID = gIOMediaBSDClient->getAnchors()->locate(anchor);
                   1659: 
                   1660:     if ( anchorID != kInvalidAnchorID )
                   1661:     {
                   1662:         // Determine whether this anchor is still has references in the minor
                   1663:         // table.  If it does,  we mark the the anchor as obsolete so that it
                   1664:         // will be removed later,  once references to it go to zero (which is
                   1665:         // handled by MinorTable::remove).
                   1666: 
                   1667:         if ( gIOMediaBSDClient->getMinors()->hasReferencesToAnchorID(anchorID) )
                   1668:             gIOMediaBSDClient->getAnchors()->obsolete(anchorID);
                   1669:         else
                   1670:             gIOMediaBSDClient->getAnchors()->remove(anchorID);
                   1671:     }
                   1672: 
                   1673:     // Enable access to tables, matching, opens, closes, and terminations.
                   1674: 
                   1675:     gIOMediaBSDClient->unlockForArbitration();    
                   1676: 
                   1677:     return kIOReturnSuccess;
                   1678: }
                   1679: 
                   1680: // =============================================================================
                   1681: // MinorTable Class
                   1682: 
                   1683: MinorTable::MinorTable(UInt32 growCount, UInt32 maxCount)
                   1684: {
                   1685:     //
                   1686:     // Initialize this object's minimal state.
                   1687:     //
                   1688: 
                   1689:     _table          = 0;
                   1690:     _tableCount     = 0;
                   1691:     _tableGrowCount = growCount;
                   1692:     _tableMaxCount  = maxCount;
                   1693: }
                   1694: 
                   1695: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1696: 
                   1697: MinorTable::~MinorTable()
                   1698: {
                   1699:     //
                   1700:     // Free all of this object's outstanding resources.
                   1701:     //
                   1702: 
                   1703:     for ( UInt32 minorID = 0; minorID < _tableCount; minorID++ )
                   1704:         if ( _table[minorID].isAssigned )  remove(minorID);
                   1705: 
                   1706:     if ( _table )  IODelete(_table, MinorSlot, _tableCount);
                   1707: }
                   1708: 
                   1709: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1710: 
                   1711: UInt32 MinorTable::insert(IOMedia * media, UInt32 anchorID, char * slicePath)
                   1712: {
                   1713:     //
                   1714:     // This method inserts the specified media/anchorID pair into an unassigned
                   1715:     // slot in the minor table and returns its ID (or kInvalidMinorID on error).
                   1716:     //
                   1717:     // Note that the bdev and cdev nodes are published as a result of this call,
                   1718:     // with the name "[r]disk<anchorID><slicePath>".  For instance, "disk2s3s1"
                   1719:     // for an anchorID of 2 and slicePath of "s3s1".
                   1720:     //
                   1721: 
                   1722:     void *       bdevNode;
                   1723:     void *       cdevNode;
                   1724:     UInt32       minorID;
                   1725:     char *       minorName;
                   1726:     UInt32       minorNameSize;
                   1727: 
                   1728:     // Search for an unassigned slot in the minor table.
                   1729: 
                   1730:     for ( minorID = 0; minorID < _tableCount; minorID++ )
                   1731:         if ( _table[minorID].isAssigned == false )  break;
                   1732: 
                   1733:     // Was an unassigned slot found?  If not, grow the table.
                   1734: 
                   1735:     if ( minorID == _tableCount )
                   1736:     {
                   1737:         MinorSlot * newTable;
                   1738:         UInt32      newTableCount;
                   1739: 
                   1740:         // We must expand the minor table since no more slots are available.
                   1741: 
                   1742:         if ( _tableCount >= _tableMaxCount)  return kInvalidMinorID;
                   1743: 
                   1744:         newTableCount = min(_tableGrowCount + _tableCount, _tableMaxCount);
                   1745:         newTable      = IONew(MinorSlot, newTableCount);
                   1746: 
                   1747:         if ( newTable == 0 )  return kInvalidMinorID;
                   1748: 
                   1749:         bzero(newTable, newTableCount * sizeof(MinorSlot));
                   1750: 
                   1751:         // Copy over the old table's entries, then free the old table.
                   1752: 
                   1753:         if ( _table )
                   1754:         {
                   1755:             bcopy(_table, newTable, _tableCount * sizeof(MinorSlot));
                   1756:             IODelete(_table, MinorSlot, _tableCount);
                   1757:         }
                   1758: 
                   1759:         // Obtain the next unassigned index (simple since we know the size of
                   1760:         // the old table),  then update our instance variables to reflect the
                   1761:         // new tables.
                   1762: 
                   1763:         minorID     = _tableCount;
                   1764:         _table      = newTable;
                   1765:         _tableCount = newTableCount;
                   1766:     }
                   1767: 
                   1768:     // Create a buffer large enough to hold the full name of the minor.
                   1769: 
                   1770:     minorNameSize = strlen("disk#");
                   1771:     for (unsigned temp = anchorID; temp >= 10; temp /= 10)  minorNameSize++;
                   1772:     minorNameSize += strlen(slicePath);
                   1773:     minorNameSize += 1;
                   1774:     minorName = IONew(char, minorNameSize);
                   1775: 
                   1776:     // Create a block and character device node in BSD for this media.
                   1777: 
                   1778:     bdevNode = devfs_make_node( /* dev        */ makedev(kMajor, minorID),
                   1779:                                 /* type       */ DEVFS_BLOCK, 
                   1780:                                 /* owner      */ UID_ROOT,
                   1781:                                 /* group      */ GID_OPERATOR, 
                   1782:                                 /* permission */ media->isWritable()?0640:0440, 
                   1783:                                 /* name (fmt) */ "disk%d%s",
                   1784:                                 /* name (arg) */ anchorID,
                   1785:                                 /* name (arg) */ slicePath );
                   1786: 
                   1787:     cdevNode = devfs_make_node( /* dev        */ makedev(kMajor, minorID),
                   1788:                                 /* type       */ DEVFS_CHAR, 
                   1789:                                 /* owner      */ UID_ROOT,
                   1790:                                 /* group      */ GID_OPERATOR, 
                   1791:                                 /* permission */ media->isWritable()?0640:0440,
                   1792:                                 /* name (fmt) */ "rdisk%d%s",
                   1793:                                 /* name (arg) */ anchorID,
                   1794:                                 /* name (arg) */ slicePath );
                   1795: 
                   1796:     if ( minorName == 0 || bdevNode == 0 || cdevNode == 0 )
                   1797:     {
                   1798:         if ( cdevNode )   devfs_remove(cdevNode);
                   1799:         if ( bdevNode )   devfs_remove(bdevNode);
                   1800:         if ( minorName )  IODelete(minorName, char, minorNameSize);
                   1801: 
                   1802:         return kInvalidMinorID;
                   1803:     }
                   1804: 
                   1805:     // Construct a name for the node.
                   1806: 
                   1807:     sprintf(minorName, "disk%ld%s", anchorID, slicePath);
                   1808:     assert(strlen(minorName) + 1 == minorNameSize);
                   1809: 
                   1810:     // Zero the new slot, fill it in, and retain the media object.
                   1811: 
                   1812:     bzero(&_table[minorID], sizeof(MinorSlot));    // (zero slot)
                   1813: 
                   1814:     _table[minorID].isAssigned    = true;          // (fill in slot)
                   1815:     _table[minorID].isEjecting    = false;
                   1816:     _table[minorID].isObsolete    = false;
                   1817:     _table[minorID].anchorID      = anchorID;
                   1818:     _table[minorID].media         = media;
                   1819:     _table[minorID].name          = minorName;
                   1820:     _table[minorID].bdevBlockSize = media->getPreferredBlockSize();
                   1821:     _table[minorID].bdevNode      = bdevNode;
                   1822:     _table[minorID].bdevOpen      = false;
                   1823:     _table[minorID].cdevNode      = cdevNode;
                   1824:     _table[minorID].cdevOpen      = false;
                   1825: 
                   1826:     _table[minorID].media->retain();               // (retain media)
                   1827: 
                   1828:     return minorID;
                   1829: }
                   1830: 
                   1831: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1832: 
                   1833: void MinorTable::remove(UInt32 minorID)
                   1834: {
                   1835:     //
                   1836:     // This method removes the specified minor from the minor table.
                   1837:     //
                   1838: 
                   1839:     UInt32 anchorID;
                   1840: 
                   1841:     assert(minorID < _tableCount);
                   1842:     assert(_table[minorID].isAssigned);
                   1843: 
                   1844:     assert(_table[minorID].isEjecting == false);
                   1845:     assert(_table[minorID].bdevOpen == false);
                   1846:     assert(_table[minorID].cdevOpen == false);
                   1847: 
                   1848:     anchorID = _table[minorID].anchorID;
                   1849: 
                   1850:     // Release the resources retained in the minor slot and zero it.
                   1851: 
                   1852:     devfs_remove(_table[minorID].cdevNode);
                   1853:     devfs_remove(_table[minorID].bdevNode);
                   1854:     IODelete(_table[minorID].name, char, strlen(_table[minorID].name) + 1);
                   1855:     _table[minorID].media->release();              // (release media)
                   1856: 
                   1857:     bzero(&_table[minorID], sizeof(MinorSlot));    // (zero slot)
                   1858: 
                   1859:     // Determine whether the associated anchor ID is marked as obsolete.  If it
                   1860:     // is and there are no other references to the anchor ID in the minor table,
                   1861:     // we remove the anchor ID from the anchor table.
                   1862: 
                   1863:     assert(gIOMediaBSDClient);
                   1864: 
                   1865:     if ( gIOMediaBSDClient->getAnchors()->isObsolete(anchorID) )
                   1866:     {
                   1867:         if ( hasReferencesToAnchorID(anchorID) == false )
                   1868:             gIOMediaBSDClient->getAnchors()->remove(anchorID);
                   1869:     }
                   1870: }
                   1871: 
                   1872: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1873: 
                   1874: UInt32 MinorTable::locate(IOMedia * media)
                   1875: {
                   1876:     //
                   1877:     // This method searches for the specified media in the minor table and
                   1878:     // returns its ID (or kInvalidMinorID on an error).   It ignores slots
                   1879:     // marked as obsolete.
                   1880:     //
                   1881: 
                   1882:     for (UInt32 minorID = 0; minorID < _tableCount; minorID++)
                   1883:     {
                   1884:         if ( _table[minorID].isAssigned != false &&
                   1885:              _table[minorID].isObsolete == false &&
                   1886:              _table[minorID].media      == media )  return minorID;
                   1887:     }
                   1888: 
                   1889:     return kInvalidMinorID;
                   1890: }
                   1891: 
                   1892: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1893: 
                   1894: UInt32 MinorTable::getOpenCountForAnchorID(UInt32 anchorID)
                   1895: {
                   1896:     //
                   1897:     // This method obtains a count of opens on the minors associated with the
                   1898:     // specified anchor ID.  A block device open is counted separately from a
                   1899:     // character device open.
                   1900:     //
                   1901: 
                   1902:     UInt32 opens = 0;
                   1903: 
                   1904:     for ( UInt32 minorID = 0; minorID < _tableCount; minorID++ )
                   1905:     {
                   1906:         if ( _table[minorID].isAssigned != false    &&
                   1907:              _table[minorID].anchorID   == anchorID )
                   1908:         {
                   1909:             opens += (_table[minorID].bdevOpen) ? 1 : 0;
                   1910:             opens += (_table[minorID].cdevOpen) ? 1 : 0;
                   1911:         }
                   1912:     }
                   1913: 
                   1914:     return opens;
                   1915: }
                   1916: 
                   1917: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1918: 
                   1919: IOMedia * MinorTable::getWholeMediaAtAnchorID(UInt32 anchorID)
                   1920: {
                   1921:     //
                   1922:     // This method obtains the whole media associated with the specified anchor
                   1923:     // ID.
                   1924:     //
                   1925: 
                   1926:     for ( UInt32 minorID = 0; minorID < _tableCount; minorID++ )
                   1927:     {
                   1928:         if ( _table[minorID].isAssigned != false    &&
                   1929:              _table[minorID].anchorID   == anchorID &&
                   1930:              _table[minorID].media->isWhole() )  return _table[minorID].media;
                   1931:     }
                   1932: 
                   1933:     return 0;
                   1934: }
                   1935: 
                   1936: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1937: 
                   1938: bool MinorTable::hasReferencesToAnchorID(UInt32 anchorID)
                   1939: {
                   1940:     //
                   1941:     // This method determines whether there are assigned minors in the minor
                   1942:     // table that refer to the specified anchor ID.
                   1943:     //
                   1944: 
                   1945:     for ( UInt32 minorID = 0; minorID < _tableCount; minorID++ )
                   1946:     {
                   1947:         if ( _table[minorID].isAssigned != false    &&
                   1948:              _table[minorID].anchorID   == anchorID )  return true;
                   1949:     }
                   1950: 
                   1951:     return false;
                   1952: }
                   1953: 
                   1954: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1955: 
                   1956: MinorSlot * MinorTable::getMinor(UInt32 minorID)
                   1957: {
                   1958:     //
                   1959:     // Obtain the structure describing the specified minor.
                   1960:     //
                   1961: 
                   1962:     if ( minorID < _tableCount && _table[minorID].isAssigned )
                   1963:         return &_table[minorID];
                   1964:     else
                   1965:         return 0;
                   1966: }
                   1967: 
                   1968: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1969: 
                   1970: void MinorTable::obsolete(UInt32 minorID)
                   1971: {
                   1972:     //
                   1973:     // This method obsoletes the specified minor, that is, the slot is marked
                   1974:     // as obsolete and will be removed later via the dkclose function once it
                   1975:     // detects the last close arrive.  Once obsoleted, the minor can be cons-
                   1976:     // idered to be removed, since it will not appear in locate searches.
                   1977:     //
                   1978: 
                   1979:     assert(minorID < _tableCount);
                   1980:     assert(_table[minorID].isAssigned);
                   1981: 
                   1982:     // Mark the minor as obsolete so that it can be removed from the table as
                   1983:     // soon as the last close arrives (dkclose function's responsibility).
                   1984: 
                   1985:     _table[minorID].isObsolete = true;
                   1986: }
                   1987: 
                   1988: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1989: 
                   1990: bool MinorTable::isObsolete(UInt32 minorID)
                   1991: {
                   1992:     //
                   1993:     // Determine whether the specified minor ID is marked as obsolete.
                   1994:     //
                   1995: 
                   1996:     assert(minorID < _tableCount);
                   1997:     assert(_table[minorID].isAssigned);
                   1998: 
                   1999:     return _table[minorID].isObsolete ? true : false;
                   2000: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.