#include "AppleRAID.h"
#define super IOService
OSDefineMetaClassAndStructors(AppleRAID, IOService);
bool AppleRAID::init()
{
if (super::init() == false) return false;
raidSets = OSDictionary::withCapacity(0x10);
raidMembers = OSDictionary::withCapacity(0x10);
logicalVolumes = OSDictionary::withCapacity(0x10);
return (raidSets && raidMembers && logicalVolumes);
}
void AppleRAID::free()
{
if (raidSets) {
raidSets->release();
raidSets = 0;
}
if (raidMembers) {
raidMembers->release();
raidMembers = 0;
}
if (logicalVolumes) {
logicalVolumes->release();
logicalVolumes = 0;
}
super::free();
}
void AppleRAID::addSet(AppleRAIDSet *set)
{
const OSString * uuid = set->getUUID();
if (uuid) {
raidSets->setObject(uuid, set);
}
}
void AppleRAID::removeSet(AppleRAIDSet * set)
{
const OSString * uuid = set->getUUID();
if (uuid) {
raidSets->removeObject(uuid);
}
}
AppleRAIDSet * AppleRAID::findSet(const OSString *uuid)
{
return OSDynamicCast(AppleRAIDSet, raidSets->getObject(uuid));
}
AppleRAIDSet * AppleRAID::findSet(AppleRAIDMember * member)
{
const OSString * setUUID = member->getSetUUID();
if (setUUID == 0) return 0;
return OSDynamicCast(AppleRAIDSet, raidSets->getObject(setUUID));
}
void AppleRAID::addMember(AppleRAIDMember *member)
{
const OSString * uuid = member->getUUID();
if (uuid) {
raidMembers->setObject(uuid, member);
}
}
void AppleRAID::removeMember(AppleRAIDMember * member)
{
const OSString * uuid = member->getUUID();
if (uuid) {
raidMembers->removeObject(uuid);
}
}
AppleRAIDMember * AppleRAID::findMember(const OSString *uuid)
{
return OSDynamicCast(AppleRAIDMember, raidMembers->getObject(uuid));
}
void AppleRAID::addLogicalVolume(AppleLVMVolume *volume)
{
const OSString * uuid = volume->getVolumeUUID();
if (uuid) {
logicalVolumes->setObject(uuid, volume);
}
}
void AppleRAID::removeLogicalVolume(AppleLVMVolume * volume)
{
const OSString * uuid = volume->getVolumeUUID();
if (uuid) {
logicalVolumes->removeObject(uuid);
}
}
AppleLVMVolume * AppleRAID::findLogicalVolume(const OSString *uuid)
{
return OSDynamicCast(AppleLVMVolume, logicalVolumes->getObject(uuid));
}
IOReturn AppleRAID::newMember(IORegistryEntry * child)
{
AppleRAIDMember * member = OSDynamicCast(AppleRAIDMember, child);
gAppleRAIDGlobals.lock();
IOLog1("AppleRAID::newMember(%p) entered.\n", child);
while (1) {
if (member == 0) break;
const OSString * memberUUID = member->getUUID();
if (memberUUID == 0) break;
if (findMember(memberUUID)) {
IOLog("AppleRAID::newMember detected duplicate member %s in set \"%s\" (%s).\n",
member->getUUIDString(), member->getSetNameString(), member->getSetUUIDString());
break;
}
addMember(member);
const OSString * setUUID = member->getSetUUID();
if (setUUID == 0) {
IOLog("AppleRAID::newMember member %s in set \"%s\" has a corrupted header (no set UUID).\n",
member->getUUIDString(), member->getSetNameString());
break;
}
AppleRAIDSet * set = findSet(setUUID);
bool firstTime = set == 0;
if (!set) {
OSString * raidLevel = OSDynamicCast(OSString, member->getHeaderProperty(kAppleRAIDLevelNameKey));
if (!raidLevel) {
IOLog("AppleRAID::newMember member %s in set \"%s\" (%s) has a corrupted header (no RAID level).\n",
member->getUUIDString(), member->getSetNameString(), member->getSetUUIDString());
break;
}
IOLog1("AppleRAID::newMember(%p) new raid set, level = %s.\n", child, raidLevel->getCStringNoCopy());
if (raidLevel->isEqualTo(kAppleRAIDLevelNameConcat)) {
set = AppleRAIDConcatSet::createRAIDSet(member);
} else
if (raidLevel->isEqualTo(kAppleRAIDLevelNameMirror)) {
set = AppleRAIDMirrorSet::createRAIDSet(member);
} else
if (raidLevel->isEqualTo(kAppleRAIDLevelNameStripe)) {
set = AppleRAIDStripeSet::createRAIDSet(member);
} else
if (raidLevel->isEqualTo(kAppleRAIDLevelNameLVG)) {
set = AppleLVMGroup::createRAIDSet(member);
}
if (set) {
IOLog1("AppleRAID::newMember(%p) raid set \"%s\" (%s) successfully created.\n",
child, set->getSetNameString(), set->getUUIDString());
addSet(set);
set->release();
} else {
IOLog("AppleRAID::newMember unknown raid level %s.\n", raidLevel->getCStringNoCopy());
}
}
if (!set) break;
if (set->isPaused() && !set->isSetComplete()) {
if (set->upgradeMember(member)) {
restartSet(set, true);
IOLog1("AppleRAID::newMember(%p) was successful (live add).\n", child);
gAppleRAIDGlobals.unlock();
return kIOReturnSuccess;
}
break;
}
if (!set->addMember(member)) {
if (!set->addSpare(member)) {
IOLog("AppleRAID::newMember was unable to add member %s to set \"%s\" (%s).\n",
member->getUUIDString(), set->getSetNameString(), set->getUUIDString());
break;
}
}
startSet(set);
if (firstTime) set->registerService();
IOLog1("AppleRAID::newMember(%p) was successful.\n", child);
gAppleRAIDGlobals.unlock();
return kIOReturnSuccess;
}
IOLog1("AppleRAID::newMember(%p) failed.\n", child);
if (member) removeMember(member);
gAppleRAIDGlobals.unlock();
return kIOReturnUnformattedMedia;
}
IOReturn AppleRAID::oldMember(IORegistryEntry * child)
{
IOLog1("AppleRAID::oldMember(%p) entered.\n", child);
gAppleRAIDGlobals.lock();
while (1) {
AppleRAIDMember * member = OSDynamicCast(AppleRAIDMember, child);
if (member == 0) break;
const OSString * memberUUID = member->getUUID();
if (!memberUUID || findMember(memberUUID) != member) break;
AppleRAIDSet * set = findSet(member);
if (!set) break;
set->retain();
removeMember(member);
set->removeMember(member, 0);
if ((set->getActiveCount() == 0) && (set->getSpareCount() == 0)) {
if (set->isRAIDMember()) {
oldMember(set);
}
IOLog1("AppleRAID::oldMember(%p) terminating parent raid set %p.\n", child, set);
removeSet(set);
} else {
set->release();
set = NULL;
}
gAppleRAIDGlobals.unlock();
if (set) {
IOLog("AppleRAID: terminating set \"%s\" (%s).\n", set->getSetNameString(), set->getUUIDString());
set->terminate();
set->release();
}
IOLog1("AppleRAID::oldMember(%p) was successful.\n", child);
return kIOReturnSuccess;
}
IOLog1("AppleRAID::oldMember(%p) lookup failed.\n", child);
gAppleRAIDGlobals.unlock();
return kIOReturnError;
}
void AppleRAID::recoverMember(IORegistryEntry * child)
{
IOLog1("AppleRAID::recoverMember(%p) entered.\n", child);
AppleRAIDMember * member = OSDynamicCast(AppleRAIDMember, child);
if (member) {
AppleRAIDSet * set = findSet(member);
if (set) set->arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, set, &AppleRAIDSet::recoverStart));
}
}
void AppleRAID::startSet(AppleRAIDSet * set)
{
IOLog1("AppleRAID::startSet(%p) entered.\n", set);
assert(gAppleRAIDGlobals.islocked());
assert(!set->isPaused());
if (set->startSet()) {
IOLog1("AppleRAID::startSet: the set %p is started.\n", set);
if (!set->isRAIDMember()) set->start(NULL);
}
(void)set->publishSet();
return;
}
void AppleRAID::degradeSet(AppleRAIDSet *set)
{
gAppleRAIDGlobals.lock();
const OSString * setUUID = set->getUUID();
if ((set == findSet(setUUID)) && (set->getSetState() == kAppleRAIDSetStateInitializing)) {
assert(!set->isPaused());
IOLog("AppleRAID::degradeSet - starting the set \"%s\" (%s).\n",
set->getSetNameString(), set->getUUIDString());
if (set->startSet()) {
IOLog1("AppleRAID::degradeSet: the set %p is started.\n", set);
if (!set->isRAIDMember()) set->start(NULL);
}
if (set->getSetState() == kAppleRAIDSetStateDegraded) {
set->bumpSequenceNumber();
set->writeRAIDHeader();
}
(void)set->publishSet();
}
gAppleRAIDGlobals.unlock();
}
void AppleRAID::restartSet(AppleRAIDSet *set, bool bump)
{
IOLog1("AppleRAID::restartSet(%p) entered.\n", set);
gAppleRAIDGlobals.lock();
IOLog("AppleRAID::restartSet - restarting set \"%s\" (%s).\n", set->getSetNameString(), set->getUUIDString());
(void)set->startSet();
if (bump) {
set->bumpSequenceNumber();
(void)set->writeRAIDHeader();
}
(void)set->publishSet();
gAppleRAIDGlobals.unlock();
}
IOReturn AppleRAID::updateSet(char * setInfoBuffer, uint32_t setInfoBufferSize, char * retBuffer, uint32_t * retBufferSize)
{
IOReturn rc = kIOReturnSuccess;
IOLog1("AppleRAID::updateSet() entered\n");
if (!isOpen()) return kIOReturnNotOpen;
if (!setInfoBuffer || !setInfoBufferSize) return kIOReturnBadArgument;
if (!retBuffer || !retBufferSize) return kIOReturnBadArgument;
gAppleRAIDGlobals.lock();
while (1) {
OSString * errmsg = 0;
OSDictionary * updateInfo = OSDynamicCast(OSDictionary, OSUnserializeXML(setInfoBuffer, &errmsg));
if (!updateInfo) {
if (errmsg) {
IOLog("AppleRAID::updateSet - header parsing failed with %s\n", errmsg->getCStringNoCopy());
errmsg->release();
}
rc = kIOReturnBadArgument;
break;
}
const OSString * setUUIDString = OSDynamicCast(OSString, updateInfo->getObject(kAppleRAIDSetUUIDKey));
AppleRAIDSet * set = findSet(setUUIDString);
if (!set) { rc = kIOReturnBadArgument; break; };
updateInfo->removeObject(kAppleRAIDSetUUIDKey);
OSNumber * number = OSDynamicCast(OSNumber, updateInfo->getObject(kAppleRAIDSequenceNumberKey));
if (!number) { rc = kIOReturnBadArgument; break; };
UInt32 seqNum = number->unsigned32BitValue();
if (seqNum && seqNum != set->getSequenceNumber()) { rc = kIOReturnBadMessageID; break; };
updateInfo->removeObject(kAppleRAIDSequenceNumberKey);
number = OSDynamicCast(OSNumber, updateInfo->getObject("_update command_"));
if (number) {
UInt32 subcommand = number->unsigned32BitValue();
IOLog1("AppleRAID::updateSet() executing subcommand %d\n", (int)subcommand);
switch (subcommand) {
case kAppleRAIDUpdateResetSet:
startSet(set); break;
case kAppleRAIDUpdateDestroySet:
if (set->unpublishSet()) {
if (!set->destroySet()) {
rc = kIOReturnError;
}
}
break;
default:
IOLog("AppleRAID::updateSet() unknown subcommand %d\n", (int)subcommand);
}
}
updateInfo->removeObject("_update command_");
if (updateInfo->getCount()) {
AppleRAIDSet * parentSet = 0;
if (set->isRAIDMember()) {
parentSet = findSet((AppleRAIDMember *)set);
IOLog1("AppleRAID::updateSet() pausing parent set %p.\n", parentSet);
IOCommandGate::Action pauseSetMethod = OSMemberFunctionCast(IOCommandGate::Action, parentSet, &AppleRAIDSet::pauseSet);
if (parentSet) parentSet->arSetCommandGate->runAction(pauseSetMethod, (void *)false);
}
IOLog1("AppleRAID::updateSet() pausing set %p.\n", set);
IOCommandGate::Action pauseSetMethod = OSMemberFunctionCast(IOCommandGate::Action, set, &AppleRAIDSet::pauseSet);
set->arSetCommandGate->runAction(pauseSetMethod, (void *)false);
if (!set->reconfigureSet(updateInfo)) rc = kIOReturnError;
restartSet(set, true);
IOLog1("AppleRAID::updateSet() unpausing set.\n");
set->arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, set, &AppleRAIDSet::unpauseSet));
if (parentSet) parentSet->arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, parentSet, &AppleRAIDSet::unpauseSet));
}
*(UInt32 *)retBuffer = set->getSequenceNumber(); *retBufferSize = sizeof(UInt32);
updateInfo->release();
IOLog1("AppleRAID::updateSet() was %ssuccessful.\n", rc ? "un" : "");
break;
}
gAppleRAIDGlobals.unlock();
return rc;
}
IOReturn AppleRAID::getListOfSets(UInt32 inFlags, char * outList, uint32_t * outListSize)
{
OSCollectionIterator * iter = 0;
OSArray * keys = 0;
OSSerialize * s = 0;
IOReturn rc = kIOReturnError;
IOLog1("AppleRAID::getListOfSets() entered\n");
if (!isOpen()) return kIOReturnNotOpen;
if (!inFlags || !outList || !outListSize) return kIOReturnBadArgument;
outList[0] = 0;
gAppleRAIDGlobals.lock();
unsigned int keyCount = raidSets->getCount();
while (keyCount) {
keys = OSArray::withCapacity(keyCount);
if (!keys) break;
iter = OSCollectionIterator::withCollection(raidSets);
if (!iter) break;
while (const OSString * setName = OSDynamicCast(OSString, iter->getNextObject())) {
AppleRAIDSet * set = findSet(setName);
if (!set) continue;
bool addToList = false;
if (inFlags && kAppleRAIDState) {
UInt32 state = set->getSetState();
addToList = (((state < kAppleRAIDSetStateOnline) && (inFlags & kAppleRAIDOfflineSets)) ||
((state == kAppleRAIDSetStateOnline) && (inFlags & kAppleRAIDOnlineSets)) ||
((state == kAppleRAIDSetStateDegraded) && (inFlags & kAppleRAIDDegradedSets)));
}
if (inFlags && kAppleRAIDVisibility) {
bool visible = !set->isRAIDMember();
addToList = visible ? (inFlags & kAppleRAIDVisibleSets) : (inFlags & kAppleRAIDInternalSets);
}
if (addToList) (void)keys->setObject(setName);
}
s = OSSerialize::withCapacity(keys->getCount() * 128);
if (!s) break;
s->clearText();
if (!keys->serialize(s)) break;
if (*outListSize < s->getLength()) {
IOLog("AppleRAID::getListOfSets() return buffer too small, need %d bytes, received %d.\n",
(int)s->getLength(), (int)*outListSize);
rc = kIOReturnNoSpace;
break;
}
*outListSize = s->getLength();
bcopy(s->text(), outList, *outListSize);
rc = kIOReturnSuccess;
break;
}
if (iter) iter->release();
if (keys) keys->release();
if (s) s->release();
if (keyCount == 0) rc = kIOReturnNoDevice;
if (rc) *outListSize = 0;
gAppleRAIDGlobals.unlock();
return rc;
}
IOReturn AppleRAID::getSetProperties(char * setString, uint32_t setStringSize, char * outProp, uint32_t * outPropSize)
{
IOReturn rc = kIOReturnError;
const OSString * setName = 0;
AppleRAIDSet * set = 0;
OSDictionary * props = 0;
OSSerialize * s = 0;
IOLog1("AppleRAID::getSetProperties(%s) entered\n", setString);
if (!isOpen()) return kIOReturnNotOpen;
if (!setString || !outProp || !outPropSize) return kIOReturnBadArgument;
outProp[0] = 0;
gAppleRAIDGlobals.lock();
while (1) {
setName = OSString::withCString(setString);
if (!setName) break;
set = findSet(setName);
if (!set) break;
IOLog1("setName = %s (%p)\n", setString, set);
props = set->getSetProperties();
if (!props) break;
s = OSSerialize::withCapacity(512);
if (!s) break;
s->clearText();
if (!props->serialize(s)) break;
if (*outPropSize < s->getLength()) {
IOLog("AppleRAID::getSetProperties() return buffer too small, need %d bytes, received %d.\n",
(int)s->getLength(), (int)*outPropSize);
rc = kIOReturnNoSpace;
break;
}
*outPropSize = s->getLength();
bcopy(s->text(), outProp, *outPropSize);
rc = kIOReturnSuccess;
break;
}
if (setName) setName->release();
if (props) props->release();
if (s) s->release();
if (rc) *outPropSize = 0;
gAppleRAIDGlobals.unlock();
return rc;
}
IOReturn AppleRAID::getMemberProperties(char * memberString, uint32_t memberStringSize, char * outProp, uint32_t * outPropSize)
{
IOReturn rc = kIOReturnError;
const OSString * memberName = 0;
AppleRAIDMember * member = 0;
OSDictionary * props = 0;
OSSerialize * s = 0;
IOLog2("AppleRAID::getMemberProperties(%s) entered\n", memberString);
if (!isOpen()) return kIOReturnNotOpen;
if (!memberString || !outProp || !outPropSize) return kIOReturnBadArgument;
outProp[0] = 0;
gAppleRAIDGlobals.lock();
while (1) {
memberName = OSString::withCString(memberString);
if (!memberName) break;
member = findMember(memberName);
if (!member) break;
IOLog1("memberName = %s (%p)\n", memberString, member);
props = member->getMemberProperties();
if (!props) break;
s = OSSerialize::withCapacity(512);
if (!s) break;
s->clearText();
if (!props->serialize(s)) break;
if (*outPropSize < s->getLength()) {
IOLog("AppleRAID::getMemberProperties() return buffer too small, need %d bytes, received %d.\n",
(int)s->getLength(), (int)*outPropSize);
rc = kIOReturnNoSpace;
break;
}
*outPropSize = s->getLength();
bcopy(s->text(), outProp, *outPropSize);
rc = kIOReturnSuccess;
break;
}
if (memberName) memberName->release();
if (props) props->release();
if (s) s->release();
if (rc) *outPropSize = 0;
gAppleRAIDGlobals.unlock();
return rc;
}
IOReturn AppleRAID::getVolumesForGroup(char * lvgString, uint32_t lvgStringSize, char * arrayString, uint32_t * outArraySize)
{
IOReturn rc = kIOReturnError;
const OSString * lvgName = 0;
AppleLVMGroup * lvg = 0;
const OSString * memberName = 0;
AppleRAIDMember * member = 0;
OSArray * array = 0;
OSSerialize * s = 0;
IOLog1("AppleRAID::getVolumesForGroup(%s) for member %s entered\n",
lvgString, lvgString[kAppleRAIDMaxUUIDStringSize] ? &lvgString[kAppleRAIDMaxUUIDStringSize] : "<all>");
if (!isOpen()) return kIOReturnNotOpen;
if (!lvgString || !arrayString || !outArraySize) return kIOReturnBadArgument;
arrayString[0] = 0;
gAppleRAIDGlobals.lock();
while (1) {
lvgName = OSString::withCString(lvgString);
if (!lvgName) break;
lvg = OSDynamicCast(AppleLVMGroup, findSet(lvgName));
if (!lvg) break;
if (lvgString[kAppleRAIDMaxUUIDStringSize]) {
memberName = OSString::withCString(&lvgString[kAppleRAIDMaxUUIDStringSize]);
if (!memberName) break;
member = findMember(memberName);
if (!member) break;
}
array = lvg->buildLogicalVolumeListFromTOC(member);
if (!array) break;
s = OSSerialize::withCapacity(512);
if (!s) break;
s->clearText();
if (!array->serialize(s)) break;
if (*outArraySize < s->getLength()) {
IOLog("AppleRAID::getVolumeForGroup() return buffer too small, need %d bytes, received %d.\n",
(int)s->getLength(), (int)*outArraySize);
rc = kIOReturnNoSpace;
break;
}
IOLog2("AppleRAID::getVolumesForGroup() size = %u array = %s\n", s->getLength(), s->text());
*outArraySize = s->getLength();
bcopy(s->text(), arrayString, *outArraySize);
rc = kIOReturnSuccess;
break;
}
if (lvgName) lvgName->release();
if (memberName) memberName->release();
if (array) array->release();
if (s) s->release();
if (rc) *outArraySize = 0;
gAppleRAIDGlobals.unlock();
return rc;
}
IOReturn AppleRAID::getVolumeProperties(char * lvString, uint32_t lvStringSize, char * outProp, uint32_t * outPropSize)
{
IOReturn rc = kIOReturnError;
const OSString * lvName = 0;
AppleLVMVolume * lv = 0;
OSDictionary * props = 0;
OSSerialize * s = 0;
IOLog1("AppleRAID::getVolumeProperties(%s) entered\n", lvString);
if (!isOpen()) return kIOReturnNotOpen;
if (!lvString || !outProp || !outPropSize) return kIOReturnBadArgument;
outProp[0] = 0;
gAppleRAIDGlobals.lock();
while (1) {
lvName = OSString::withCString(lvString);
if (!lvName) break;
lv = findLogicalVolume(lvName);
if (!lv) break;
props = lv->getVolumeProperties();
if (!props) break;
s = OSSerialize::withCapacity(512);
if (!s) break;
s->clearText();
if (!props->serialize(s)) break;
if (*outPropSize < s->getLength()) {
IOLog("AppleRAID::getVolumeProperties() return buffer too small, need %d bytes, received %d.\n",
(int)s->getLength(), (int)*outPropSize);
rc = kIOReturnNoSpace;
break;
}
*outPropSize = s->getLength();
bcopy(s->text(), outProp, *outPropSize);
rc = kIOReturnSuccess;
break;
}
if (lvName) lvName->release();
if (props) props->release();
if (s) s->release();
if (rc) *outPropSize = 0;
gAppleRAIDGlobals.unlock();
return rc;
}
IOReturn AppleRAID::getVolumeExtents(char * lvString, uint32_t lvStringSize, char * extentsBuffer, uint32_t * extentsSize)
{
IOReturn rc = kIOReturnError;
const OSString * lvName = 0;
AppleLVMVolume * lv = 0;
AppleLVMGroup * lvg = 0;
IOLog1("AppleRAID::getVolumeExtents(%s) entered\n", lvString);
if (!isOpen()) return kIOReturnNotOpen;
if (!lvString || !extentsBuffer || !extentsSize) return kIOReturnBadArgument;
gAppleRAIDGlobals.lock();
while (1) {
lvName = OSString::withCString(lvString);
if (!lvName) break;
AppleRAIDExtentOnDisk * extent = (AppleRAIDExtentOnDisk *)extentsBuffer;
lv = findLogicalVolume(lvName);
if (!lv) {
lvg = OSDynamicCast(AppleLVMGroup, findSet(lvName));
if (!lvg) break;
UInt64 extentCount = lvg->getExtentCount();
if (extentCount * sizeof(AppleRAIDExtentOnDisk) > *extentsSize) {
extent->extentByteOffset = extentCount;
extent->extentByteCount = 0;
*extentsSize = sizeof(AppleRAIDExtentOnDisk);
rc = kIOReturnSuccess; } else {
if (lvg->buildExtentList(extent)) {
*extentsSize = extentCount * sizeof(AppleRAIDExtentOnDisk);
rc = kIOReturnSuccess;
}
}
IOLog1("LVG %s (%p) has %llu total extents.\n", lvString, lvg, extentCount);
break;
}
UInt64 extentCount = lv->getExtentCount();
if (extentCount * sizeof(AppleRAIDExtentOnDisk) > *extentsSize) {
extent->extentByteOffset = extentCount;
extent->extentByteCount = 0;
*extentsSize = sizeof(AppleRAIDExtentOnDisk);
rc = kIOReturnSuccess; } else {
if (lv->buildExtentList(extent)) {
*extentsSize = extentCount * sizeof(AppleRAIDExtentOnDisk);
rc = kIOReturnSuccess;
}
}
IOLog1("LV %s (%p) has %llu extents.\n", lvString, lv, extentCount);
break;
}
if (lvName) lvName->release();
if (rc) *extentsSize = 0;
gAppleRAIDGlobals.unlock();
return rc;
}
IOReturn AppleRAID::updateLogicalVolume(char * lveBuffer, uint32_t lveBufferSize, char * retBuffer, uint32_t * retBufferSize)
{
OSDictionary * lvProps = NULL;
IOReturn rc = kIOReturnBadArgument;
IOLog1("AppleRAID::updateLogicalVolume() entered\n");
if (!isOpen()) return kIOReturnNotOpen;
if (!lveBuffer || !lveBufferSize) return kIOReturnBadArgument;
if (!retBuffer || !retBufferSize) return kIOReturnBadArgument;
AppleLVMVolumeOnDisk * lve = (AppleLVMVolumeOnDisk *)lveBuffer;
gAppleRAIDGlobals.lock();
while (1) {
lvProps = AppleLVMVolume::propsFromHeader(lve);
if (!lvProps) break;
const OSString * setUUIDString = OSDynamicCast(OSString, lvProps->getObject(kAppleLVMGroupUUIDKey));
AppleLVMGroup * lvg = OSDynamicCast(AppleLVMGroup, findSet(setUUIDString));
if (!lvg) break;
OSNumber * number = OSDynamicCast(OSNumber, lvProps->getObject(kAppleLVMVolumeSequenceKey));
if (!number) break;
UInt32 seqNum = number->unsigned32BitValue();
if (seqNum && seqNum != lvg->getSequenceNumber()) { rc = kIOReturnBadMessageID; break; };
const OSString * lvUUIDString = OSDynamicCast(OSString, lvProps->getObject(kAppleLVMVolumeUUIDKey));
AppleLVMVolume * lv = OSDynamicCast(AppleLVMVolume, findLogicalVolume(lvUUIDString));
if (lv) {
rc = lvg->updateLogicalVolume(lv, lvProps, lve);
} else {
rc = lvg->createLogicalVolume(lvProps, lve);
}
*(UInt32 *)retBuffer = lvg->getSequenceNumber();
*retBufferSize = sizeof(UInt32);
break;
}
gAppleRAIDGlobals.unlock();
if (lvProps) lvProps->release();
IOLog1("AppleRAID::updateLogicalVolume() was %ssuccessful.\n", rc ? "un" : "");
return rc;
}
IOReturn AppleRAID::destroyLogicalVolume(char * lvString, uint32_t lvStringSize, char * retBuffer, uint32_t * retBufferSize)
{
IOReturn rc = kIOReturnBadArgument;
IOLog1("AppleRAID::destroyLogicalVolume() entered\n");
if (!isOpen()) return kIOReturnNotOpen;
if (!lvString || !lvStringSize) return kIOReturnBadArgument;
if (!retBuffer || !retBufferSize) return kIOReturnBadArgument;
gAppleRAIDGlobals.lock();
while (1) {
OSString * lvName = OSString::withCString(lvString);
if (!lvName) break;
AppleLVMVolume * lv = findLogicalVolume(lvName);
if (!lv) break;
const OSString * lvgUUID = lv->getGroupUUID();
if (!lvgUUID) break;
AppleLVMGroup * lvg = (AppleLVMGroup *)findSet(lvgUUID);
if (!lvg) break;
rc = lvg->destroyLogicalVolume(lv);
*(UInt32 *)retBuffer = lvg->getSequenceNumber();
*retBufferSize = sizeof(UInt32);
break;
}
gAppleRAIDGlobals.unlock();
IOLog1("AppleRAID::destroyLogicalVolume() was %ssuccessful.\n", rc ? "un" : "");
return rc;
}