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; }
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); }
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; }
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; }