1/* 2 * Copyright (c) 2001-2007 Apple 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 "AppleRAID.h" 24 25#define super IOService 26OSDefineMetaClassAndStructors(AppleRAID, IOService); 27 28bool AppleRAID::init() 29{ 30 if (super::init() == false) return false; 31 32 raidSets = OSDictionary::withCapacity(0x10); 33 raidMembers = OSDictionary::withCapacity(0x10); 34 logicalVolumes = OSDictionary::withCapacity(0x10); 35 36 return (raidSets && raidMembers && logicalVolumes); 37} 38 39void AppleRAID::free() 40{ 41 if (raidSets) { 42 raidSets->release(); 43 raidSets = 0; 44 } 45 if (raidMembers) { 46 raidMembers->release(); 47 raidMembers = 0; 48 } 49 if (logicalVolumes) { 50 logicalVolumes->release(); 51 logicalVolumes = 0; 52 } 53 54 super::free(); 55} 56 57// ************************************************************************************************** 58 59void AppleRAID::addSet(AppleRAIDSet *set) 60{ 61 const OSString * uuid = set->getUUID(); 62 63 if (uuid) { 64 raidSets->setObject(uuid, set); 65 } 66} 67 68void AppleRAID::removeSet(AppleRAIDSet * set) 69{ 70 const OSString * uuid = set->getUUID(); 71 72 if (uuid) { 73 raidSets->removeObject(uuid); 74 } 75} 76 77AppleRAIDSet * AppleRAID::findSet(const OSString *uuid) 78{ 79 return OSDynamicCast(AppleRAIDSet, raidSets->getObject(uuid)); 80} 81 82AppleRAIDSet * AppleRAID::findSet(AppleRAIDMember * member) 83{ 84 const OSString * setUUID = member->getSetUUID(); 85 if (setUUID == 0) return 0; 86 87 // top level set has both UUID's set the same 88 89 return OSDynamicCast(AppleRAIDSet, raidSets->getObject(setUUID)); 90} 91 92// ************************************************************************************************** 93 94void AppleRAID::addMember(AppleRAIDMember *member) 95{ 96 const OSString * uuid = member->getUUID(); 97 98 if (uuid) { 99 raidMembers->setObject(uuid, member); 100 } 101} 102 103void AppleRAID::removeMember(AppleRAIDMember * member) 104{ 105 const OSString * uuid = member->getUUID(); 106 107 if (uuid) { 108 raidMembers->removeObject(uuid); 109 } 110} 111 112AppleRAIDMember * AppleRAID::findMember(const OSString *uuid) 113{ 114 return OSDynamicCast(AppleRAIDMember, raidMembers->getObject(uuid)); 115} 116 117// ************************************************************************************************** 118 119void AppleRAID::addLogicalVolume(AppleLVMVolume *volume) 120{ 121 const OSString * uuid = volume->getVolumeUUID(); 122 123 if (uuid) { 124 logicalVolumes->setObject(uuid, volume); 125 } 126} 127 128void AppleRAID::removeLogicalVolume(AppleLVMVolume * volume) 129{ 130 const OSString * uuid = volume->getVolumeUUID(); 131 132 if (uuid) { 133 logicalVolumes->removeObject(uuid); 134 } 135} 136 137AppleLVMVolume * AppleRAID::findLogicalVolume(const OSString *uuid) 138{ 139 return OSDynamicCast(AppleLVMVolume, logicalVolumes->getObject(uuid)); 140} 141 142// ************************************************************************************************** 143 144// this should only fail in drastic cases 145 146IOReturn AppleRAID::newMember(IORegistryEntry * child) 147{ 148 AppleRAIDMember * member = OSDynamicCast(AppleRAIDMember, child); 149 150 // this code is running under the global raid lock 151 gAppleRAIDGlobals.lock(); 152 153 IOLog1("AppleRAID::newMember(%p) entered.\n", child); 154 155 while (1) { 156 157 if (member == 0) break; 158 159 // Look up the members's uuid 160 const OSString * memberUUID = member->getUUID(); 161 if (memberUUID == 0) break; 162 163 // check if member already exists? 164 if (findMember(memberUUID)) { 165 IOLog("AppleRAID::newMember detected duplicate member %s in set \"%s\" (%s).\n", 166 member->getUUIDString(), member->getSetNameString(), member->getSetUUIDString()); 167 // XXX should break the set, this is bad 168 break; 169 } 170 171 addMember(member); 172 173 // Look up the set's uuid 174 const OSString * setUUID = member->getSetUUID(); 175 if (setUUID == 0) { 176 IOLog("AppleRAID::newMember member %s in set \"%s\" has a corrupted header (no set UUID).\n", 177 member->getUUIDString(), member->getSetNameString()); 178 break; 179 } 180 181 AppleRAIDSet * set = findSet(setUUID); 182 183 bool firstTime = set == 0; 184 185 // If the unique name was not found then create a new raid set 186 if (!set) { 187 188 OSString * raidLevel = OSDynamicCast(OSString, member->getHeaderProperty(kAppleRAIDLevelNameKey)); 189 if (!raidLevel) { 190 IOLog("AppleRAID::newMember member %s in set \"%s\" (%s) has a corrupted header (no RAID level).\n", 191 member->getUUIDString(), member->getSetNameString(), member->getSetUUIDString()); 192 break; 193 } 194 195 IOLog1("AppleRAID::newMember(%p) new raid set, level = %s.\n", child, raidLevel->getCStringNoCopy()); 196 197 // XXX - should make this dynamic at run time, have raid levels register with the controller 198 // XXX - or try to dynamically load plugins right here based on the raid level string 199 200 if (raidLevel->isEqualTo(kAppleRAIDLevelNameConcat)) { 201 set = AppleRAIDConcatSet::createRAIDSet(member); 202 } else 203 if (raidLevel->isEqualTo(kAppleRAIDLevelNameMirror)) { 204 set = AppleRAIDMirrorSet::createRAIDSet(member); 205 } else 206 if (raidLevel->isEqualTo(kAppleRAIDLevelNameStripe)) { 207 set = AppleRAIDStripeSet::createRAIDSet(member); 208 } else 209 if (raidLevel->isEqualTo(kAppleRAIDLevelNameLVG)) { 210 set = AppleLVMGroup::createRAIDSet(member); 211 } 212 213 if (set) { 214 IOLog1("AppleRAID::newMember(%p) raid set \"%s\" (%s) successfully created.\n", 215 child, set->getSetNameString(), set->getUUIDString()); 216 addSet(set); 217 set->release(); 218 } else { 219 IOLog("AppleRAID::newMember unknown raid level %s.\n", raidLevel->getCStringNoCopy()); 220 } 221 } 222 223 // only punt on headerless raid partitions 224 if (!set) break; 225 226 // is this a live add of a new member? 227 // concat only, mirrors come in as spares 228 if (set->isPaused() && !set->isSetComplete()) { 229 if (set->upgradeMember(member)) { 230 restartSet(set, true); 231 IOLog1("AppleRAID::newMember(%p) was successful (live add).\n", child); 232 gAppleRAIDGlobals.unlock(); 233 return kIOReturnSuccess; 234 } 235 break; 236 } 237 238 // add member to raid set... 239 if (!set->addMember(member)) { 240 if (!set->addSpare(member)) { 241 IOLog("AppleRAID::newMember was unable to add member %s to set \"%s\" (%s).\n", 242 member->getUUIDString(), set->getSetNameString(), set->getUUIDString()); 243 break; 244 } 245 } 246 247 // try starting up the set 248 startSet(set); 249 250 // needed for user notifications 251 if (firstTime) set->registerService(); 252 253 IOLog1("AppleRAID::newMember(%p) was successful.\n", child); 254 gAppleRAIDGlobals.unlock(); 255 return kIOReturnSuccess; 256 } 257 258 IOLog1("AppleRAID::newMember(%p) failed.\n", child); 259 260 if (member) removeMember(member); 261 262 gAppleRAIDGlobals.unlock(); 263 return kIOReturnUnformattedMedia; 264} 265 266IOReturn AppleRAID::oldMember(IORegistryEntry * child) 267{ 268 IOLog1("AppleRAID::oldMember(%p) entered.\n", child); 269 270 // this code can not make any i/o requests, or it 271 // may deadlock this is because the driver calling 272 // this is holding it's lock 273 274 // this code is running under the global raid lock 275 gAppleRAIDGlobals.lock(); 276 277 while (1) { 278 279 AppleRAIDMember * member = OSDynamicCast(AppleRAIDMember, child); 280 if (member == 0) break; 281 282 // still tracking this member? 283 const OSString * memberUUID = member->getUUID(); 284 if (!memberUUID || findMember(memberUUID) != member) break; 285 286 // does it still belong to a raid set? 287 AppleRAIDSet * set = findSet(member); 288 if (!set) break; 289 290 set->retain(); 291 292 removeMember(member); 293 set->removeMember(member, 0); 294 295 // if this member's set is empty then nuke the set as well 296 if ((set->getActiveCount() == 0) && (set->getSpareCount() == 0)) { 297 298 // if this set is part of another set then handle that first 299 if (set->isRAIDMember()) { 300 oldMember(set); 301 } 302 303 IOLog1("AppleRAID::oldMember(%p) terminating parent raid set %p.\n", child, set); 304 removeSet(set); 305 } else { 306 set->release(); 307 set = NULL; 308 } 309 310 gAppleRAIDGlobals.unlock(); 311 312 if (set) { 313 IOLog("AppleRAID: terminating set \"%s\" (%s).\n", set->getSetNameString(), set->getUUIDString()); 314 set->terminate(); 315 set->release(); 316 } 317 318 IOLog1("AppleRAID::oldMember(%p) was successful.\n", child); 319 320 return kIOReturnSuccess; 321 } 322 323 IOLog1("AppleRAID::oldMember(%p) lookup failed.\n", child); 324 gAppleRAIDGlobals.unlock(); 325 return kIOReturnError; 326} 327 328 329void AppleRAID::recoverMember(IORegistryEntry * child) 330{ 331 IOLog1("AppleRAID::recoverMember(%p) entered.\n", child); 332 333 AppleRAIDMember * member = OSDynamicCast(AppleRAIDMember, child); 334 if (member) { 335 AppleRAIDSet * set = findSet(member); 336 if (set) set->arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, set, &AppleRAIDSet::recoverStart)); 337 } 338} 339 340 341// ***************************************************************************** 342 343void AppleRAID::startSet(AppleRAIDSet * set) 344{ 345 IOLog1("AppleRAID::startSet(%p) entered.\n", set); 346 347 // this code is running under the global raid lock 348 assert(gAppleRAIDGlobals.islocked()); 349 350 assert(!set->isPaused()); 351 352 if (set->startSet()) { 353 354 IOLog1("AppleRAID::startSet: the set %p is started.\n", set); 355 356 // check for a "stacked" raid header, the first time 357 // we get here we don't know if the set is a raid member 358 if (!set->isRAIDMember()) set->start(NULL); 359 } 360 361 // let the evilness begin... 362 (void)set->publishSet(); 363 364 return; 365} 366 367void AppleRAID::degradeSet(AppleRAIDSet *set) 368{ 369 // this code is running under the global raid lock 370 gAppleRAIDGlobals.lock(); 371 372 // make sure we still know about this set and it is in the right state 373 // the set has an extra retain on it to make this work (see ARM::init) 374 const OSString * setUUID = set->getUUID(); 375 if ((set == findSet(setUUID)) && (set->getSetState() == kAppleRAIDSetStateInitializing)) { 376 377 assert(!set->isPaused()); 378 379 IOLog("AppleRAID::degradeSet - starting the set \"%s\" (%s).\n", 380 set->getSetNameString(), set->getUUIDString()); 381 382 if (set->startSet()) { 383 384 IOLog1("AppleRAID::degradeSet: the set %p is started.\n", set); 385 386 // check for a "stacked" raid header 387 if (!set->isRAIDMember()) set->start(NULL); 388 } 389 390 if (set->getSetState() == kAppleRAIDSetStateDegraded) { 391 set->bumpSequenceNumber(); 392 set->writeRAIDHeader(); 393 } 394 395 // let the evilness begin... 396 (void)set->publishSet(); 397 } 398 399 gAppleRAIDGlobals.unlock(); 400} 401 402void AppleRAID::restartSet(AppleRAIDSet *set, bool bump) 403{ 404 IOLog1("AppleRAID::restartSet(%p) entered.\n", set); 405 406 // this code is running under the global raid lock 407 gAppleRAIDGlobals.lock(); 408 409 IOLog("AppleRAID::restartSet - restarting set \"%s\" (%s).\n", set->getSetNameString(), set->getUUIDString()); 410 411 (void)set->startSet(); 412 if (bump) { 413 set->bumpSequenceNumber(); 414 (void)set->writeRAIDHeader(); 415 } 416 (void)set->publishSet(); 417 418 gAppleRAIDGlobals.unlock(); 419} 420 421 422IOReturn AppleRAID::updateSet(char * setInfoBuffer, uint32_t setInfoBufferSize, char * retBuffer, uint32_t * retBufferSize) 423{ 424 IOReturn rc = kIOReturnSuccess; 425 IOLog1("AppleRAID::updateSet() entered\n"); 426 427 if (!isOpen()) return kIOReturnNotOpen; 428 if (!setInfoBuffer || !setInfoBufferSize) return kIOReturnBadArgument; 429 if (!retBuffer || !retBufferSize) return kIOReturnBadArgument; 430 431 // this code is running under the global raid lock 432 gAppleRAIDGlobals.lock(); 433 434 while (1) { 435 OSString * errmsg = 0; 436 OSDictionary * updateInfo = OSDynamicCast(OSDictionary, OSUnserializeXML(setInfoBuffer, &errmsg)); 437 if (!updateInfo) { 438 if (errmsg) { 439 IOLog("AppleRAID::updateSet - header parsing failed with %s\n", errmsg->getCStringNoCopy()); 440 errmsg->release(); 441 } 442 rc = kIOReturnBadArgument; 443 break; 444 } 445 446 // find the set 447 const OSString * setUUIDString = OSDynamicCast(OSString, updateInfo->getObject(kAppleRAIDSetUUIDKey)); 448 AppleRAIDSet * set = findSet(setUUIDString); 449 if (!set) { rc = kIOReturnBadArgument; break; }; 450 updateInfo->removeObject(kAppleRAIDSetUUIDKey); 451 452 // if sequence number has changed then bail, something has changed 453 OSNumber * number = OSDynamicCast(OSNumber, updateInfo->getObject(kAppleRAIDSequenceNumberKey)); 454 if (!number) { rc = kIOReturnBadArgument; break; }; 455 UInt32 seqNum = number->unsigned32BitValue(); 456 if (seqNum && seqNum != set->getSequenceNumber()) { rc = kIOReturnBadMessageID; break; }; 457 updateInfo->removeObject(kAppleRAIDSequenceNumberKey); 458 459 number = OSDynamicCast(OSNumber, updateInfo->getObject("_update command_")); 460 if (number) { 461 UInt32 subcommand = number->unsigned32BitValue(); 462 463 IOLog1("AppleRAID::updateSet() executing subcommand %d\n", (int)subcommand); 464 465 switch (subcommand) { 466 467 case kAppleRAIDUpdateResetSet: 468 469 startSet(set); // rescan raid headers (stacked sets) 470 break; 471 472 case kAppleRAIDUpdateDestroySet: 473 474 if (set->unpublishSet()) { 475 if (!set->destroySet()) { 476 rc = kIOReturnError; 477 } 478 } 479 break; 480 481 default: 482 IOLog("AppleRAID::updateSet() unknown subcommand %d\n", (int)subcommand); 483 } 484 } 485 updateInfo->removeObject("_update command_"); 486 487 // for each remaining prop that has changed call a specific set function or merge in 488 if (updateInfo->getCount()) { 489 490 // we only need to go one level higher since we are not changing 491 // the state of any of member sets at that level 492 AppleRAIDSet * parentSet = 0; 493 if (set->isRAIDMember()) { 494 parentSet = findSet((AppleRAIDMember *)set); 495 IOLog1("AppleRAID::updateSet() pausing parent set %p.\n", parentSet); 496 IOCommandGate::Action pauseSetMethod = OSMemberFunctionCast(IOCommandGate::Action, parentSet, &AppleRAIDSet::pauseSet); 497 if (parentSet) parentSet->arSetCommandGate->runAction(pauseSetMethod, (void *)false); 498 } 499 IOLog1("AppleRAID::updateSet() pausing set %p.\n", set); 500 IOCommandGate::Action pauseSetMethod = OSMemberFunctionCast(IOCommandGate::Action, set, &AppleRAIDSet::pauseSet); 501 set->arSetCommandGate->runAction(pauseSetMethod, (void *)false); 502 503 if (!set->reconfigureSet(updateInfo)) rc = kIOReturnError; 504 505 // reallocate the member arrays and republish the set's IOMedia 506 restartSet(set, true); 507 508 // if the set is waiting for a new added disk leave it paused 509 IOLog1("AppleRAID::updateSet() unpausing set.\n"); 510 511 set->arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, set, &AppleRAIDSet::unpauseSet)); 512 if (parentSet) parentSet->arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, parentSet, &AppleRAIDSet::unpauseSet)); 513 } 514 515 *(UInt32 *)retBuffer = set->getSequenceNumber(); // XXX this looks wrong for the destroy case? 516 *retBufferSize = sizeof(UInt32); 517 518 updateInfo->release(); 519 520 IOLog1("AppleRAID::updateSet() was %ssuccessful.\n", rc ? "un" : ""); 521 break; 522 } 523 524 gAppleRAIDGlobals.unlock(); 525 526 return rc; 527} 528 529 530// ***************************************************************************** 531 532 533IOReturn AppleRAID::getListOfSets(UInt32 inFlags, char * outList, uint32_t * outListSize) 534{ 535 OSCollectionIterator * iter = 0; 536 OSArray * keys = 0; 537 OSSerialize * s = 0; 538 IOReturn rc = kIOReturnError; 539 540 IOLog1("AppleRAID::getListOfSets() entered\n"); 541 542 if (!isOpen()) return kIOReturnNotOpen; 543 if (!inFlags || !outList || !outListSize) return kIOReturnBadArgument; 544 545 outList[0] = 0; 546 547 // this code is running under the global raid lock 548 gAppleRAIDGlobals.lock(); 549 550 unsigned int keyCount = raidSets->getCount(); 551 552 while (keyCount) { 553 554 keys = OSArray::withCapacity(keyCount); 555 if (!keys) break; 556 557 iter = OSCollectionIterator::withCollection(raidSets); 558 if (!iter) break; 559 560 while (const OSString * setName = OSDynamicCast(OSString, iter->getNextObject())) { 561 562 AppleRAIDSet * set = findSet(setName); 563 if (!set) continue; 564 565 bool addToList = false; 566 567 if (inFlags && kAppleRAIDState) { 568 UInt32 state = set->getSetState(); 569 addToList = (((state < kAppleRAIDSetStateOnline) && (inFlags & kAppleRAIDOfflineSets)) || 570 ((state == kAppleRAIDSetStateOnline) && (inFlags & kAppleRAIDOnlineSets)) || 571 ((state == kAppleRAIDSetStateDegraded) && (inFlags & kAppleRAIDDegradedSets))); 572 } 573 574 if (inFlags && kAppleRAIDVisibility) { 575 bool visible = !set->isRAIDMember(); 576 addToList = visible ? (inFlags & kAppleRAIDVisibleSets) : (inFlags & kAppleRAIDInternalSets); 577 } 578 579 if (addToList) (void)keys->setObject(setName); 580 } 581 582 s = OSSerialize::withCapacity(keys->getCount() * 128); 583 if (!s) break; 584 585 s->clearText(); 586 if (!keys->serialize(s)) break; 587 588 if (*outListSize < s->getLength()) { 589 IOLog("AppleRAID::getListOfSets() return buffer too small, need %d bytes, received %d.\n", 590 (int)s->getLength(), (int)*outListSize); 591 rc = kIOReturnNoSpace; 592 break; 593 } 594 *outListSize = s->getLength(); 595 596 bcopy(s->text(), outList, *outListSize); 597 598 rc = kIOReturnSuccess; 599 break; 600 } 601 if (iter) iter->release(); 602 if (keys) keys->release(); 603 if (s) s->release(); 604 if (keyCount == 0) rc = kIOReturnNoDevice; 605 606 if (rc) *outListSize = 0; 607 608 gAppleRAIDGlobals.unlock(); 609 610 return rc; 611} 612 613 614IOReturn AppleRAID::getSetProperties(char * setString, uint32_t setStringSize, char * outProp, uint32_t * outPropSize) 615{ 616 IOReturn rc = kIOReturnError; 617 const OSString * setName = 0; 618 AppleRAIDSet * set = 0; 619 OSDictionary * props = 0; 620 OSSerialize * s = 0; 621 622 IOLog1("AppleRAID::getSetProperties(%s) entered\n", setString); 623 624 if (!isOpen()) return kIOReturnNotOpen; 625 if (!setString || !outProp || !outPropSize) return kIOReturnBadArgument; 626 627 outProp[0] = 0; 628 629 // this code is running under the global raid lock 630 gAppleRAIDGlobals.lock(); 631 632 while (1) { 633 634 setName = OSString::withCString(setString); 635 if (!setName) break; 636 637 set = findSet(setName); 638 if (!set) break; 639 640 IOLog1("setName = %s (%p)\n", setString, set); 641 642 // get the prop list from the set 643 props = set->getSetProperties(); 644 if (!props) break; 645 646 s = OSSerialize::withCapacity(512); 647 if (!s) break; 648 649 s->clearText(); 650 if (!props->serialize(s)) break; 651 652 if (*outPropSize < s->getLength()) { 653 IOLog("AppleRAID::getSetProperties() return buffer too small, need %d bytes, received %d.\n", 654 (int)s->getLength(), (int)*outPropSize); 655 rc = kIOReturnNoSpace; 656 break; 657 } 658 659 *outPropSize = s->getLength(); 660 bcopy(s->text(), outProp, *outPropSize); 661 662 rc = kIOReturnSuccess; 663 break; 664 } 665 if (setName) setName->release(); 666 if (props) props->release(); 667 if (s) s->release(); 668 669 if (rc) *outPropSize = 0; 670 671 gAppleRAIDGlobals.unlock(); 672 673 return rc; 674} 675 676 677IOReturn AppleRAID::getMemberProperties(char * memberString, uint32_t memberStringSize, char * outProp, uint32_t * outPropSize) 678{ 679 IOReturn rc = kIOReturnError; 680 const OSString * memberName = 0; 681 AppleRAIDMember * member = 0; 682 OSDictionary * props = 0; 683 OSSerialize * s = 0; 684 685 IOLog2("AppleRAID::getMemberProperties(%s) entered\n", memberString); 686 687 if (!isOpen()) return kIOReturnNotOpen; 688 if (!memberString || !outProp || !outPropSize) return kIOReturnBadArgument; 689 690 outProp[0] = 0; 691 692 // this code is running under the global raid lock 693 gAppleRAIDGlobals.lock(); 694 695 while (1) { 696 697 memberName = OSString::withCString(memberString); 698 if (!memberName) break; 699 700 member = findMember(memberName); 701 if (!member) break; 702 703 IOLog1("memberName = %s (%p)\n", memberString, member); 704 705 // get the prop list from the member 706 props = member->getMemberProperties(); 707 if (!props) break; 708 709 s = OSSerialize::withCapacity(512); 710 if (!s) break; 711 712 s->clearText(); 713 if (!props->serialize(s)) break; 714 715 if (*outPropSize < s->getLength()) { 716 IOLog("AppleRAID::getMemberProperties() return buffer too small, need %d bytes, received %d.\n", 717 (int)s->getLength(), (int)*outPropSize); 718 rc = kIOReturnNoSpace; 719 break; 720 } 721 722 *outPropSize = s->getLength(); 723 bcopy(s->text(), outProp, *outPropSize); 724 725 rc = kIOReturnSuccess; 726 break; 727 } 728 if (memberName) memberName->release(); 729 if (props) props->release(); 730 if (s) s->release(); 731 732 if (rc) *outPropSize = 0; 733 734 gAppleRAIDGlobals.unlock(); 735 736 return rc; 737} 738 739// ***************************************************************************** 740 741IOReturn AppleRAID::getVolumesForGroup(char * lvgString, uint32_t lvgStringSize, char * arrayString, uint32_t * outArraySize) 742{ 743 IOReturn rc = kIOReturnError; 744 const OSString * lvgName = 0; 745 AppleLVMGroup * lvg = 0; 746 const OSString * memberName = 0; 747 AppleRAIDMember * member = 0; 748 OSArray * array = 0; 749 OSSerialize * s = 0; 750 751 IOLog1("AppleRAID::getVolumesForGroup(%s) for member %s entered\n", 752 lvgString, lvgString[kAppleRAIDMaxUUIDStringSize] ? &lvgString[kAppleRAIDMaxUUIDStringSize] : "<all>"); 753 754 if (!isOpen()) return kIOReturnNotOpen; 755 if (!lvgString || !arrayString || !outArraySize) return kIOReturnBadArgument; 756 757 arrayString[0] = 0; 758 759 // this code is running under the global raid lock 760 gAppleRAIDGlobals.lock(); 761 762 while (1) { 763 764 lvgName = OSString::withCString(lvgString); 765 if (!lvgName) break; 766 lvg = OSDynamicCast(AppleLVMGroup, findSet(lvgName)); 767 if (!lvg) break; 768 769 if (lvgString[kAppleRAIDMaxUUIDStringSize]) { 770 memberName = OSString::withCString(&lvgString[kAppleRAIDMaxUUIDStringSize]); 771 if (!memberName) break; 772 member = findMember(memberName); 773 if (!member) break; 774 } 775 776 // get the prop list from the volume 777 array = lvg->buildLogicalVolumeListFromTOC(member); 778 if (!array) break; 779 780 s = OSSerialize::withCapacity(512); 781 if (!s) break; 782 783 s->clearText(); 784 if (!array->serialize(s)) break; 785 786 if (*outArraySize < s->getLength()) { 787 IOLog("AppleRAID::getVolumeForGroup() return buffer too small, need %d bytes, received %d.\n", 788 (int)s->getLength(), (int)*outArraySize); 789 rc = kIOReturnNoSpace; 790 break; 791 } 792 793 IOLog2("AppleRAID::getVolumesForGroup() size = %u array = %s\n", s->getLength(), s->text()); 794 795 *outArraySize = s->getLength(); 796 bcopy(s->text(), arrayString, *outArraySize); 797 798 rc = kIOReturnSuccess; 799 break; 800 } 801 if (lvgName) lvgName->release(); 802 if (memberName) memberName->release(); 803 if (array) array->release(); 804 if (s) s->release(); 805 806 if (rc) *outArraySize = 0; 807 808 gAppleRAIDGlobals.unlock(); 809 810 return rc; 811} 812 813IOReturn AppleRAID::getVolumeProperties(char * lvString, uint32_t lvStringSize, char * outProp, uint32_t * outPropSize) 814{ 815 IOReturn rc = kIOReturnError; 816 const OSString * lvName = 0; 817 AppleLVMVolume * lv = 0; 818 OSDictionary * props = 0; 819 OSSerialize * s = 0; 820 821 IOLog1("AppleRAID::getVolumeProperties(%s) entered\n", lvString); 822 823 if (!isOpen()) return kIOReturnNotOpen; 824 if (!lvString || !outProp || !outPropSize) return kIOReturnBadArgument; 825 826 outProp[0] = 0; 827 828 // this code is running under the global raid lock 829 gAppleRAIDGlobals.lock(); 830 831 while (1) { 832 833 lvName = OSString::withCString(lvString); 834 if (!lvName) break; 835 836 lv = findLogicalVolume(lvName); 837 if (!lv) break; 838 839 // get the prop list from the volume 840 props = lv->getVolumeProperties(); 841 if (!props) break; 842 843 s = OSSerialize::withCapacity(512); 844 if (!s) break; 845 846 s->clearText(); 847 if (!props->serialize(s)) break; 848 849 if (*outPropSize < s->getLength()) { 850 IOLog("AppleRAID::getVolumeProperties() return buffer too small, need %d bytes, received %d.\n", 851 (int)s->getLength(), (int)*outPropSize); 852 rc = kIOReturnNoSpace; 853 break; 854 } 855 856 *outPropSize = s->getLength(); 857 bcopy(s->text(), outProp, *outPropSize); 858 859 rc = kIOReturnSuccess; 860 break; 861 } 862 if (lvName) lvName->release(); 863 if (props) props->release(); 864 if (s) s->release(); 865 866 if (rc) *outPropSize = 0; 867 868 gAppleRAIDGlobals.unlock(); 869 870 return rc; 871} 872 873 874IOReturn AppleRAID::getVolumeExtents(char * lvString, uint32_t lvStringSize, char * extentsBuffer, uint32_t * extentsSize) 875{ 876 IOReturn rc = kIOReturnError; 877 const OSString * lvName = 0; 878 AppleLVMVolume * lv = 0; 879 AppleLVMGroup * lvg = 0; 880 881 IOLog1("AppleRAID::getVolumeExtents(%s) entered\n", lvString); 882 883 if (!isOpen()) return kIOReturnNotOpen; 884 if (!lvString || !extentsBuffer || !extentsSize) return kIOReturnBadArgument; 885 886 // this code is running under the global raid lock 887 gAppleRAIDGlobals.lock(); 888 889 while (1) { 890 891 lvName = OSString::withCString(lvString); 892 if (!lvName) break; 893 894 // get the extent list from the volume 895 AppleRAIDExtentOnDisk * extent = (AppleRAIDExtentOnDisk *)extentsBuffer; 896 897 lv = findLogicalVolume(lvName); 898 if (!lv) { 899 900 // the lvg list is special 901 lvg = OSDynamicCast(AppleLVMGroup, findSet(lvName)); 902 if (!lvg) break; 903 904 UInt64 extentCount = lvg->getExtentCount(); 905 if (extentCount * sizeof(AppleRAIDExtentOnDisk) > *extentsSize) { 906 extent->extentByteOffset = extentCount; 907 extent->extentByteCount = 0; 908 *extentsSize = sizeof(AppleRAIDExtentOnDisk); 909 rc = kIOReturnSuccess; // error is indicated via return buffer 910 } else { 911 if (lvg->buildExtentList(extent)) { 912 *extentsSize = extentCount * sizeof(AppleRAIDExtentOnDisk); 913 rc = kIOReturnSuccess; 914 } 915 } 916 IOLog1("LVG %s (%p) has %llu total extents.\n", lvString, lvg, extentCount); 917 break; 918 } 919 920 UInt64 extentCount = lv->getExtentCount(); 921 if (extentCount * sizeof(AppleRAIDExtentOnDisk) > *extentsSize) { 922 extent->extentByteOffset = extentCount; 923 extent->extentByteCount = 0; 924 *extentsSize = sizeof(AppleRAIDExtentOnDisk); 925 rc = kIOReturnSuccess; // error is indicated via return buffer 926 } else { 927 if (lv->buildExtentList(extent)) { 928 *extentsSize = extentCount * sizeof(AppleRAIDExtentOnDisk); 929 rc = kIOReturnSuccess; 930 } 931 } 932 IOLog1("LV %s (%p) has %llu extents.\n", lvString, lv, extentCount); 933 934 break; 935 } 936 if (lvName) lvName->release(); 937 938 if (rc) *extentsSize = 0; 939 940 gAppleRAIDGlobals.unlock(); 941 942 return rc; 943} 944 945 946IOReturn AppleRAID::updateLogicalVolume(char * lveBuffer, uint32_t lveBufferSize, char * retBuffer, uint32_t * retBufferSize) 947{ 948 OSDictionary * lvProps = NULL; 949 IOReturn rc = kIOReturnBadArgument; 950 IOLog1("AppleRAID::updateLogicalVolume() entered\n"); 951 952 if (!isOpen()) return kIOReturnNotOpen; 953 if (!lveBuffer || !lveBufferSize) return kIOReturnBadArgument; 954 if (!retBuffer || !retBufferSize) return kIOReturnBadArgument; 955 956 AppleLVMVolumeOnDisk * lve = (AppleLVMVolumeOnDisk *)lveBuffer; 957 958 // this code is running under the global raid lock 959 gAppleRAIDGlobals.lock(); 960 961 while (1) { 962 963 lvProps = AppleLVMVolume::propsFromHeader(lve); 964 if (!lvProps) break; 965 966 // find the set 967 const OSString * setUUIDString = OSDynamicCast(OSString, lvProps->getObject(kAppleLVMGroupUUIDKey)); 968 AppleLVMGroup * lvg = OSDynamicCast(AppleLVMGroup, findSet(setUUIDString)); 969 if (!lvg) break; 970 971 // if sequence number has changed then bail, something has changed 972 // the logical volume should be updated with the current LVG sequence number 973 OSNumber * number = OSDynamicCast(OSNumber, lvProps->getObject(kAppleLVMVolumeSequenceKey)); 974 if (!number) break; 975 UInt32 seqNum = number->unsigned32BitValue(); 976 if (seqNum && seqNum != lvg->getSequenceNumber()) { rc = kIOReturnBadMessageID; break; }; 977 978 // look up the volume UUID, this might be an update 979 const OSString * lvUUIDString = OSDynamicCast(OSString, lvProps->getObject(kAppleLVMVolumeUUIDKey)); 980 AppleLVMVolume * lv = OSDynamicCast(AppleLVMVolume, findLogicalVolume(lvUUIDString)); 981 982 // do something 983 984 if (lv) { 985 rc = lvg->updateLogicalVolume(lv, lvProps, lve); 986 } else { 987 rc = lvg->createLogicalVolume(lvProps, lve); 988 } 989 990 *(UInt32 *)retBuffer = lvg->getSequenceNumber(); 991 *retBufferSize = sizeof(UInt32); 992 993 break; 994 } 995 996 gAppleRAIDGlobals.unlock(); 997 998 if (lvProps) lvProps->release(); 999 1000 IOLog1("AppleRAID::updateLogicalVolume() was %ssuccessful.\n", rc ? "un" : ""); 1001 return rc; 1002} 1003 1004 1005IOReturn AppleRAID::destroyLogicalVolume(char * lvString, uint32_t lvStringSize, char * retBuffer, uint32_t * retBufferSize) 1006{ 1007 IOReturn rc = kIOReturnBadArgument; 1008 IOLog1("AppleRAID::destroyLogicalVolume() entered\n"); 1009 1010 if (!isOpen()) return kIOReturnNotOpen; 1011 if (!lvString || !lvStringSize) return kIOReturnBadArgument; 1012 if (!retBuffer || !retBufferSize) return kIOReturnBadArgument; 1013 1014 // this code is running under the global raid lock 1015 gAppleRAIDGlobals.lock(); 1016 1017 while (1) { 1018 OSString * lvName = OSString::withCString(lvString); 1019 if (!lvName) break; 1020 1021 AppleLVMVolume * lv = findLogicalVolume(lvName); 1022 if (!lv) break; 1023 1024 const OSString * lvgUUID = lv->getGroupUUID(); 1025 if (!lvgUUID) break; 1026 AppleLVMGroup * lvg = (AppleLVMGroup *)findSet(lvgUUID); 1027 if (!lvg) break; 1028 1029 // do something 1030 rc = lvg->destroyLogicalVolume(lv); 1031 1032 *(UInt32 *)retBuffer = lvg->getSequenceNumber(); 1033 *retBufferSize = sizeof(UInt32); 1034 1035 break; 1036 } 1037 1038 gAppleRAIDGlobals.unlock(); 1039 1040 IOLog1("AppleRAID::destroyLogicalVolume() was %ssuccessful.\n", rc ? "un" : ""); 1041 return rc; 1042} 1043