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#include <IOKit/IOPolledInterface.h> 25#include "sys/param.h" // MAXBSIZE 26 27#define super AppleRAIDMember 28OSDefineMetaClassAndAbstractStructors(AppleRAIDSet, AppleRAIDMember); 29 30void AppleRAIDSet::free(void) 31{ 32 if (arOpenReaders) arOpenReaders->release(); 33 34 if (arMembers) IODelete(arMembers, AppleRAIDMember *, arLastAllocCount); 35 if (arSpareMembers) arSpareMembers->release(); 36 37// UInt32 count = 0; // XXXXXXXXXXXXXXX LVM 38 if (arStorageRequestPool) { 39 while (1) { 40 AppleRAIDStorageRequest * storageRequest; 41 storageRequest = (AppleRAIDStorageRequest *)arStorageRequestPool->getCommand(false); 42 if (storageRequest == 0) break; 43// count++; // XXXXXXXXXXXXXXX 44 storageRequest->release(); 45 } 46 arStorageRequestPool->release(); 47 arStorageRequestPool = 0; 48 } 49// IOLog1("ARSFree: freed %lu SR's, pending %lu XXXXXXXXXXXXXXX\n", count, arStorageRequestsPending); 50 51 if (arSetCommandGate != 0) { 52 arSetWorkLoop->removeEventSource(arSetCommandGate); 53 arSetCommandGate->release(); 54 arSetCommandGate = 0; 55 } 56 if (arSetEventSource != 0) { 57 arSetWorkLoop->removeEventSource(arSetEventSource); 58 arSetEventSource->release(); 59 arSetEventSource = 0; 60 } 61 if (arSetWorkLoop != 0) arSetWorkLoop->release(); 62 arSetWorkLoop = 0; 63 64 if (arRecoveryThreadCall) thread_call_free(arRecoveryThreadCall); 65 arRecoveryThreadCall = 0; 66 67 super::free(); 68} 69 70// once only init 71bool AppleRAIDSet::init() 72{ 73 if (super::init() == false) return false; 74 75 arSetState = kAppleRAIDSetStateInitializing; 76 setProperty(kAppleRAIDStatusKey, kAppleRAIDStatusOffline); 77 // this will disable the writing of hibernation data on RAID volumes 78 setProperty(kIOPolledInterfaceSupportKey, kOSBooleanFalse); 79 80 arMemberCount = 0; 81 arLastAllocCount = 0; 82 arSequenceNumber = 0; 83 arMedia = NULL; 84 arOpenLevel = kIOStorageAccessNone; 85 arOpenReaders = OSSet::withCapacity(10); 86 arOpenReaderWriters = OSSet::withCapacity(10); 87 88 arSetCompleteTimeout = kARSetCompleteTimeoutNone; 89 arSetBlockCount = 0; 90 arSetMediaSize = 0; 91 arMaxReadRequestFactor = 0; 92 arPrimaryMetaDataUsed = 0; 93 arPrimaryMetaDataMax = 0; 94 95 arMembers = 0; 96 arSpareMembers = OSSet::withCapacity(10); 97 98 arSetIsSyncingCount = 0; 99 100 if (!arSpareMembers || !arOpenReaders) return false; 101 102 // Get the WorkLoop. 103 if (getWorkLoop() != 0) { 104 arSetCommandGate = IOCommandGate::commandGate(this); 105 if (arSetCommandGate != 0) { 106 getWorkLoop()->addEventSource(arSetCommandGate); 107 } 108 109 AppleRAIDEventSource::Action completeRequestMethod = OSMemberFunctionCast(AppleRAIDEventSource::Action, this, &AppleRAIDSet::completeRAIDRequest); 110 arSetEventSource = AppleRAIDEventSource::withAppleRAIDSet(this, completeRequestMethod); 111 if (arSetEventSource != 0) { 112 getWorkLoop()->addEventSource(arSetEventSource); 113 } 114 } 115 116 thread_call_func_t recoverMethod = OSMemberFunctionCast(thread_call_func_t, this, &AppleRAIDSet::recover); 117 arRecoveryThreadCall = thread_call_allocate(recoverMethod, (thread_call_param_t)this); 118 if (arRecoveryThreadCall == 0) return false; 119 120 arAllocateRequestMethod = (IOCommandGate::Action)0xdeadbeef; 121 122 return true; 123} 124 125bool AppleRAIDSet::initWithHeader(OSDictionary * header, bool firstTime) 126{ 127 if (!header) return false; 128 129 OSString * string; 130 string = OSDynamicCast(OSString, header->getObject(kAppleRAIDSetNameKey)); 131 if (string) setProperty(kAppleRAIDSetNameKey, string); 132 133 string = OSDynamicCast(OSString, header->getObject(kAppleRAIDSetUUIDKey)); 134 if (string) { 135 setProperty(kAppleRAIDMemberUUIDKey, string); // the real uuid for this set 136 setProperty(kAppleRAIDSetUUIDKey, string); // is overridden in addMember if stacked 137 } else { 138 if (firstTime) return false; 139 } 140 // this is only in v2 headers, the spare list is built on the fly 141 OSArray * members = OSDynamicCast(OSArray, header->getObject(kAppleRAIDMembersKey)); 142 if (members) setProperty(kAppleRAIDMembersKey, members); 143 144 OSNumber * number; 145 number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDHeaderVersionKey)); 146 if (number) { 147 arHeaderVersion = number->unsigned32BitValue(); 148 } else { 149 if (firstTime) return false; 150 } 151 152 number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDSequenceNumberKey)); 153 if (number) { 154 arSequenceNumber = number->unsigned32BitValue(); 155 } else { 156 if (firstTime) return false; 157 } 158 159 number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDChunkSizeKey)); 160 if (number) { 161 arSetBlockSize = number->unsigned64BitValue(); 162 } else { 163 if (firstTime) return false; 164 } 165 166 // not really in v2 header 167 number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDMemberCountKey)); 168 if (number) { 169 arMemberCount = number->unsigned32BitValue(); 170 } else { 171 if (firstTime) return false; 172 } 173 174 number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDBaseOffsetKey)); 175 if (number) { 176 arBaseOffset = number->unsigned64BitValue(); 177 } else { 178 if (firstTime) return false; 179 } 180 181 number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDNativeBlockSizeKey)); 182 if (number) { 183 arNativeBlockSize = number->unsigned64BitValue(); 184 } else { 185 if (firstTime) return false; 186 } 187 188 number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDPrimaryMetaDataUsedKey)); 189 if (number) { 190 arPrimaryMetaDataUsed = number->unsigned64BitValue(); 191 } 192 193 // don't care if these fail 194 setProperty(kAppleRAIDSetContentHintKey, header->getObject(kAppleRAIDSetContentHintKey)); 195 setProperty(kAppleRAIDCanAddMembersKey, header->getObject(kAppleRAIDCanAddMembersKey)); 196 setProperty(kAppleRAIDCanAddSparesKey, header->getObject(kAppleRAIDCanAddSparesKey)); 197 setProperty(kAppleRAIDRemovalAllowedKey, header->getObject(kAppleRAIDRemovalAllowedKey)); 198 setProperty(kAppleRAIDSizesCanVaryKey, header->getObject(kAppleRAIDSizesCanVaryKey)); 199 200 return true; 201} 202 203//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 204//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 205//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 206 207bool AppleRAIDSet::addSpare(AppleRAIDMember * member) 208{ 209 IOLog1("AppleRAIDSet::addSpare(%p) entered, spare count was %u.\n", member, (uint32_t)getSpareCount()); 210 211 assert(gAppleRAIDGlobals.islocked()); 212 213 if (!this->attach(member)) { 214 IOLog1("AppleRAIDSet::addSpare(%p) this->attach(%p) failed\n", this, member); 215 member->changeMemberState(kAppleRAIDMemberStateBroken); 216 return false; 217 } 218 219 arSpareMembers->setObject(member); 220 221 return true; 222} 223 224bool AppleRAIDSet::addMember(AppleRAIDMember * member) 225{ 226 IOLog1("AppleRAIDSet::addMember(%p) called\n", member); 227 228 assert(gAppleRAIDGlobals.islocked()); 229 230 if (member->isBroken()) return false; 231 232 // deal with spare members separately 233 if (member->isSpare()) return false; 234 235 // new members should be closed ... 236 if (member->getMemberState() != kAppleRAIDMemberStateClosed) { 237 IOLog1("AppleRAIDSet::addMember(%p) member is not closed.\n", member); 238 member->changeMemberState(kAppleRAIDMemberStateBroken); 239 return false; 240 } 241 242 // check the current state of the raid set, can we accept another member? 243 if (arActiveCount >= arMemberCount) { 244 IOLog("AppleRAIDSet::addMember() too many members, active = %u, count = %u, member = %s\n", 245 (uint32_t)arActiveCount, (uint32_t)arMemberCount, member->getUUIDString()); 246 member->changeMemberState(kAppleRAIDMemberStateSpare); 247 return false; 248 } 249 250 // double check, can the set take more members? 251 // degraded sets should reject new members unless paused 252 if (getSetState() >= kAppleRAIDSetStateOnline && !arSetIsPaused) { 253 IOLog("AppleRAIDSet::addMember() set already started, ignoring new member %s\n", member->getUUIDString()); 254 member->changeMemberState(kAppleRAIDMemberStateSpare); 255 return false; 256 } 257 258 OSNumber * number; 259 number = OSDynamicCast(OSNumber, member->getHeaderProperty(kAppleRAIDHeaderVersionKey)); 260 if (!number) return false; 261 UInt32 memberHeaderVersion = number->unsigned32BitValue(); 262 263 // double check that this member is a part of the set, only for v2 headers 264 OSArray * memberUUIDs = OSDynamicCast(OSArray, getProperty(kAppleRAIDMembersKey)); 265 if (memberUUIDs) { 266 const OSString * uuid = member->getUUID(); 267 if (!uuid) return false; 268 bool foundit = false; 269 for (UInt32 i = 0; i < arMemberCount; i++) { 270 271 if (uuid->isEqualTo(memberUUIDs->getObject(i))) { 272 foundit = arMembers[i] == 0; 273 } 274 if (foundit) break; 275 } 276 if (!foundit) return false; 277 } 278 279 // no mix and match header versions 280 if (memberHeaderVersion != arHeaderVersion) { 281 IOLog("AppleRAIDSet::addMember() header version mismatch for member %s\n", 282 member->getUUIDString()); 283 // just punt, this is fatal and requires user interaction 284 // it is possible to get here during a failed set upgrade 285 changeSetState(kAppleRAIDSetStateFailed); 286 member->changeMemberState(kAppleRAIDMemberStateBroken); 287 return false; 288 } 289 290 number = OSDynamicCast(OSNumber, member->getHeaderProperty(kAppleRAIDSequenceNumberKey)); 291 if (!number) return false; 292 UInt32 memberSequenceNumber = number->unsigned32BitValue(); 293 UInt32 memberIndex = member->getMemberIndex(); 294 295 // Don't use members that have sequence numbers older than the raid set. 296 if (memberSequenceNumber < arSequenceNumber) { 297 IOLog("AppleRAIDSet::addMember() detected expired sequenceNumber (%u) for member %s\n", 298 (uint32_t)memberSequenceNumber, member->getUUIDString()); 299 member->changeMemberState(kAppleRAIDMemberStateSpare); 300 return false; 301 } 302 303 // If this new member is newer than the others then remove the old ones. 304 if (memberSequenceNumber > arSequenceNumber) { 305 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 306 if (arMembers[cnt] != 0) { 307 308 OSNumber * number = OSDynamicCast(OSNumber, arMembers[cnt]->getHeaderProperty(kAppleRAIDSequenceNumberKey)); 309 if (number) { 310 IOLog("AppleRAIDSet::addMember() detected expired sequenceNumber (%u) for member %s\n", 311 number->unsigned32BitValue(), arMembers[cnt]->getUUIDString()); 312 } 313 AppleRAIDMember * expiredMember = arMembers[cnt]; 314 removeMember(arMembers[cnt], 0); 315 expiredMember->changeMemberState(kAppleRAIDMemberStateSpare); 316 addSpare(expiredMember); 317 } 318 } 319 320 // we may have removed everything 321 if (arActiveCount == 0) { 322 arSetState = kAppleRAIDSetStateInitializing; 323 setProperty(kAppleRAIDStatusKey, kAppleRAIDStatusOffline); 324 initWithHeader(member->getHeader(), true); 325 } 326 327 // Update the raid set's sequence number. 328 arSequenceNumber = memberSequenceNumber; 329 330 // reset the block count 331 arSetBlockCount = 0; 332 333 // calculate the max size for the primary data, the primary data is always the 334 // same size but may be at different offsets depending on the type of raid set 335 assert(arPrimaryMetaDataMax ? (arPrimaryMetaDataMax == member->getPrimaryMaxSize()) : 1); 336 arPrimaryMetaDataMax = member->getPrimaryMaxSize(); 337 } 338 339 // Make sure this is the only member in this slot. 340 if (arMembers[memberIndex] != 0) { 341 IOLog("AppleRAIDSet::addMember() detected the same member index (%u) twice?\n", (uint32_t)memberIndex); 342 // take the entire set set offline, this is fatal 343 changeSetState(kAppleRAIDSetStateFailed); 344 member->changeMemberState(kAppleRAIDMemberStateBroken); 345 return false; 346 } 347 348 // 349 // at this point we should have a valid member 350 // 351 352 // Save the AppleRAIDMember in the raid set. 353 arMembers[memberIndex] = member; 354 355 if (!this->attach(member)) { 356 IOLog1("AppleRAIDSet::addMember(%p) this->attach(%p) failed\n", this, member); 357 member->changeMemberState(kAppleRAIDMemberStateBroken); 358 return false; 359 } 360 361 // Count this member as started. 362 arActiveCount++; 363 364 IOLog1("AppleRAIDSet::addMember(%p) was successful.\n", member); 365 366 return true; 367} 368 369// this also removes spares 370 371bool AppleRAIDSet::removeMember(AppleRAIDMember * member, IOOptionBits options) 372{ 373 IOLog1("AppleRAIDSet::removeMember(%p) called\n", member); 374 375 assert(gAppleRAIDGlobals.islocked()); 376 377 bool shouldBeClosed = member->changeMemberState(kAppleRAIDMemberStateClosing); 378 379 // spares are not open 380 if (shouldBeClosed) member->close(this, options); 381 382 member->changeMemberState(kAppleRAIDMemberStateClosed); 383 384 UInt32 memberIndex = member->getMemberIndex(); 385 386 if (arMembers[memberIndex] == member) { 387 arMembers[memberIndex] = 0; 388 arActiveCount--; 389 } 390 391 arSpareMembers->removeObject(member); 392 393 this->detach(member); 394 395 return true; 396} 397 398 399bool AppleRAIDSet::upgradeMember(AppleRAIDMember *member) 400{ 401 IOLog1("AppleRAIDSet::upgradeMember(%p) entered.\n", this); 402 403 // this is running in the workloop (when called from rebuildComplete) 404 405 // the set is paused 406 assert(arSetIsPaused); 407 408 // update member & spare uuid lists in raid headers, only for v2 headers 409 OSArray * memberUUIDs = OSDynamicCast(OSArray, getProperty(kAppleRAIDMembersKey)); 410 OSArray * spareUUIDs = OSDynamicCast(OSArray, getProperty(kAppleRAIDSparesKey)); 411 for (UInt32 i = 0; i < arMemberCount; i++) { 412 if (arMembers[i]) { 413 arMembers[i]->setHeaderProperty(kAppleRAIDMembersKey, memberUUIDs); 414 arMembers[i]->setHeaderProperty(kAppleRAIDSparesKey, spareUUIDs); 415 } 416 } 417 418 // fix up the member 419 member->setHeaderProperty(kAppleRAIDMemberTypeKey, kAppleRAIDMembersKey); 420 member->setHeaderProperty(kAppleRAIDSequenceNumberKey, arSequenceNumber, 32); 421 member->setHeaderProperty(kAppleRAIDMembersKey, memberUUIDs); 422 member->setHeaderProperty(kAppleRAIDSparesKey, spareUUIDs); 423 424 // add member into the raid set (special cased for paused sets) 425 if (!addMember(member)) return false; 426 427 // force it open (if needed) 428 if (arOpenReaderWriters->getCount() || arOpenReaders->getCount()) { 429 IOStorageAccess level = arOpenReaderWriters->getCount() ? kIOStorageAccessReaderWriter : kIOStorageAccessReader; 430 IOLog1("AppleRAIDSet::upgradeMember(%p) opening for read%s.\n", this, arOpenReaderWriters->getCount() ? "/write" : " only"); 431 if (!member->open(this, 0, level)) { 432 IOLog("AppleRAIDSet::upgradeMember(%p) open failed.\n", this); 433 return false; 434 } 435 } 436 437 return true; 438} 439 440//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 441//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 442//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 443 444 445bool AppleRAIDSet::resizeSet(UInt32 newMemberCount) 446{ 447 AppleRAIDMember **oldMembers = 0; 448 449 IOLog1("AppleRAIDSet::resizeSet(%p) entered. alloc = %d old = %d new = %d\n", 450 this, (int)arLastAllocCount, (int)arMemberCount, (int)newMemberCount); 451 452 UInt32 oldMemberCount = arMemberCount; 453 454 // if downsizing, just hold on to the extra space 455 if (arLastAllocCount && (arLastAllocCount >= newMemberCount)) { 456 arMemberCount = newMemberCount; 457 // zero out the deleted stuff; 458 for (UInt32 i = newMemberCount; i < arLastAllocCount; i++) { 459 arMembers[i] = NULL; 460 } 461 return true; 462 } 463 464 // back up the old member info if we need to increase the set size 465 if (arLastAllocCount) { 466 oldMembers = arMembers; 467 } 468 469 arMembers = IONew(AppleRAIDMember *, newMemberCount); 470 if (!arMembers) return false; 471 472 // Clear the new arrays. 473 bzero(arMembers, sizeof(AppleRAIDMember *) * newMemberCount); 474 475 // copy the old into the new, if needed 476 if (arLastAllocCount) { 477 bcopy(oldMembers, arMembers, sizeof(AppleRAIDMember *) * oldMemberCount); 478 IODelete(oldMembers, AppleRAIDMember *, arLastAllocCount); 479 } 480 481 arLastAllocCount = newMemberCount; 482 arMemberCount = newMemberCount; 483 484 IOLog1("AppleRAIDSet::resizeSet(%p) successful\n", this); 485 486 return true; 487} 488 489 490UInt32 AppleRAIDSet::nextSetState(void) 491{ 492 if (isSetComplete()) { 493 return kAppleRAIDSetStateOnline; 494 } 495 496 if (arActiveCount == 0 && getSpareCount() == 0) { 497 IOLog1("AppleRAIDSet::nextSetState: %p is empty, setting state to terminating.\n", this); 498 return kAppleRAIDSetStateTerminating; 499 } 500 501 if (getSetState() != kAppleRAIDSetStateInitializing) { 502 IOLog1("AppleRAIDSet::nextSetState: set \"%s\" failed to come online.\n", getSetNameString()); 503 } 504 505 return kAppleRAIDSetStateInitializing; 506} 507 508 509UInt64 AppleRAIDSet::getSmallestMaxByteCount(void) 510{ 511 UInt64 minimum = MAXBSIZE; // currently 1MB 512 UInt64 newMinimum; 513 514 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 515 AppleRAIDMember * target = arMembers[cnt]; 516 if (target) { 517 518 newMinimum = 0; 519 520 OSNumber * number = OSDynamicCast(OSNumber, target->getProperty(kIOMaximumByteCountReadKey, gIOServicePlane)); 521 if (number) { 522 newMinimum = number->unsigned64BitValue(); 523 if (newMinimum) minimum = min(minimum, newMinimum); 524 } 525 526 if (!newMinimum) { 527 OSNumber * number = OSDynamicCast(OSNumber, target->getProperty(kIOMaximumBlockCountReadKey, gIOServicePlane)); 528 if (number) { 529 newMinimum = number->unsigned64BitValue() * 512; 530 if (newMinimum) minimum = min(minimum, newMinimum); 531 } 532 } 533 } 534 } 535 536 return minimum; 537} 538 539void AppleRAIDSet::setSmallest64BitMemberPropertyFor(const char * key, UInt32 multiplier) 540{ 541 UInt64 minimum = UINT64_MAX; 542 543 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 544 AppleRAIDMember * target = arMembers[cnt]; 545 if (target) { 546 OSNumber * number = OSDynamicCast(OSNumber, target->getProperty(key, gIOServicePlane)); 547 if (number) { 548 UInt64 newMinimum = number->unsigned64BitValue(); 549 if (newMinimum) minimum = min(minimum, newMinimum); 550 } 551 } 552 } 553 554 if (minimum < UINT64_MAX) { 555 setProperty(key, minimum * multiplier, 64); 556 } else { 557 removeProperty(key); 558 } 559} 560 561 562void AppleRAIDSet::setLargest64BitMemberPropertyFor(const char * key, UInt32 multiplier) 563{ 564 UInt64 maximum = 0; 565 566 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 567 AppleRAIDMember * target = arMembers[cnt]; 568 if (target) { 569 OSNumber * number = OSDynamicCast(OSNumber, target->getProperty(key, gIOServicePlane)); 570 if (number) { 571 UInt64 newMaximum = number->unsigned64BitValue(); 572 if (newMaximum) maximum = max(maximum, newMaximum); 573 } 574 } 575 } 576 577 if (maximum > 0) { 578 setProperty(key, maximum * multiplier, 64); 579 } else { 580 removeProperty(key); 581 } 582} 583 584 585bool AppleRAIDSet::startSet(void) 586{ 587 IOLog1("AppleRAIDSet::startSet %p called with %u of %u members (%u spares).\n", 588 this, (uint32_t)arActiveCount, (uint32_t)arMemberCount, (uint32_t)getSpareCount()); 589 590 // if terminating, stay that way 591 if (getSetState() <= kAppleRAIDSetStateTerminating) { 592 IOLog1("AppleRAIDSet::startSet: the set \"%s\" is terminating or broken (%d).\n", getSetNameString(), (int)getSetState()); 593 return false; 594 } 595 596 // update set status 597 UInt32 nextState = nextSetState(); 598 changeSetState(nextState); 599 if (nextState < kAppleRAIDSetStateOnline) { 600 IOLog1("AppleRAIDSet::startSet %p was unsuccessful.\n", this); 601 return false; 602 } 603 604 // clean out the old storage requests and their memory descriptors 605 606 if (arStorageRequestPool && arSetIsPaused) { 607 assert(arStorageRequestsPending == 0); 608 while (1) { 609 AppleRAIDStorageRequest * storageRequest; 610 storageRequest = (AppleRAIDStorageRequest *)arStorageRequestPool->getCommand(false); 611 if (storageRequest == 0) break; 612 storageRequest->release(); 613 } 614 arStorageRequestPool->release(); 615 arStorageRequestPool = 0; 616 } 617 618 // Create and populate the storage request pool. 619 620 if (!arStorageRequestPool) { 621 622 // XXX fix this? looks like the code always calls getCommand with false 623 // XXX while already inside the workloop, just use fCommandChain directly ? 624 625 arStorageRequestPool = IOCommandPool::withWorkLoop(getWorkLoop()); 626 if (arStorageRequestPool == 0) return kIOReturnNoMemory; 627 for (UInt32 cnt = 0; cnt < kAppleRAIDStorageRequestCount; cnt++) { 628 629 AppleRAIDStorageRequest * storageRequest; 630 if (OSDynamicCast(AppleLVMGroup, this)) { 631 storageRequest = AppleLVMStorageRequest::withAppleRAIDSet(this); 632 } else { 633 storageRequest = AppleRAIDStorageRequest::withAppleRAIDSet(this); 634 } 635 if (storageRequest == 0) break; 636 arStorageRequestPool->returnCommand(storageRequest); 637 } 638 } 639 640 // (re)calculate ejectable and writeable, ... 641 642 arIsWritable = true; 643 arIsEjectable = true; 644 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 645 646 // if any members are not ejectable/writable turn off the entire set 647 648 if (arMembers[cnt] && (arMembers[cnt]->getMemberState() >= kAppleRAIDMemberStateClosed)) { 649 if (!arMembers[cnt]->isEjectable()) arIsEjectable = false; 650 if (!arMembers[cnt]->isWritable()) arIsWritable = false; 651 } 652 } 653 654 setSmallest64BitMemberPropertyFor(kIOMaximumBlockCountReadKey, 1); 655 setSmallest64BitMemberPropertyFor(kIOMaximumBlockCountWriteKey, 1); 656 setSmallest64BitMemberPropertyFor(kIOMaximumByteCountReadKey, 1); 657 setSmallest64BitMemberPropertyFor(kIOMaximumByteCountWriteKey, 1); 658 659 setSmallest64BitMemberPropertyFor(kIOMaximumSegmentCountReadKey, 1); 660 setSmallest64BitMemberPropertyFor(kIOMaximumSegmentCountWriteKey, 1); 661 setSmallest64BitMemberPropertyFor(kIOMaximumSegmentByteCountReadKey, 1); // don't scale this 662 setSmallest64BitMemberPropertyFor(kIOMaximumSegmentByteCountWriteKey, 1); // don't scale this 663 664 setLargest64BitMemberPropertyFor(kIOMinimumSegmentAlignmentByteCountKey, 1); // don't scale this 665 setSmallest64BitMemberPropertyFor(kIOMaximumSegmentAddressableBitCountKey, 1); // don't scale this 666 667 IOLog1("AppleRAIDSet::startSet %p was successful.\n", this); 668 return true; 669} 670 671 672bool AppleRAIDSet::publishSet(void) 673{ 674 IOLog1("AppleRAIDSet::publishSet called %p\n", this); 675 676 // are we (still) connected to the io registry? 677 if (arActiveCount == 0 && getSpareCount() == 0) { 678 IOLog1("AppleRAIDSet::publishSet: the set %p is empty, aborting.\n", this); 679 return false; 680 } 681 682 if (getSetState() < kAppleRAIDSetStateOnline || isRAIDMember()) { 683 IOLog1("AppleRAIDSet::publishSet: skipping offline or stacked raid set.\n"); 684 unpublishSet(); 685 return true; 686 } 687 688 // logical volume groups do not export a media object 689 const char * contentHint = 0; 690 OSString * theHint = OSDynamicCast(OSString, getProperty(kAppleRAIDSetContentHintKey)); 691 if (theHint) { 692 if (theHint->isEqualTo(kAppleRAIDNoMediaExport)) { 693 IOLog1("AppleRAIDSet::publishSet: shortcircuiting publish for no media set.\n"); 694 return true; 695 } 696 contentHint = theHint->getCStringNoCopy(); 697 } 698 699 // Create the member object for the raid set. 700 bool firstTime = false; 701 if (arMedia) { 702 arMedia->retain(); 703 } else { 704 arMedia = new IOMedia; 705 firstTime = true; 706 } 707 708 if (arMedia) { 709 710 IOMediaAttributeMask attributes = arIsEjectable ? (kIOMediaAttributeEjectableMask | kIOMediaAttributeRemovableMask) : 0; 711 if (arMedia->init(/* base */ 0, 712 /* size */ arSetMediaSize, 713 /* preferredBlockSize */ arNativeBlockSize, 714 /* attributes */ attributes, 715 /* isWhole */ true, 716 /* isWritable */ arIsWritable, 717 /* contentHint */ contentHint)) { 718 719 arMedia->setName(getSetNameString()); 720 721 // Set a location value (partition number) for this partition. 722 char location[12]; 723 snprintf(location, sizeof(location), "%d", 0); 724 arMedia->setLocation(location); 725 726 OSArray * bootArray = OSArray::withCapacity(arMemberCount); 727 if (bootArray) { 728 // if any of the devices are not in the device tree 729 // just return an empty array 730 (void)addBootDeviceInfo(bootArray); 731 arMedia->setProperty(kIOBootDeviceKey, bootArray); 732 bootArray->release(); 733 } 734 735 arMedia->setProperty(kIOMediaUUIDKey, (OSObject *)getUUID()); 736 arMedia->setProperty(kAppleRAIDIsRAIDKey, kOSBooleanTrue); 737 if (getSetState() < kAppleRAIDSetStateOnline || isRAIDMember()) { 738 arMedia->setProperty("autodiskmount", kOSBooleanFalse); 739 } else { 740 arMedia->removeProperty("autodiskmount"); 741 } 742 743 if (firstTime) { 744 arMedia->attach(this); 745 arMedia->registerService(); 746 } else { 747 arMedia->messageClients(kIOMessageServicePropertyChange); 748 } 749 } 750 } else { 751 IOLog("AppleRAIDSet::publishSet(void): failed for set \"%s\" (%s)\n", getSetNameString(), getUUIDString()); 752 } 753 754 if (arMedia) arMedia->release(); 755 756 IOLog1("AppleRAIDSet::publishSet: was %ssuccessful.\n", arMedia ? "" : "un"); 757 return arMedia != NULL; 758} 759 760 761bool AppleRAIDSet::unpublishSet(void) 762{ 763 bool success = true; 764 765 IOLog1("AppleRAIDSet::unpublishSet(%p) entered, arMedia = %p\n", this, arMedia); 766 767 if (arMedia) { 768 success = arMedia->terminate(kIOServiceRequired | kIOServiceSynchronous); 769 arMedia = 0; 770 } 771 772 return success; 773} 774 775bool AppleRAIDSet::destroySet(void) 776{ 777 IOLog1("AppleRAIDSet::destroySet(%p) entered.\n", this); 778 779 assert(gAppleRAIDGlobals.islocked()); 780 781 if (isRAIDMember()) { 782 IOLog("AppleRAIDSet::destroySet() failed, an attempt was made to destroy subordinate set\n"); 783 return false; 784 } 785 786 // zero headers on members 787 for (UInt32 i = 0; i < arMemberCount; i++) { 788 if (arMembers[i]) { 789 (void)arMembers[i]->zeroRAIDHeader(); 790 if (arMembers[i]->getMemberState() == kAppleRAIDMemberStateRebuilding) { 791 arMembers[i]->changeMemberState(kAppleRAIDMemberStateSpare, true); 792 while (arMembers[i]->getMemberState() == kAppleRAIDMemberStateSpare) { 793 IOSleep(50); 794 } 795 // drag member back to spare list, keeping it attached, ** active count doesn't change ** 796 AppleRAIDMember * member = arMembers[i]; 797 arMembers[i] = 0; 798 arSpareMembers->setObject(member); 799 } 800 } 801 } 802 803 // zero headers on spares 804 OSCollectionIterator * iter = OSCollectionIterator::withCollection(arSpareMembers); 805 if (!iter) return false; 806 while (AppleRAIDMember * spare = (AppleRAIDMember *)iter->getNextObject()) { 807 (void)spare->zeroRAIDHeader(); 808 } 809 iter->release(); 810 811 // this keeps us from bumping sequence numbers on the way down 812 changeSetState(kAppleRAIDSetStateTerminating); 813 814 // remove the members from the set 815 for (UInt32 i = 0; i < arMemberCount; i++) { 816 if (arMembers[i]) { 817 if (arMembers[i]->isRAIDSet()) { 818 arController->oldMember(arMembers[i]); 819 } else { 820 arMembers[i]->stop(NULL); 821 } 822 } 823 } 824 825 // remove the spares from the set 826 // make a copy since this changes the spare list 827 OSSet * copy = OSSet::withSet(arSpareMembers, arSpareMembers->getCount()); 828 if (!copy) return false; 829 while (AppleRAIDMember * spare = (AppleRAIDMember *)copy->getAnyObject()) { 830 copy->removeObject(spare); 831 if (spare->isRAIDSet()) { 832 arController->oldMember(spare); 833 } else { 834 spare->stop(NULL); 835 } 836 } 837 copy->release(); 838 839 IOLog1("AppleRAIDSet::destroySet(%p) was successful.\n", this); 840 841 return true; 842} 843 844 845bool AppleRAIDSet::reconfigureSet(OSDictionary * updateInfo) 846{ 847 bool updateHeader = false; 848 UInt32 newMemberCount = arMemberCount; 849 850 IOLog1("AppleRAIDSet::reconfigureSet(%p) entered.\n", this); 851 852 OSString * deleted = OSString::withCString(kAppleRAIDDeletedUUID); 853 if (!deleted) return false; 854 855 OSArray * oldMemberList = OSDynamicCast(OSArray, getProperty(kAppleRAIDMembersKey)); 856 OSArray * newMemberList = OSDynamicCast(OSArray, updateInfo->getObject(kAppleRAIDMembersKey)); 857 858 if (oldMemberList && newMemberList) { 859 860 IOLog1("AppleRAIDSet::reconfigureSet(%p) updating member list.\n", this); 861 862 assert(arMemberCount == oldMemberList->getCount()); 863 864 // look for kAppleRAIDDeletedUUID 865 for (UInt32 i = 0; i < newMemberCount; i++) { 866 867 OSString * uuid = OSDynamicCast(OSString, newMemberList->getObject(i)); 868 869 if (uuid && (uuid->isEqualTo(deleted))) { 870 871 if (arMembers[i]) { 872 arMembers[i]->zeroRAIDHeader(); 873 if (arMembers[i]->getMemberState() == kAppleRAIDMemberStateRebuilding) { 874 // hack, this will cause the rebuild to abort 875 arMembers[i]->changeMemberState(kAppleRAIDMemberStateSpare, true); 876 while (arMembers[i]->getMemberState() == kAppleRAIDMemberStateSpare) { 877 arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::unpauseSet)); 878 IOSleep(50); 879 arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::pauseSet), (void *)false); 880 } 881 // drag member back to spare list, keeping it attached, ** active count doesn't change ** 882 AppleRAIDMember * member = arMembers[i]; 883 arMembers[i] = 0; 884 arSpareMembers->setObject(member); 885 if (member->isRAIDSet()) { 886 arController->oldMember(member); 887 } else { 888 member->stop(NULL); 889 } 890 } else { 891 if (arMembers[i]->isRAIDSet()) { 892 arController->oldMember(arMembers[i]); 893 } else { 894 arMembers[i]->stop(NULL); 895 } 896 } 897 } else { 898 // if the member is broken it might be in the spare list 899 OSString * olduuid = OSDynamicCast(OSString, oldMemberList->getObject(i)); 900 OSCollectionIterator * iter = OSCollectionIterator::withCollection(arSpareMembers); 901 if (!iter) return false; 902 903 while (AppleRAIDMember * spare = (AppleRAIDMember *)iter->getNextObject()) { 904 if (spare->getUUID()->isEqualTo(olduuid)) { 905 spare->zeroRAIDHeader(); 906 if (spare->isRAIDSet()) { 907 arController->oldMember(spare); 908 } else { 909 spare->stop(NULL); 910 } 911 break; 912 } 913 } 914 iter->release(); 915 } 916 917 // slide everything in one to fill the deleted spot 918 newMemberCount--; 919 newMemberList->removeObject(i); 920 for (UInt32 j = i; j < newMemberCount; j++) { 921 arMembers[j] = arMembers[j + 1]; 922 if (arMembers[j]) arMembers[j]->setMemberIndex(j); 923 } 924 925 break; // XXX this can only delete one member, the interface allows for more 926 } 927 } 928 929 // this catches new member adds, resizeSet() fixes arMemberCount below 930 newMemberCount = newMemberList->getCount(); 931 932 setProperty(kAppleRAIDMembersKey, newMemberList); 933 updateInfo->removeObject(kAppleRAIDMembersKey); 934 updateHeader = true; 935 } 936 937 OSArray * oldSpareList = OSDynamicCast(OSArray, getProperty(kAppleRAIDSparesKey)); 938 OSArray * newSpareList = OSDynamicCast(OSArray, updateInfo->getObject(kAppleRAIDSparesKey)); 939 if (oldSpareList && newSpareList) { 940 941 IOLog1("AppleRAIDSet::reconfigureSet(%p) updating spare list.\n", this); 942 943 // look for kAppleRAIDDeletedUUID in new list 944 UInt32 spareCount = newSpareList->getCount(); 945 for (UInt32 i = 0; i < spareCount; i++) { 946 947 OSString * uuid = OSDynamicCast(OSString, newSpareList->getObject(i)); 948 if (!uuid || !uuid->isEqualTo(deleted)) continue; 949 950 // remove "deleted uuid" from the new list 951 newSpareList->removeObject(i); 952 953 // get the old uuid based on the position of the deleted uuid marker 954 OSString * olduuid = OSDynamicCast(OSString, oldSpareList->getObject(i)); 955 if (!olduuid) return false; 956 957 // Find && nuke the old spare 958 OSCollectionIterator * iter = OSCollectionIterator::withCollection(arSpareMembers); 959 if (!iter) return false; 960 961 while (AppleRAIDMember * spare = (AppleRAIDMember *)iter->getNextObject()) { 962 if (spare->getUUID()->isEqualTo(olduuid)) { 963 spare->zeroRAIDHeader(); 964 if (spare->isRAIDSet()) { 965 arController->oldMember(spare); 966 } else { 967 spare->stop(NULL); 968 } 969 break; 970 } 971 } 972 iter->release(); 973 974 break; // XXX this can only delete one spare, the interface allows for more 975 } 976 setProperty(kAppleRAIDSparesKey, newSpareList); 977 updateInfo->removeObject(kAppleRAIDSparesKey); 978 updateHeader = true; 979 } 980 deleted->release(); 981 982 // pull out the remaining stuff 983 if (updateInfo->getCount()) { 984 initWithHeader(updateInfo, false); 985 updateHeader = true; 986 } 987 988 // newMemberCount will be zero when deleting last member 989 if (newMemberCount != arMemberCount) { 990 991 resizeSet(newMemberCount); 992 993 // update the shadow member count 994 OSNumber * number = OSNumber::withNumber(newMemberCount, 32); 995 if (number) { 996 updateInfo->setObject(kAppleRAIDMemberCountKey, number); 997 number->release(); 998 } 999 } 1000 1001 if (updateHeader) { 1002 1003 changeSetState(kAppleRAIDSetStateInitializing); 1004 1005 OSArray * memberUUIDs = OSDynamicCast(OSArray, getProperty(kAppleRAIDMembersKey)); 1006 OSArray * spareUUIDs = OSDynamicCast(OSArray, getProperty(kAppleRAIDSparesKey)); 1007 for (UInt32 i = 0; i < arMemberCount; i++) { 1008 if (arMembers[i]) { 1009 1010 // merge new properties into each member 1011 arMembers[i]->updateRAIDHeader(updateInfo); 1012 1013 // update member & spare uuid lists in raid headers, only for v2 headers 1014 arMembers[i]->setHeaderProperty(kAppleRAIDMembersKey, memberUUIDs); 1015 arMembers[i]->setHeaderProperty(kAppleRAIDSparesKey, spareUUIDs); 1016 } 1017 } 1018 } 1019 1020 return true; 1021} 1022 1023 1024//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1025//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1026//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1027 1028UInt32 AppleRAIDSet::getSequenceNumber() 1029{ 1030 return arSequenceNumber; 1031} 1032 1033void AppleRAIDSet::bumpSequenceNumber(void) 1034{ 1035 UInt32 cnt; 1036 1037 assert(gAppleRAIDGlobals.islocked()); 1038 1039 arSequenceNumber++; 1040 1041 IOLog1("AppleRAIDSet::bumpSequenceNumber(%p) bumping to %u\n", this, (uint32_t)arSequenceNumber); 1042 1043 for (cnt = 0; cnt < arMemberCount; cnt++) { 1044 1045 if (arMembers[cnt]) { 1046 arMembers[cnt]->setHeaderProperty(kAppleRAIDSequenceNumberKey, arSequenceNumber, 32); 1047 } 1048 } 1049} 1050 1051IOReturn AppleRAIDSet::writeRAIDHeader(void) 1052{ 1053 UInt32 cnt; 1054 IOReturn rc = kIOReturnSuccess, rc2; 1055 1056 IOLog1("AppleRAIDSet::writeRAIDHeader(%p) entered.\n", this); 1057 1058 assert(gAppleRAIDGlobals.islocked()); 1059 1060 if ((arActiveCount == 0) || getSetState() <= kAppleRAIDSetStateTerminating) { 1061 IOLog1("AppleRAIDSet::writeRAIDHeader(%p) ignoring request, the set is empty or broken/terminating.\n", this); 1062 return rc; 1063 } 1064 1065 // opening the set changes it's state 1066 UInt32 formerSetState = getSetState(); 1067 1068 // we need to be opened for write 1069 bool openedForWrite = arOpenReaderWriters->getCount() != 0; 1070 bool openedForRead = arOpenReaders->getCount() != 0; 1071 if (!openedForWrite) { 1072 IOLog1("AppleRAIDSet::writeRAIDHeader(%p): opening set for writing.\n", this); 1073 if (!open(this, 0, kIOStorageAccessReaderWriter)) return kIOReturnIOError; 1074 } 1075 1076 for (cnt = 0; cnt < arMemberCount; cnt++) { 1077 1078 if (!arMembers[cnt] || (arMembers[cnt]->getMemberState() < kAppleRAIDMemberStateOpen)) continue; 1079 1080 if (arMembers[cnt]->isRAIDSet() && (rc2 = arMembers[cnt]->AppleRAIDMember::writeRAIDHeader()) != kIOReturnSuccess) { 1081 IOLog("AppleRAIDSet::writeRAIDHeader() update failed on a set level on set \"%s\" (%s) member %s, rc = %x\n", 1082 getSetNameString(), getUUIDString(), arMembers[cnt]->getUUIDString(), rc2); 1083 rc = rc2; 1084 // keep going ... 1085 } 1086 1087 if ((rc2 = arMembers[cnt]->writeRAIDHeader()) != kIOReturnSuccess) { 1088 IOLog("AppleRAIDSet::writeRAIDHeader() update failed at member level on set \"%s\" (%s) member %s, rc = %x\n", 1089 getSetNameString(), getUUIDString(), arMembers[cnt]->getUUIDString(), rc2); 1090 rc = rc2; 1091 // keep going ... 1092 } 1093 } 1094 1095 if (!openedForWrite) { 1096 if (!openedForRead) { 1097 IOLog1("AppleRAIDSet::writeRAIDHeader(%p): closing set.\n", this); 1098 close(this, 0); 1099 } else { 1100 IOLog1("AppleRAIDSet::writeRAIDHeader(%p): downgrading set to read only.\n", this); 1101 if (!open(this, 0, kIOStorageAccessReader)) { // downgrades should "always" work 1102 IOLog1("AppleRAIDSet::writeRAIDHeader(%p): downgrade back to RO failed.\n", this); 1103 changeSetState(kAppleRAIDSetStateFailed); 1104 return kIOReturnError; 1105 } 1106 } 1107 changeSetState(formerSetState); 1108 } 1109 IOLog1("AppleRAIDSet::writeRAIDHeader(%p) exiting with 0x%x.\n", this, rc); 1110 1111 return rc; 1112} 1113 1114//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1115//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1116//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1117 1118 1119 1120IOBufferMemoryDescriptor * AppleRAIDSet::readPrimaryMetaData(AppleRAIDMember * member) 1121{ 1122 if (!member) return NULL; 1123 return member->readPrimaryMetaData(); 1124} 1125 1126IOReturn AppleRAIDSet::writePrimaryMetaData(IOBufferMemoryDescriptor * primaryBuffer) 1127{ 1128 UInt32 cnt; 1129 IOReturn rc = kIOReturnSuccess, rc2; 1130 1131 IOLog1("AppleRAIDSet::writePrimaryMetaData(%p) entered.\n", this); 1132 1133 // XXX assert(gAppleRAIDGlobals.islocked()); 1134 1135 if ((arActiveCount == 0) || getSetState() <= kAppleRAIDSetStateTerminating) { 1136 IOLog1("AppleRAIDSet::writePrimaryMetaData(%p) ignoring request, the set is empty or broken/terminating.\n", this); 1137 return rc; 1138 } 1139 1140 // opening the set changes it's state 1141 UInt32 formerSetState = getSetState(); 1142 1143 // we need to be opened for write 1144 bool openedForWrite = arOpenReaderWriters->getCount() != 0; 1145 bool openedForRead = arOpenReaders->getCount() != 0; 1146 if (!openedForWrite) { 1147 IOLog1("AppleRAIDSet::writePrimaryMetaData(%p): opening set for writing.\n", this); 1148 if (!open(this, 0, kIOStorageAccessReaderWriter)) return kIOReturnIOError; 1149 } 1150 1151 for (cnt = 0; cnt < arMemberCount; cnt++) { 1152 1153 if (!arMembers[cnt] || (arMembers[cnt]->getMemberState() < kAppleRAIDMemberStateOpen)) continue; 1154 1155 if ((rc2 = arMembers[cnt]->writePrimaryMetaData(primaryBuffer)) != kIOReturnSuccess) { 1156 IOLog("AppleRAIDSet::writePrimaryMetaData() update failed on set \"%s\" (%s) member %s, rc = %x\n", 1157 getSetNameString(), getUUIDString(), arMembers[cnt]->getUUIDString(), rc2); 1158 rc = rc2; 1159 // keep going ... 1160 } 1161 } 1162 1163 if (!openedForWrite) { 1164 if (!openedForRead) { 1165 IOLog1("AppleRAIDSet::writePrimaryMetaData(%p): closing set.\n", this); 1166 close(this, 0); 1167 } else { 1168 IOLog1("AppleRAIDSet::writePrimaryMetaData(%p): downgrading set to read only.\n", this); 1169 if (!open(this, 0, kIOStorageAccessReader)) { // downgrades should "always" work 1170 IOLog1("AppleRAIDSet::writePrimaryMetaData(%p): downgrade back to RO failed.\n", this); 1171 changeSetState(kAppleRAIDSetStateFailed); 1172 return kIOReturnError; 1173 } 1174 } 1175 changeSetState(formerSetState); 1176 } 1177 IOLog1("AppleRAIDSet::writePrimaryMetaData(%p) exiting with 0x%x.\n", this, rc); 1178 1179 return rc; 1180} 1181 1182 1183// read into a buffer using member offsets 1184 1185bool AppleRAIDSet::readIntoBuffer(AppleRAIDMember * member, IOBufferMemoryDescriptor * buffer, UInt64 offset) 1186{ 1187 assert(buffer); 1188 assert(member); 1189 1190 // Open the whole set 1191 bool openedForRead = isOpen(); 1192 if (!openedForRead) { 1193 if (!getTarget()->open(this, 0, kIOStorageAccessReader)) return false; 1194 } 1195 1196 // Read into the buffer 1197 buffer->setDirection(kIODirectionIn); 1198 IOReturn rc = member->getTarget()->read(this, offset, buffer); 1199 1200 // Close the set 1201 if (!openedForRead) { 1202 getTarget()->close(this, 0); 1203 } 1204 1205 return rc == kIOReturnSuccess; 1206} 1207 1208// write from a buffer using member offsets 1209 1210IOReturn AppleRAIDSet::writeFromBuffer(AppleRAIDMember * member, IOBufferMemoryDescriptor * buffer, UInt64 offset) 1211{ 1212 IOReturn rc = kIOReturnSuccess; 1213 1214 IOLog1("AppleRAIDSet::writeFromBuffer(%p) entered.\n", this); 1215 1216// assert(gAppleRAIDGlobals.islocked()); 1217 1218 if ((arActiveCount == 0) || getSetState() <= kAppleRAIDSetStateTerminating) { 1219 IOLog1("AppleRAIDSet::writeFromBuffer(%p) ignoring request, the set is empty or broken/terminating.\n", this); 1220 return rc; 1221 } 1222 1223 // opening the set changes it's state 1224 UInt32 formerSetState = getSetState(); 1225 1226 // we need to be opened for write 1227 bool openedForWrite = arOpenReaderWriters->getCount() != 0; 1228 bool openedForRead = arOpenReaders->getCount() != 0; 1229 if (!openedForWrite) { 1230 IOLog1("AppleRAIDSet::writeFromBuffer(%p): opening set for writing.\n", this); 1231 if (!open(this, 0, kIOStorageAccessReaderWriter)) return kIOReturnIOError; 1232 } 1233 1234 buffer->setDirection(kIODirectionOut); 1235 rc = member->getTarget()->write(this, offset, buffer); 1236 1237 if (!openedForWrite) { 1238 if (!openedForRead) { 1239 IOLog1("AppleRAIDSet::writeFromBuffer(%p): closing set.\n", this); 1240 close(this, 0); 1241 } else { 1242 IOLog1("AppleRAIDSet::writeFromBuffer(%p): downgrading set to read only.\n", this); 1243 if (!open(this, 0, kIOStorageAccessReader)) { // downgrades should "always" work 1244 IOLog1("AppleRAIDSet::writeFromBuffer(%p): downgrade back to RO failed.\n", this); 1245 changeSetState(kAppleRAIDSetStateFailed); 1246 return kIOReturnError; 1247 } 1248 } 1249 changeSetState(formerSetState); 1250 } 1251 IOLog1("AppleRAIDSet::writeFromBuffer(%p) exiting with 0x%x.\n", this, rc); 1252 1253 return rc; 1254} 1255 1256 1257//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1258//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1259//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1260 1261 1262const OSString * AppleRAIDSet::getSetName(void) 1263{ 1264 return OSDynamicCast(OSString, getProperty(kAppleRAIDSetNameKey)); 1265} 1266 1267const OSString * AppleRAIDSet::getUUID(void) 1268{ 1269 return OSDynamicCast(OSString, getProperty(kAppleRAIDMemberUUIDKey)); 1270} 1271 1272const OSString * AppleRAIDSet::getSetUUID(void) 1273{ 1274 return OSDynamicCast(OSString, getProperty(kAppleRAIDSetUUIDKey)); 1275} 1276 1277const OSString * AppleRAIDSet::getDiskName(void) 1278{ 1279 return arMedia ? OSDynamicCast(OSString, arMedia->getProperty(kIOBSDNameKey)) : NULL; 1280} 1281 1282//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1283//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1284//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1285 1286IOStorage * AppleRAIDSet::getTarget(void) const 1287{ 1288 return (IOStorage *)this; 1289} 1290 1291bool AppleRAIDSet::isRAIDSet(void) 1292{ 1293 return true; 1294} 1295 1296bool AppleRAIDSet::isSetComplete(void) 1297{ 1298 return arActiveCount == arMemberCount; 1299} 1300 1301bool AppleRAIDSet::bumpOnError(void) 1302{ 1303 return false; 1304} 1305 1306UInt64 AppleRAIDSet::getSize() const 1307{ 1308 return arSetMediaSize; 1309} 1310 1311IOWorkLoop * AppleRAIDSet::getWorkLoop(void) 1312{ 1313 // Create a WorkLoop if it has not already been done. 1314 if (arSetWorkLoop == 0) { 1315 arSetWorkLoop = IOWorkLoop::workLoop(); 1316 } 1317 1318 return arSetWorkLoop; 1319} 1320 1321bool AppleRAIDSet::changeSetState(UInt32 newState) 1322{ 1323 bool swapState = false; 1324 const char *newStatus = "bogus"; 1325 1326#ifdef DEBUG 1327 const char *oldStatus = "not set"; 1328 OSString *oldStatusString = OSDynamicCast(OSString, getProperty(kAppleRAIDStatusKey)); 1329 if (oldStatusString) oldStatus = oldStatusString->getCStringNoCopy(); 1330#endif 1331 1332 // short cut 1333 if (arSetState == newState) return true; 1334 1335 switch (newState) { 1336 1337 case kAppleRAIDSetStateFailed: // 0 1338 swapState = true; 1339 newStatus = kAppleRAIDStatusFailed; 1340 break; 1341 1342 case kAppleRAIDSetStateTerminating: // 1 1343 swapState = arSetState > kAppleRAIDSetStateFailed; 1344 newStatus = kAppleRAIDStatusOffline; 1345 break; 1346 1347 case kAppleRAIDSetStateInitializing: // 2 1348 swapState = arSetState > kAppleRAIDSetStateTerminating; 1349 newStatus = kAppleRAIDStatusOffline; 1350 break; 1351 1352 case kAppleRAIDSetStateOnline: // 3 1353 swapState = arSetState >= kAppleRAIDSetStateInitializing; 1354 newStatus = kAppleRAIDStatusOnline; 1355 break; 1356 1357 case kAppleRAIDSetStateDegraded: // 4 1358 swapState = arSetState >= kAppleRAIDSetStateInitializing; 1359 newStatus = kAppleRAIDStatusDegraded; 1360 break; 1361 1362 default: 1363 IOLog("AppleRAIDSet::changeSetState() this \"%s\" (%s), bogus state %u?\n", 1364 getSetNameString(), getUUIDString(), (uint32_t)newState); 1365 } 1366 1367 if (swapState) { 1368 IOLog1("AppleRAIDSet::changeSetState(%p) from %u (%s) to %u (%s).\n", 1369 this, (uint32_t)arSetState, oldStatus, (uint32_t)newState, newStatus); 1370 1371 if (isRAIDMember()) { 1372 if ((newState >= kAppleRAIDSetStateOnline) && (newState > arSetState)) { 1373 if (getMemberState() >= kAppleRAIDMemberStateClosing) { 1374 changeMemberState(kAppleRAIDMemberStateOpen); 1375 } else { 1376 changeMemberState(kAppleRAIDMemberStateClosed); 1377 } 1378 } 1379 if ((newState < kAppleRAIDSetStateOnline) && (newState < arSetState)) { 1380 changeMemberState(kAppleRAIDMemberStateClosing); 1381 } 1382 } 1383 1384 arSetState = newState; 1385 setProperty(kAppleRAIDStatusKey, newStatus); 1386 messageClients(kAppleRAIDMessageSetChanged); 1387 1388 } else { 1389 IOLog1("AppleRAIDSet::changeSetState(%p) FAILED from %u (%s) to %u (%s).\n", 1390 this, (uint32_t)arSetState, oldStatus, (uint32_t)newState, newStatus); 1391 } 1392 1393 return swapState; 1394} 1395 1396//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1397//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1398//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1399 1400bool 1401AppleRAIDSet::addBootDeviceInfo(OSArray * bootArray) 1402{ 1403 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 1404 if (arMembers[cnt] != NULL) { 1405 if ((arMembers[cnt]->getMemberState() >= kAppleRAIDMemberStateClosed) && 1406 (arMembers[cnt]->getMemberState() != kAppleRAIDMemberStateRebuilding)) { 1407 1408 if (!arMembers[cnt]->addBootDeviceInfo(bootArray)) { 1409 // if any of the devices are not in the device tree 1410 // just return an empty array 1411 bootArray->flushCollection(); 1412 return false; 1413 } 1414 } 1415 } 1416 } 1417 1418 return true; 1419} 1420 1421 1422OSDictionary * AppleRAIDSet::getSetProperties(void) 1423{ 1424 OSNumber * tmpNumber; 1425 1426 OSDictionary * props = OSDictionary::withCapacity(32); 1427 if (!props) return NULL; 1428 1429 props->setObject(kAppleRAIDSetNameKey, getSetName()); 1430 props->setObject(kAppleRAIDSetUUIDKey, getUUID()); 1431 props->setObject(kAppleRAIDLevelNameKey, getProperty(kAppleRAIDLevelNameKey)); 1432 1433 tmpNumber = OSNumber::withNumber(arHeaderVersion, 32); 1434 if (tmpNumber) { 1435 props->setObject(kAppleRAIDHeaderVersionKey, tmpNumber); 1436 tmpNumber->release(); 1437 } 1438 1439 tmpNumber = OSNumber::withNumber(arSequenceNumber, 32); 1440 if (tmpNumber) { 1441 props->setObject(kAppleRAIDSequenceNumberKey, tmpNumber); 1442 tmpNumber->release(); 1443 } 1444 1445 tmpNumber = OSNumber::withNumber(arSetBlockSize, 64); 1446 if (tmpNumber) { 1447 props->setObject(kAppleRAIDChunkSizeKey, tmpNumber); 1448 tmpNumber->release(); 1449 } 1450 1451 tmpNumber = OSNumber::withNumber(arSetBlockCount, 64); 1452 if (tmpNumber) { 1453 props->setObject(kAppleRAIDChunkCountKey, tmpNumber); 1454 tmpNumber->release(); 1455 } 1456 1457 if (arPrimaryMetaDataUsed) { 1458 tmpNumber = OSNumber::withNumber(arPrimaryMetaDataUsed, 64); 1459 if (tmpNumber){ 1460 props->setObject(kAppleRAIDPrimaryMetaDataUsedKey, tmpNumber); 1461 tmpNumber->release(); 1462 } 1463 } 1464 props->setObject(kAppleRAIDSetContentHintKey, getProperty(kAppleRAIDSetContentHintKey)); 1465 1466 props->setObject(kAppleRAIDCanAddMembersKey, getProperty(kAppleRAIDCanAddMembersKey)); 1467 props->setObject(kAppleRAIDCanAddSparesKey, getProperty(kAppleRAIDCanAddSparesKey)); 1468 props->setObject(kAppleRAIDRemovalAllowedKey, getProperty(kAppleRAIDRemovalAllowedKey)); 1469 props->setObject(kAppleRAIDSizesCanVaryKey, getProperty(kAppleRAIDSizesCanVaryKey)); 1470 1471 // not from header 1472 1473 props->setObject(kAppleRAIDStatusKey, getProperty(kAppleRAIDStatusKey)); 1474 props->setObject(kIOBSDNameKey, getDiskName()); 1475 1476 // set up the members array, only v2 headers contain a list of the members 1477 OSArray * members = OSDynamicCast(OSArray, getProperty(kAppleRAIDMembersKey)); 1478 if (members) { 1479 1480 props->setObject(kAppleRAIDMembersKey, members); 1481 1482 } else { 1483 1484 members = OSArray::withCapacity(arMemberCount); 1485 if (members) { 1486 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 1487 if (arMembers[cnt] != 0) { 1488 const OSString * uuid = arMembers[cnt]->getUUID(); 1489 if (uuid) members->setObject(uuid); 1490 } else { 1491 OSString * uuid = OSString::withCString(kAppleRAIDMissingUUID); 1492 if (uuid) { 1493 members->setObject(uuid); 1494 uuid->release(); 1495 } 1496 } 1497 } 1498 props->setObject(kAppleRAIDMembersKey, members); 1499 members->release(); 1500 } 1501 } 1502 1503 // we don't worry about losing spares from this spare uuid list, 1504 // if they ever come online again they will be returned to the list 1505 OSArray * spares = OSArray::withCapacity(arMemberCount); 1506 OSCollectionIterator * iter = OSCollectionIterator::withCollection(arSpareMembers); 1507 if (spares && iter) { 1508 while (AppleRAIDMember * spare = (AppleRAIDMember *)iter->getNextObject()) { 1509 1510 const OSString * uuid = spare->getUUID(); 1511 assert(uuid); 1512 if (!uuid) continue; 1513 1514 // skip spares that are in the member list 1515 OSArray * members = (OSArray *)props->getObject(kAppleRAIDMembersKey); 1516 UInt32 memberCount = members ? members->getCount() : 0; 1517 bool foundIt = false; 1518 for (UInt32 cnt2 = 0; cnt2 < memberCount; cnt2++) { 1519 foundIt = members->getObject(cnt2)->isEqualTo(uuid); 1520 if (foundIt) break; 1521 } 1522 if (foundIt) continue; 1523 1524 // finally, add it to the spare list 1525 spares->setObject(uuid); 1526 } 1527 props->setObject(kAppleRAIDSparesKey, spares); 1528 setProperty(kAppleRAIDSparesKey, spares); // lazy update 1529 spares->release(); 1530 iter->release(); 1531 } 1532 1533 return props; 1534} 1535 1536 1537//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1538//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1539//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1540 1541// This code was lifted from IOPartitionScheme.cpp 1542// 1543// It has few major additions: 1544// 1) Instead of opening or closing one device it handles all the members in a set 1545// 2) Only logical volume groups allow more that one open for writing. 1546// 3) Rebuilding members are left writable even if the set is only open for read. 1547// 4) Opens are only allowed for sets that are online or degraded and at the top level. 1548 1549bool AppleRAIDSet::handleOpen(IOService * client, 1550 IOOptionBits options, 1551 void * argument) 1552{ 1553 // 1554 // The handleOpen method grants or denies permission to access this object 1555 // to an interested client. The argument is an IOStorageAccess value that 1556 // specifies the level of access desired -- reader or reader-writer. 1557 // 1558 // This method can be invoked to upgrade or downgrade the access level for 1559 // an existing client as well. The previous access level will prevail for 1560 // upgrades that fail, of course. A downgrade should never fail. If the 1561 // new access level should be the same as the old for a given client, this 1562 // method will do nothing and return success. In all cases, one, singular 1563 // close-per-client is expected for all opens-per-client received. 1564 // 1565 // This implementation replaces the IOService definition of handleOpen(). 1566 // 1567 // We are guaranteed that no other opens or closes will be processed until 1568 // we make our decision, change our state, and return from this method. 1569 // 1570 1571 IOStorageAccess access = (IOStorageAccess) (uintptr_t) argument; 1572 IOStorageAccess level; 1573 1574 IOLogOC("AppleRAIDSet::handleOpen(%p) called, client %p, access %u, state %u, client is a set = %s, raid member = %s.\n", 1575 this, client, (uint32_t)access, (uint32_t)arSetState, OSDynamicCast(AppleRAIDSet, client) ? "y" : "n", isRAIDMember() ? "y" : "n"); 1576 1577 assert(client); 1578 assert( access == kIOStorageAccessReader || 1579 access == kIOStorageAccessReaderWriter ); 1580 1581 access &= kIOStorageAccessReaderWriter; // just in case 1582 1583 // only allow "external" opens after we have published that we are online 1584 if (!OSDynamicCast(AppleRAIDSet, client) && getSetState() < kAppleRAIDSetStateOnline) { 1585 IOLogOC("AppleRAIDSet::handleOpen(%p) open refused (set is not online (published)).\n", this); 1586 return false; 1587 } 1588 // only allow the set that we are a member of to open us if we are stacked. 1589 // however, until we open and read the header, "is member" will be false 1590 if (!OSDynamicCast(AppleRAIDSet, client) && isRAIDMember()) { 1591 IOLogOC("AppleRAIDSet::handleOpen(%p) open refused (set is stacked).\n", this); 1592 return false; 1593 } 1594 assert(arSetState >= kAppleRAIDSetStateOnline); 1595 1596 unsigned writers = arOpenReaderWriters->getCount(); 1597 1598#ifdef XXX 1599 if (writers >= arOpenReaderWriterMax) 1600 { 1601 IOLogOC("AppleRAIDSet::handleOpen(%p) client %p access %lu arOpenReaderWriter already set %p\n", 1602 this, client, access, arOpenReaderWriter); 1603 return false; 1604 } 1605#endif 1606 1607 if (arOpenReaderWriters->containsObject(client)) writers--; 1608 if (access == kIOStorageAccessReaderWriter) writers++; 1609 1610 level = (writers) ? kIOStorageAccessReaderWriter : kIOStorageAccessReader; 1611 1612 // 1613 // Determine whether the levels below us accept this open or not (we avoid 1614 // the open if the required access is the access we already hold). 1615 // 1616 1617 if (arOpenLevel != level) 1618 { 1619 bool success = false; 1620 1621//XXX level = (level | kIOStorageAccessSharedLock); breaks stacked raid sets, see assert above 1622 1623 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 1624 if (arMembers[cnt] != 0) { 1625 1626 IOLogOC("AppleRAIDSet::handleOpen(%p) opening %p member=%u access=%u level=%u\n", 1627 this, arMembers[cnt], (uint32_t)cnt, (uint32_t)access, (uint32_t)level); 1628 1629 if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateRebuilding) continue; 1630 1631 success = arMembers[cnt]->open(this, options, level); 1632 1633 if (!success) { 1634 IOLog("AppleRAIDSet::handleOpen(%p) client %p member %s failed to open for set \"%s\" (%s).\n", 1635 this, client, arMembers[cnt]->getUUIDString(), getSetNameString(), getUUIDString()); 1636 IOLogOC("AppleRAIDSet::handleOpen() open failed on member %u of %u (active = %u), state = %u isOpen = %s", 1637 (uint32_t)cnt, (uint32_t)arMemberCount, (uint32_t)arActiveCount, (uint32_t)arSetState, arMembers[cnt]->isOpen(NULL) ? "t" : "f"); 1638 1639 // XXX this is wrong, we might need to just downgrade instead 1640 1641 // clean up any successfully opened members 1642 for (UInt32 cnt2 = 0; cnt2 < cnt; cnt2++) { 1643 if (arMembers[cnt2] != 0) { 1644 if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateRebuilding) continue; 1645 arMembers[cnt2]->close(this, 0); 1646 } 1647 } 1648 1649 return false; 1650 } 1651 } 1652 } 1653 1654 level = (level & kIOStorageAccessReaderWriter); 1655 } 1656 1657 // 1658 // Process the open. 1659 // 1660 1661 if (access == kIOStorageAccessReader) 1662 { 1663 arOpenReaders->setObject(client); 1664 1665 arOpenReaderWriters->removeObject(client); // (for a downgrade) 1666 } 1667 else // (access == kIOStorageAccessReaderWriter) 1668 { 1669 arOpenReaderWriters->setObject(client); 1670 1671 arOpenReaders->removeObject(client); // (for an upgrade) 1672 } 1673 1674 arOpenLevel = level; 1675 1676 changeMemberState(kAppleRAIDMemberStateOpen); // for stacked raid sets 1677 1678 IOLogOC("AppleRAIDSet::handleOpen(%p) successful, client %p, access %u, state %u\n", this, client, (uint32_t)access, (uint32_t)arSetState); 1679 1680 return true; 1681} 1682 1683bool AppleRAIDSet::handleIsOpen(const IOService * client) const 1684{ 1685 if (client == 0) return (arOpenLevel != kIOStorageAccessNone); 1686 1687 bool open = arOpenReaderWriters->containsObject(client) || arOpenReaders->containsObject(client); 1688 1689 IOLogOC("AppleRAIDSet::handleIsOpen(%p) client %p is %s\n", this, client, open ? "true" : "false"); 1690 1691 return open; 1692} 1693 1694 1695void AppleRAIDSet::handleClose(IOService * client, IOOptionBits options) 1696{ 1697 IOLogOC("AppleRAIDSet::handleClose(%p) called, client %p current state %u\n", this, client, (uint32_t)arSetState); 1698 1699 // 1700 // The handleClose method closes the client's access to this object. 1701 // 1702 // This implementation replaces the IOService definition of handleClose(). 1703 // 1704 // We are guaranteed that no other opens or closes will be processed until 1705 // we change our state and return from this method. 1706 // 1707 1708 assert(client); 1709 1710 // 1711 // Process the close. 1712 // 1713 1714 if (arOpenReaderWriters->containsObject(client)) // (is it a reader-writer?) 1715 { 1716 arOpenReaderWriters->removeObject(client); 1717 } 1718 else if (arOpenReaders->containsObject(client)) // (is the client a reader?) 1719 { 1720 arOpenReaders->removeObject(client); 1721 } 1722 else // (is the client is an imposter?) 1723 { 1724 assert(0); 1725 return; 1726 } 1727 1728 1729 // 1730 // Reevaluate the open we have on the level below us. If no opens remain, 1731 // we close, or if no reader-writer remains, but readers do, we downgrade. 1732 // 1733 1734 IOStorageAccess level; 1735 1736 if (arOpenReaderWriters->getCount()) level = kIOStorageAccessReaderWriter; 1737 else if (arOpenReaders->getCount()) level = kIOStorageAccessReader; 1738 else level = kIOStorageAccessNone; 1739 1740 if (level == kIOStorageAccessNone) { 1741 changeMemberState(kAppleRAIDMemberStateClosing); // for stacked raid sets 1742 } 1743 1744 if (arOpenLevel != level) // (has open level changed?) 1745 { 1746 assert(level != kIOStorageAccessReaderWriter); 1747 1748 if (level == kIOStorageAccessNone) // (is a close in order?) 1749 { 1750 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 1751 if (arMembers[cnt] != 0) { 1752 if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateRebuilding) continue; 1753 arMembers[cnt]->close(this, options); 1754 } 1755 } 1756 1757 } else { // (is a downgrade in order?) 1758 1759//XXX level = (level | kIOStorageAccessSharedLock); 1760 1761 bool success; 1762 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 1763 if (arMembers[cnt] != 0) { 1764 if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateRebuilding) continue; 1765 success = arMembers[cnt]->open(this, 0, level); 1766 assert(success); // (should never fail, unless avoided deadlock) 1767 } 1768 } 1769 1770 level = (level & kIOStorageAccessReaderWriter); // clear the shared bit 1771 } 1772 1773 arOpenLevel = level; 1774 } 1775 1776 if (level == kIOStorageAccessNone) { 1777 changeMemberState(kAppleRAIDMemberStateClosed); // for stacked raid sets 1778 } 1779} 1780 1781//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1782//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1783//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1784 1785void AppleRAIDSet::read(IOService *client, UInt64 byteStart, 1786 IOMemoryDescriptor *buffer, IOStorageAttributes * attributes, IOStorageCompletion * completion) 1787{ 1788 AppleRAIDStorageRequest * storageRequest; 1789 1790 IOLogRW("AppleRAIDSet::read(%p, %llu, 0x%x) this %p, state %u\n", client, byteStart, buffer ? (uint32_t)buffer->getLength() : 0, this, (uint32_t)arSetState); 1791 1792 arSetCommandGate->runAction(arAllocateRequestMethod, &storageRequest); 1793 1794 if (storageRequest != 0) { 1795 buffer->retain(); 1796 storageRequest->read(client, byteStart, buffer, attributes, completion); 1797 } else { 1798 IOLogRW("AppleRAIDSet::read(%p, 0x%llx) could not allocate a storage request\n", client, byteStart); 1799 IOStorage::complete(completion, kIOReturnNoMedia, 0); 1800 } 1801} 1802 1803void AppleRAIDSet::write(IOService *client, UInt64 byteStart, 1804 IOMemoryDescriptor *buffer, IOStorageAttributes * attributes, IOStorageCompletion * completion) 1805{ 1806 AppleRAIDStorageRequest * storageRequest; 1807 1808 IOLogRW("AppleRAIDSet::write(%p, %llu, 0x%x) this %p, state %u\n", client, byteStart, buffer ? (uint32_t)buffer->getLength() : 0, this, (uint32_t)arSetState); 1809 1810 arSetCommandGate->runAction(arAllocateRequestMethod, &storageRequest); 1811 1812 if (storageRequest != 0) { 1813 buffer->retain(); 1814 storageRequest->write(client, byteStart, buffer, attributes, completion); 1815 } else { 1816 IOLogRW("AppleRAIDSet::write(%p, 0x%llx) could not allocate a storage request\n", client, byteStart); 1817 IOStorage::complete(completion, kIOReturnNoMedia, 0); 1818 } 1819} 1820 1821void AppleRAIDSet::activeReadMembers(AppleRAIDMember ** activeMembers, UInt64 byteStart, UInt32 byteCount) 1822{ 1823 // XXX the default code should be able to cache this, maybe in the storage request? 1824 1825 for (UInt32 index = 0; index < arMemberCount; index++) { 1826 AppleRAIDMember * member = arMembers[index]; 1827 if (member && member->getMemberState() >= kAppleRAIDMemberStateClosing) { 1828 activeMembers[index] = arMembers[index]; 1829 } else { 1830 activeMembers[index] = (AppleRAIDMember *)index; 1831 } 1832 } 1833} 1834 1835void AppleRAIDSet::activeWriteMembers(AppleRAIDMember ** activeMembers, UInt64 byteStart, UInt32 byteCount) 1836{ 1837 // XXX the default code should be able to cache this, maybe in the storage request? 1838 1839 for (UInt32 index = 0; index < arMemberCount; index++) { 1840 AppleRAIDMember * member = arMembers[index]; 1841 if (member && member->getMemberState() >= kAppleRAIDMemberStateClosing) { 1842 activeMembers[index] = arMembers[index]; 1843 } else { 1844 activeMembers[index] = (AppleRAIDMember *)index; 1845 } 1846 } 1847} 1848 1849// the top set (master) needs to go through the workloop 1850// members or members are then already called in that workloop 1851// member sets can just call through, the syncing count is already bumped 1852 1853IOReturn AppleRAIDSet::synchronizeCache(IOService *client) 1854{ 1855 if (OSDynamicCast(AppleRAIDSet, client)) return synchronizeCacheGated(client); 1856 1857 IOCommandGate::Action syncCacheMethod = OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::synchronizeCacheGated); 1858 return arSetCommandGate->runAction(syncCacheMethod, (void *)client); 1859} 1860 1861IOReturn AppleRAIDSet::synchronizeCacheGated(IOService *client) 1862{ 1863 AppleRAIDSet * masterSet = OSDynamicCast(AppleRAIDSet, client); 1864 1865 if (masterSet == NULL) { 1866 while (arSetIsSyncingCount > 0) { 1867 IOLog1("AppleRAIDSet::requestSynchronizeCache(%p) stalled count=%d \n", client, (int32_t)arSetIsSyncingCount); 1868 arSetCommandGate->commandSleep(&arSetIsSyncingCount, THREAD_UNINT); 1869 } 1870 arSetIsSyncingCount++; // prevents multiple drops to zero 1871 } 1872 1873 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 1874 1875 if (!arMembers[cnt] || (arMembers[cnt]->getMemberState() < kAppleRAIDMemberStateRebuilding)) continue; 1876 1877 arMembers[cnt]->synchronizeCache(masterSet ? masterSet : this); 1878 } 1879 1880 // wait for members to complete 1881 if (masterSet == NULL) { 1882 while (arSetIsSyncingCount > 1) { 1883 arSetCommandGate->commandSleep(&arSetIsSyncingCount, THREAD_UNINT); 1884 } 1885 1886 // we are done, wake up any other blocked requests 1887 arSetIsSyncingCount--; 1888 assert(arSetIsSyncingCount == 0); 1889 arSetCommandGate->commandWakeup(&arSetIsSyncingCount, /* oneThread */ false); 1890 } 1891 1892 return 0; 1893} 1894 1895void AppleRAIDSet::synchronizeStarted(void) 1896{ 1897 arSetIsSyncingCount++; 1898} 1899 1900void AppleRAIDSet::synchronizeCompleted(void) 1901{ 1902 arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::synchronizeCompletedGated)); 1903} 1904 1905void AppleRAIDSet::synchronizeCompletedGated(void) 1906{ 1907 arSetIsSyncingCount--; 1908 if (arSetIsSyncingCount <= 1) { 1909 assert(arSetIsSyncingCount == 1); 1910 arSetCommandGate->commandWakeup(&arSetIsSyncingCount, /* oneThread */ false); 1911 } 1912} 1913 1914bool AppleRAIDSet::pauseSet(bool whenIdle) 1915{ 1916 // this is running in the workloop 1917 if (whenIdle) { 1918 if (arStorageRequestsPending != 0) return false; 1919 if (arSetWasBlockedByPause) { 1920 arSetWasBlockedByPause = false; 1921 return false; 1922 } 1923 } 1924 1925 // *** ALWAYS CALL SLEEPS IN THE SAME ORDER *** 1926 1927 // only one pause at a time 1928 while (arSetIsPaused) { 1929 arSetWasBlockedByPause = true; 1930 arSetCommandGate->commandSleep(&arSetIsPaused, THREAD_UNINT); 1931 } 1932 1933 arSetIsPaused++; 1934 1935 // wait for any currently pending i/o to drain. 1936 while (arStorageRequestsPending != 0) { 1937 arSetCommandGate->commandSleep(&arStorageRequestPool, THREAD_UNINT); 1938 } 1939 1940 return true; 1941} 1942 1943void AppleRAIDSet::unpauseSet() 1944{ 1945 // this is running in the workloop 1946 1947 assert(arSetIsPaused); 1948 1949 arSetIsPaused--; 1950 if (arSetIsPaused == 0) { 1951 arSetCommandGate->commandWakeup(&arSetIsPaused, /* oneThread */ false); 1952 } 1953} 1954 1955IOReturn AppleRAIDSet::allocateRAIDRequest(AppleRAIDStorageRequest **storageRequest) 1956{ 1957 while (1) { 1958 if ((arActiveCount == 0) || getSetState() <= kAppleRAIDSetStateTerminating) { 1959 *storageRequest = 0; 1960 return kIOReturnNoMedia; 1961 } 1962 1963 // *** ALWAYS CALL SLEEPS IN THE SAME ORDER *** 1964 1965 if (arSetIsPaused) { 1966 arSetWasBlockedByPause = true; 1967 arSetCommandGate->commandSleep(&arSetIsPaused, THREAD_UNINT); 1968 continue; 1969 } 1970 1971 *storageRequest = (AppleRAIDStorageRequest *)arStorageRequestPool->getCommand(false); 1972 if (*storageRequest == 0) { 1973 arSetCommandGate->commandSleep(&arStorageRequestPool, THREAD_UNINT); 1974 continue; 1975 } 1976 1977 break; 1978 } 1979 1980 arStorageRequestsPending++; 1981 1982 return kIOReturnSuccess; 1983} 1984 1985void AppleRAIDSet::returnRAIDRequest(AppleRAIDStorageRequest *storageRequest) 1986{ 1987 arStorageRequestsPending--; 1988 arStorageRequestPool->returnCommand(storageRequest); 1989 arSetCommandGate->commandWakeup(&arStorageRequestPool, /* oneThread */ false); 1990} 1991 1992void AppleRAIDSet::completeRAIDRequest(AppleRAIDStorageRequest *storageRequest) 1993{ 1994 UInt32 cnt; 1995 UInt64 byteCount; 1996 IOReturn status; 1997 bool isWrite; 1998 1999 // this is running in the workloop, via a AppleRAIDEvent 2000 2001 isWrite = (storageRequest->srMemoryDescriptorDirection == kIODirectionOut); 2002 byteCount = 0; 2003 status = kIOReturnSuccess; 2004 2005 // Collect the status and byte count for each member. 2006 for (cnt = 0; cnt < arMemberCount; cnt++) { 2007 2008 // Ignore missing members. 2009 if (arMembers[cnt] == 0) continue; 2010 2011 // Ignore offline members 2012 if (arMembers[cnt]->getMemberState() != kAppleRAIDMemberStateOpen) { 2013 IOLogRW("AppleRAIDSet::completeRAIDRequest - [%u] tbc 0x%llx, sbc 0x%llx bc 0x%llx, member %p, member state %u\n", 2014 (uint32_t)cnt, storageRequest->srByteCount, storageRequest->srRequestByteCounts[cnt], 2015 byteCount, arMembers[cnt], (uint32_t)arMembers[cnt]->getMemberState()); 2016 2017 if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateClosing) { 2018 status = kIOReturnOffline; 2019 } 2020 2021 continue; 2022 } 2023 2024 // Return any status errors. 2025 if (storageRequest->srRequestStatus[cnt] != kIOReturnSuccess) { 2026 status = storageRequest->srRequestStatus[cnt]; 2027 IOLog("AppleRAID::completeRAIDRequest - error 0x%x detected for set \"%s\" (%s), member %s, set byte offset = %llu.\n", 2028 status, getSetNameString(), getUUIDString(), arMembers[cnt]->getUUIDString(), storageRequest->srByteStart); 2029 2030 continue; 2031 } 2032 2033 // once the status goes bad, stop counting bytes transfered 2034 if (status == kIOReturnSuccess) { 2035 byteCount += storageRequest->srRequestByteCounts[cnt]; 2036 } 2037 2038 IOLogRW("AppleRAIDSet::completeRAIDRequest - [%u] tbc 0x%llx, sbc 0x%llx bc 0x%llx, member %p\n", 2039 (uint32_t)cnt, storageRequest->srByteCount, storageRequest->srRequestByteCounts[cnt], 2040 byteCount, arMembers[cnt]); 2041 } 2042 2043 // Return an underrun error if the byte count is not complete. 2044 // This can happen if one or more members reported a smaller than expected byte count. 2045 if ((status == kIOReturnSuccess) && (byteCount != storageRequest->srByteCount)) { 2046 IOLog("AppleRAID::completeRAIDRequest - underrun detected, expected = 0x%llx, actual = 0x%llx, set = \"%s\" (%s)\n", 2047 storageRequest->srByteCount, byteCount, getSetNameString(), getUUIDString()); 2048 status = kIOReturnUnderrun; 2049 byteCount = 0; 2050 } 2051 2052 storageRequest->srMemoryDescriptor->release(); 2053 returnRAIDRequest(storageRequest); 2054 2055 // Call the clients completion routine, bad status is also returned here. 2056 IOStorage::complete(&storageRequest->srClientsCompletion, status, byteCount); 2057 2058 // remove any failing members from the set 2059 if (status != kIOReturnSuccess) recoverStart(); 2060} 2061 2062void AppleRAIDSet::recoverStart() 2063{ 2064 IOLog1("AppleRAID::recoverStart entered\n"); 2065 2066 arSetIsPaused++; 2067 retain(); // the set also holds a controller ref 2068 2069 bool bumped = thread_call_enter(arRecoveryThreadCall); 2070 2071 if (bumped) { 2072 arSetIsPaused--; 2073 release(); 2074 } 2075} 2076 2077void AppleRAIDSet::recoverWait() 2078{ 2079 // this is on a separate thread 2080 // running on the workloop 2081 2082 assert(arSetIsPaused); 2083 2084 IOLog1("AppleRAID::recover %u requests are pending.\n", (uint32_t)arStorageRequestsPending); 2085 while (arStorageRequestsPending != 0) { 2086 arSetCommandGate->commandSleep(&arStorageRequestPool, THREAD_UNINT); 2087 } 2088} 2089 2090bool AppleRAIDSet::recover() 2091{ 2092 // this is on a separate thread 2093 // the set is paused. 2094 2095 // still here? 2096 if (arController->findSet(getUUID()) != this) return false; 2097 2098 // wait for outstanding i/o 2099 arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::recoverWait)); 2100 2101 IOLog1("AppleRAID::recover wait for requests complete.\n"); 2102 2103 // at this point, the set should be paused and not allowing any new i/o 2104 // and there should be no active i/o outstanding other than the failed i/o 2105 2106 // thread_call_enter() allows multiple threads to run at once 2107 // the first one that gets out of sleep will then do most of the work 2108 IOSleep(100); 2109 2110 // remove any bad members from the set and reconfigure memory descriptors 2111 2112 gAppleRAIDGlobals.lock(); 2113 2114 assert(arSetIsPaused); 2115 2116 UInt32 oldActiveCount = arActiveCount; 2117 OSSet * brokenMembers= OSSet::withCapacity(10); 2118 2119 for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) { 2120 2121 if (arMembers[cnt] == 0) continue; 2122 2123 if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateClosing) { 2124 2125 IOLog("AppleRAID::recover() member %s from set \"%s\" (%s) has been marked offline.\n", 2126 arMembers[cnt]->getUUIDString(), getSetNameString(), getUUIDString()); 2127 2128 // manually move bad member to the spare list 2129 // leaving it attached and then close them last 2130 2131 AppleRAIDMember * brokenMember = arMembers[cnt]; 2132 2133 arMembers[cnt] = 0; 2134 arActiveCount--; 2135 2136 brokenMembers->setObject(brokenMember); 2137 arSpareMembers->setObject(brokenMember); 2138 2139 brokenMember->changeMemberState(kAppleRAIDMemberStateBroken); 2140 } 2141 } 2142 2143 if (oldActiveCount != arActiveCount) { 2144 2145 // reconfigure the set with the remaining active members 2146 arController->restartSet(this, bumpOnError()); 2147 2148 // close the new spares 2149 while (brokenMembers->getCount()) { 2150 2151 AppleRAIDMember * brokenMember = (AppleRAIDMember *)brokenMembers->getAnyObject(); 2152 brokenMember->close(this, 0); 2153 brokenMembers->removeObject(brokenMember); 2154 } 2155 } 2156 2157 brokenMembers->release(); 2158 2159 bool stillAlive = arActiveCount > 0; 2160 2161 gAppleRAIDGlobals.unlock(); 2162 2163 arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::unpauseSet)); 2164 2165 release(); // from recoverStart 2166 2167 IOLog1("AppleRAID::recover finished\n"); 2168 return stillAlive; 2169} 2170