AppleRAID * AppleRAIDGlobals::getController(void)
{
    lock();

    if (!raidController) {

	IOLog1("AppleRAIDGlobals::getController - creating AppleRAID\n");
	assert(raidControllerReferences == 0);

	// XXX - move all this to AppleRAID class, same for releaseController
	raidController = new AppleRAID;
	if (raidController) {
	    
	    raidController->init();

	    const OSSymbol * userClient = OSSymbol::withCStringNoCopy("AppleRAIDUserClient");
	    if (userClient) {
		raidController->setProperty(gIOUserClientClassKey, (OSObject *)userClient);
		userClient->release();
	    }
	    raidController->attach(IOService::getResourceService());
	    raidController->registerService();
	}
    }
    
    if (raidControllerReferences++) raidController->retain();

    unlock();

    return raidController;
}
AppleLVMLogicalExtent * AppleLVMVolume::addExtent(AppleLVMGroup * lvg, AppleRAIDExtentOnDisk * extentOnDisk)
{
    AppleLVMLogicalExtent ** extent = &lvExtent[0];
    AppleLVMLogicalExtent * extentInCore = new AppleLVMLogicalExtent;
    UInt64 volumeOffset = 0;

    // find end of list
    while (*extent) {
	volumeOffset += (*extent)->lvExtentSize;
	extent = &((*extent)->skip[0]);
    }

    // XXX hm, there is no range checking here

    extentInCore->skip[0] = 0;
    extentInCore->lvgNext = 0;

    extentInCore->lvMemberIndex = lvg->getMemberIndexFromOffset(extentOnDisk->extentByteOffset);

    extentInCore->lvExtentVolumeOffset = volumeOffset;
    extentInCore->lvExtentGroupOffset = extentOnDisk->extentByteOffset;
    extentInCore->lvExtentMemberOffset = extentOnDisk->extentByteOffset - lvg->getMemberStartingOffset(extentInCore->lvMemberIndex);

    extentInCore->lvExtentSize = extentOnDisk->extentByteCount;

    *extent = extentInCore;
    lvCalculatedSize = volumeOffset + extentInCore->lvExtentSize;
    
    IOLog1("AppleLVMVolume::addExtent() successful, offset = %llu, size = %llu totalSize = %llu\n",   // XXX <<<<<<<< log2
	   extentInCore->lvExtentVolumeOffset, extentInCore->lvExtentSize, lvCalculatedSize);

    return extentInCore;
}
bool AppleRAIDMirrorSet::publishSet(void)
{
    if (arExpectingLiveAdd) {
        IOLog1("AppleRAIDMirror::publishSet() publish ignored.\n");
        return false;
    }

    return super::publishSet();
}
bool AppleLVMVolume::initWithHeader(OSDictionary * props)
{
    IOLog1("AppleLVMVolume::initWithHeader() entered\n");

    if (lvProps) lvProps->release();
    lvProps = props;
    lvProps->retain();

    if (!getVolumeUUID()) return false;
    if (!getGroupUUID()) return false;
    
    OSNumber * number;
    number = OSDynamicCast(OSNumber, lvProps->getObject(kAppleLVMVolumeSequenceKey));
    if (!number) return false;
    lvSequenceNumber = number->unsigned32BitValue();

    number = OSDynamicCast(OSNumber, lvProps->getObject(kAppleLVMVolumeExtentCountKey));
    if (!number) return false;
    lvExtentCount = number->unsigned64BitValue();
    
    number = OSDynamicCast(OSNumber, lvProps->getObject(kAppleLVMVolumeSizeKey));
    if (!number) return false;
    lvClaimedSize = number->unsigned64BitValue();

    OSString * type = OSDynamicCast(OSString, lvProps->getObject(kAppleLVMVolumeTypeKey));
    if (!type) return false;
    if (type->isEqualTo(kAppleLVMVolumeTypeConcat)) lvTypeID = kLVMTypeConcat;
    if (type->isEqualTo(kAppleLVMVolumeTypeBitMap)) lvTypeID = kLVMTypeBitMap;
    if (type->isEqualTo(kAppleLVMVolumeTypeSnapRO)) lvTypeID = kLVMTypeSnapRO;
    if (type->isEqualTo(kAppleLVMVolumeTypeSnapRW)) lvTypeID = kLVMTypeSnapRW;
    if (type->isEqualTo(kAppleLVMVolumeTypeMaster)) lvTypeID = kLVMTypeMaster;
    if (!lvTypeID) return false;

    lvSnapShot = NULL;  // just clear these, they might not exist yet.
    lvBitMap = NULL;
    lvParent = NULL;

    IOLog1("AppleLVMVolume::initWithHeader() successful for %s, size = %llu extent count = %llu\n",
	   getVolumeUUIDString(), lvClaimedSize, lvExtentCount);
    
    return true;
}
AppleRAIDGlobals::~AppleRAIDGlobals()
{
    IOLog1("AppleRAIDGlobals::~AppleRAIDGlobals called.\n");

    assert(raidControllerReferences == 0);
    
    if (raidGlobalLock) {
        IORecursiveLockFree(raidGlobalLock);
        raidGlobalLock = 0;
    }
}
bool AppleRAIDMirrorSet::startSet(void)
{
    IOLog1("AppleRAIDMirrorSet::startSet() - parallel read request max %lld bytes.\n", getSmallestMaxByteCount());
    arMaxReadRequestFactor = getSmallestMaxByteCount() / arSetBlockSize;

    if (super::startSet() == false) return false;

    if (getSetState() == kAppleRAIDSetStateDegraded) {

        if (getSpareCount()) rebuildStart();

    } else {
        // clear the timeout once the set is complete
        arSetCompleteTimeout = kARSetCompleteTimeoutNone;
    }

    return true;
}
bool AppleRAIDMirrorSet::init()
{
    IOLog1("AppleRAIDMirrorSet::init() called\n");

    if (super::init() == false) return false;

    arRebuildThreadCall = 0;
    arSetCompleteThreadCall = 0;
    arExpectingLiveAdd = 0;
    arMaxReadRequestFactor = 32;	// with the default 32KB blocksize -> 1 MB

    queue_init(&arFailedRequestQueue);

    setProperty(kAppleRAIDLevelNameKey, kAppleRAIDLevelNameMirror);

    arAllocateRequestMethod = OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::allocateRAIDRequest);

    return true;
}
AppleRAIDSet * AppleRAIDMirrorSet::createRAIDSet(AppleRAIDMember * firstMember)
{
    AppleRAIDMirrorSet *raidSet = new AppleRAIDMirrorSet;

    IOLog1("AppleRAIDMirrorSet::createRAIDSet(%p) called, new set = %p  *********\n", firstMember, raidSet);

    while (raidSet) {

        if (!raidSet->init()) break;
        if (!raidSet->initWithHeader(firstMember->getHeader(), true)) break;
        if (raidSet->resizeSet(raidSet->getMemberCount())) return raidSet;

        break;
    }

    if (raidSet) raidSet->release();

    return 0;
}
Exemple #9
0
bool AppleLVMGroup::removeMember(AppleRAIDMember * member, IOOptionBits options)
{
    UInt32 memberIndex = member->getMemberIndex();
    UInt64 memberBlockCount = arMemberBlockCounts[memberIndex];

    IOLog1("AppleLVMGroup::removeMember(%p) called for index %d block count %lld\n",
	   member, (int)memberIndex, memberBlockCount);

    // XXX
    //               tbd
    // XXX
    
    // remove this member's blocks from the total block count
    arSetBlockCount -= memberBlockCount;
    arSetMediaSize = arSetBlockCount * arSetBlockSize;

    if (arMetaDataVolumes[memberIndex]) arMetaDataVolumes[memberIndex]->release();
    arMetaDataVolumes[memberIndex] = 0;
	
    return super::removeMember(member, options);
}
Exemple #10
0
AppleRAIDSet * AppleLVMGroup::createRAIDSet(AppleRAIDMember * firstMember)
{
    AppleLVMGroup *raidSet = new AppleLVMGroup;

    AppleLVGTOCEntrySanityCheck();	// debug only
    AppleLVMVolumeOnDiskSanityCheck();	// debug only

    IOLog1("AppleLVMGroup::createRAIDSet(%p) called, new set = %p  *********\n", firstMember, raidSet);

    while (raidSet){

	if (!raidSet->init()) break;
	if (!raidSet->initWithHeader(firstMember->getHeader(), true)) break;
	if (raidSet->resizeSet(raidSet->getMemberCount())) return raidSet;

	break;
    }

    if (raidSet) raidSet->release();
    
    return 0;
}    
bool AppleLVMVolume::addExtents(AppleLVMGroup * lvg, AppleLVMVolumeOnDisk * lve)
{

    // XXX failure cases need to mark lv as broken
    
    AppleRAIDExtentOnDisk * extent = (AppleRAIDExtentOnDisk *)((char *)lve + lve->lvExtentsStart);
    if ((void *)(extent + lvExtentCount) > (void *)((char *)lve + lve->lvHeaderSize - sizeof(AppleRAIDExtentOnDisk))) {
	IOLog("AppleLVMVolume::addExtents() too many extents detected for logical volume \"%s\"\n", getVolumeUUIDString());
	return false;
    }
	
    UInt64 count = lvExtentCount;
    while (count) {
	AppleLVMLogicalExtent * newExtent = addExtent(lvg, extent);
	if (!newExtent) {
	    IOLog("AppleLVMVolume::addExtents() overlapping extent detected in logical volume \"%s\"\n", getVolumeUUIDString());
	    return false;
	}
	if (!lvg->addExtentToLVG(newExtent)) {
	    IOLog("AppleLVMVolume::addExtents() overlapping logical volumes detected for logical volume \"%s\"\n", getVolumeUUIDString());
	    return false;
	}
	count--;
	extent++;
    }

    if (lvClaimedSize != lvCalculatedSize) {
	IOLog("AppleLVMVolume::addExtents() size error for extent list for logical volume \"%s\"\n", getVolumeUUIDString());
	IOLog("AppleLVMVolume::addExtents() expected size %llu, calculated size %llu\n", lvClaimedSize, lvCalculatedSize);
	return false;
    }
    
    IOLog1("AppleLVMVolume::addExtents() successful for %s, extent count = %llu, size = %llu\n",
	   getVolumeUUIDString(), lvExtentCount, lvCalculatedSize);

    return true;
}
Exemple #12
0
bool AppleLVMGroup::init()
{
    IOLog1("AppleLVMGroup::init() called\n");
            
    if (super::init() == false) return false;

    arMemberBlockCounts = 0;
    arMemberStartingOffset = 0;
    arExpectingLiveAdd = 0;
    arPrimaryNeedsUpdate = false;
    arPrimaryBuffer = NULL;
    arLogicalVolumeCount = 0;
    arLogicalVolumeActiveCount = 0;
    arLogicalVolumes = NULL;
    arMetaDataVolumes = 0;
    arExtentCount = 0;
    arExtents = NULL;
	
    setProperty(kAppleRAIDLevelNameKey, kAppleRAIDLevelNameLVG);

    arAllocateRequestMethod = OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::allocateRAIDRequest);
    
    return true;
}
void AppleRAIDMirrorSet::completeRAIDRequest(AppleRAIDStorageRequest *storageRequest)
{
    UInt32		cnt;
    UInt64              byteCount;
    UInt64              expectedByteCount;
    IOReturn            status;
    bool		isWrite;

    isWrite = (storageRequest->srMemoryDescriptorDirection == kIODirectionOut);
    byteCount = 0;
    expectedByteCount = isWrite ? storageRequest->srByteCount * storageRequest->srActiveCount : storageRequest->srByteCount;
    status = kIOReturnSuccess;

    // Collect the status and byte count for each member.
    for (cnt = 0; cnt < arMemberCount; cnt++) {

        // Ignore missing members.
        if (arMembers[cnt] == 0) continue;

        // rebuilding members
        if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateRebuilding) {

            if (!isWrite) {
                assert(storageRequest->srRequestByteCounts[cnt] == 0);
                continue;
            }

            if (storageRequest->srRequestStatus[cnt] != kIOReturnSuccess ||
                    storageRequest->srRequestByteCounts[cnt] != storageRequest->srByteCount) {

                // This will terminate the rebuild thread
                arMembers[cnt]->changeMemberState(kAppleRAIDMemberStateBroken);
                IOLog("AppleRAID::completeRAIDRequest - write error 0x%x detected during rebuild for set \"%s\" (%s) on member %s, set byte offset = %llu.\n",
                      storageRequest->srRequestStatus[cnt], getSetNameString(), getUUIDString(),
                      arMembers[cnt]->getUUIDString(), storageRequest->srByteStart);
            }
            continue;
        }

        // offline members
        if (arMembers[cnt]->getMemberState() != kAppleRAIDMemberStateOpen) {
            IOLogRW("AppleRAIDMirrorSet::completeRAIDRequest - [%u] tbc 0x%llx, sbc 0x%llx bc 0x%llx, member %p, member state %u\n",
                    (uint32_t)cnt, storageRequest->srByteCount, storageRequest->srRequestByteCounts[cnt],
                    byteCount, arMembers[cnt], (uint32_t)arMembers[cnt]->getMemberState());

            status = kIOReturnIOError;

            continue;
        }

        // failing members
        if (storageRequest->srRequestStatus[cnt] != kIOReturnSuccess) {
            IOLog("AppleRAID::completeRAIDRequest - error 0x%x detected for set \"%s\" (%s), member %s, set byte offset = %llu.\n",
                  storageRequest->srRequestStatus[cnt], getSetNameString(), getUUIDString(),
                  arMembers[cnt]->getUUIDString(), storageRequest->srByteStart);

            status = storageRequest->srRequestStatus[cnt];

            // mark this member to be removed
            arMembers[cnt]->changeMemberState(kAppleRAIDMemberStateClosing);
            continue;
        }

        byteCount += storageRequest->srRequestByteCounts[cnt];

        IOLogRW("AppleRAIDMirrorSet::completeRAIDRequest - [%u] tbc 0x%llx, sbc 0x%llx bc 0x%llx, member %p\n",
                (uint32_t)cnt, storageRequest->srByteCount, storageRequest->srRequestByteCounts[cnt],
                byteCount, arMembers[cnt]);
    }

    // Return an underrun error if the byte count is not complete.
    // dkreadwrite should clip any requests beyond our published size
    // however we still see underruns with pulled disks (bug?)

    if (status == kIOReturnSuccess) {

        if (byteCount != expectedByteCount) {
            IOLog("AppleRAID::completeRAIDRequest - underrun detected on set = \"%s\" (%s)\n", getSetNameString(), getUUIDString());
            IOLog1("AppleRAID::completeRAIDRequest - total expected = 0x%llx (0x%llx), actual = 0x%llx\n",
                   expectedByteCount, storageRequest->srByteCount, byteCount);
            status = kIOReturnUnderrun;
            byteCount = 0;

        } else {

            // fix up write byte count
            byteCount = storageRequest->srByteCount;
        }

    } else {

        IOLog1("AppleRAID::completeRAIDRequest - error detected\n");

        UInt32 stillAliveCount = 0;

        for (cnt = 0; cnt < arMemberCount; cnt++) {

            if (arMembers[cnt] == 0) continue;

            if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateOpen) {
                stillAliveCount++;
            }
        }

        // if we haven't lost the entire set, retry the failed requests
        if (stillAliveCount) {

            bool recoveryActive = queue_empty(&arFailedRequestQueue) != true;

            arStorageRequestsPending--;
            queue_enter(&arFailedRequestQueue, storageRequest, AppleRAIDStorageRequest *, fCommandChain);
            arSetCommandGate->commandWakeup(&arStorageRequestPool, /* oneThread */ false);

            // kick off the recovery thread if it isn't already active
            if (!recoveryActive) {
                recoverStart();
            }

            return;

        } else {

            // or let the recovery thread finish off the set
            recoverStart();
        }

        byteCount = 0;
    }
AppleRAIDGlobals::AppleRAIDGlobals()
{
    IOLog1("AppleRAIDGlobals() initing\n");
    raidGlobalLock = IORecursiveLockAlloc();
    raidControllerReferences = 0;
}