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 AppleRAIDSet 26OSDefineMetaClassAndStructors(AppleLVMGroup, AppleRAIDSet); 27 28AppleRAIDSet * AppleLVMGroup::createRAIDSet(AppleRAIDMember * firstMember) 29{ 30 AppleLVMGroup *raidSet = new AppleLVMGroup; 31 32 AppleLVGTOCEntrySanityCheck(); // debug only 33 AppleLVMVolumeOnDiskSanityCheck(); // debug only 34 35 IOLog1("AppleLVMGroup::createRAIDSet(%p) called, new set = %p *********\n", firstMember, raidSet); 36 37 while (raidSet){ 38 39 if (!raidSet->init()) break; 40 if (!raidSet->initWithHeader(firstMember->getHeader(), true)) break; 41 if (raidSet->resizeSet(raidSet->getMemberCount())) return raidSet; 42 43 break; 44 } 45 46 if (raidSet) raidSet->release(); 47 48 return 0; 49} 50 51 52bool AppleLVMGroup::init() 53{ 54 IOLog1("AppleLVMGroup::init() called\n"); 55 56 if (super::init() == false) return false; 57 58 arMemberBlockCounts = 0; 59 arMemberStartingOffset = 0; 60 arExpectingLiveAdd = 0; 61 arPrimaryNeedsUpdate = false; 62 arPrimaryBuffer = NULL; 63 arLogicalVolumeCount = 0; 64 arLogicalVolumeActiveCount = 0; 65 arLogicalVolumes = NULL; 66 arMetaDataVolumes = 0; 67 arExtentCount = 0; 68 arExtents = NULL; 69 70 setProperty(kAppleRAIDLevelNameKey, kAppleRAIDLevelNameLVG); 71 72 arAllocateRequestMethod = OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::allocateRAIDRequest); 73 74 return true; 75} 76 77void AppleLVMGroup::free(void) 78{ 79 80 if (arMemberBlockCounts) IODelete(arMemberBlockCounts, UInt64, arMemberCount); 81 if (arMemberStartingOffset) IODelete(arMemberStartingOffset, UInt64, arMemberCount); 82 if (arPrimaryBuffer) arPrimaryBuffer->release(); 83 84 UInt32 i; 85 if (arLogicalVolumes) { 86 for (i = 0; i < arLogicalVolumeCount; i++) { 87 if (arLogicalVolumes[i]) { 88 arController->removeLogicalVolume(arLogicalVolumes[i]); 89 arLogicalVolumes[i]->release(); 90 arLogicalVolumes[i] = NULL; 91 } 92 } 93 IODelete(arLogicalVolumes, AppleLVMVolume *, 1024); // XXXTOC 94 } 95 96 if (arMetaDataVolumes) { 97 for (i = 0; i < arMemberCount; i++) { 98 if (arMetaDataVolumes[i]) arMetaDataVolumes[i]->release(); 99 } 100 IODelete(arMetaDataVolumes, AppleLVMVolume *, arMemberCount); 101 } 102 103 super::free(); 104} 105 106//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 107//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 108//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 109 110bool AppleLVMGroup::addSpare(AppleRAIDMember * member) 111{ 112 if (super::addSpare(member) == false) return false; 113 114 member->changeMemberState(kAppleRAIDMemberStateBroken); 115 116 return true; 117} 118 119bool AppleLVMGroup::addMember(AppleRAIDMember * member) 120{ 121 if (super::addMember(member) == false) return false; 122 123 OSNumber * number = OSDynamicCast(OSNumber, member->getHeaderProperty(kAppleRAIDChunkCountKey)); 124 if (!number) return false; 125 UInt64 memberBlockCount = number->unsigned64BitValue(); 126 127 UInt32 memberIndex = member->getMemberIndex(); 128 arMemberBlockCounts[memberIndex] = memberBlockCount; 129 130 // total up the block count as we go 131 arSetBlockCount += memberBlockCount; 132 arSetMediaSize = arSetBlockCount * arSetBlockSize; 133 134 // read the TOC on this member 135 IOBufferMemoryDescriptor * newPrimaryBuffer = readPrimaryMetaData(member); 136 if (newPrimaryBuffer && arPrimaryBuffer != newPrimaryBuffer) { 137 if (arPrimaryBuffer) arPrimaryBuffer->release(); 138 arPrimaryBuffer = newPrimaryBuffer; 139 } 140 141 // scan the logical volumes in start 142 143 return true; 144} 145 146bool AppleLVMGroup::removeMember(AppleRAIDMember * member, IOOptionBits options) 147{ 148 UInt32 memberIndex = member->getMemberIndex(); 149 UInt64 memberBlockCount = arMemberBlockCounts[memberIndex]; 150 151 IOLog1("AppleLVMGroup::removeMember(%p) called for index %d block count %lld\n", 152 member, (int)memberIndex, memberBlockCount); 153 154 // XXX 155 // tbd 156 // XXX 157 158 // remove this member's blocks from the total block count 159 arSetBlockCount -= memberBlockCount; 160 arSetMediaSize = arSetBlockCount * arSetBlockSize; 161 162 if (arMetaDataVolumes[memberIndex]) arMetaDataVolumes[memberIndex]->release(); 163 arMetaDataVolumes[memberIndex] = 0; 164 165 return super::removeMember(member, options); 166} 167 168bool AppleLVMGroup::resizeSet(UInt32 newMemberCount) 169{ 170 UInt32 oldMemberCount = arMemberCount; 171 172 UInt64 * oldBlockCounts = arMemberBlockCounts; 173 arMemberBlockCounts = IONew(UInt64, newMemberCount); 174 bzero(arMemberBlockCounts, sizeof(UInt64) * newMemberCount); 175 if (oldBlockCounts) { 176 bcopy(oldBlockCounts, arMemberBlockCounts, sizeof(UInt64) * oldMemberCount); 177 IODelete(oldBlockCounts, sizeof(UInt64), oldMemberCount); 178 } 179 180 UInt64 * oldStartingOffset = arMemberStartingOffset; 181 arMemberStartingOffset = IONew(UInt64, newMemberCount); 182 bzero(arMemberStartingOffset, sizeof(UInt64) * newMemberCount); 183 if (oldStartingOffset) { 184 bcopy(oldStartingOffset, arMemberStartingOffset, sizeof(UInt64) * oldMemberCount); 185 IODelete(oldStartingOffset, sizeof(UInt64), oldMemberCount); 186 } 187 188 AppleLVMVolume ** oldMetaDataVolumes = arMetaDataVolumes; 189 arMetaDataVolumes = IONew(AppleLVMVolume *, newMemberCount); 190 bzero(arMetaDataVolumes, sizeof(AppleLVMVolume *) * newMemberCount); 191 if (oldMetaDataVolumes) { 192 bcopy(oldMetaDataVolumes, arMetaDataVolumes, sizeof(AppleLVMVolume *) * oldMemberCount); 193 IODelete(oldMetaDataVolumes, sizeof(AppleLVMVolume *), oldMemberCount); 194 } 195 196 if (super::resizeSet(newMemberCount) == false) return false; 197 198 if (oldMemberCount && arMemberCount > oldMemberCount) arExpectingLiveAdd += arMemberCount - oldMemberCount; 199 200 return true; 201} 202 203bool AppleLVMGroup::startSet(void) 204{ 205 if (super::startSet() == false) return false; 206 207 // the set remains paused when a new member is added 208 if (arExpectingLiveAdd) { 209 arExpectingLiveAdd--; 210 if (arExpectingLiveAdd == 0) unpauseSet(); 211 212 // XXXTOC will need to update the TOC on the new member 213 } 214 215 assert(arPrimaryBuffer); 216 if (!arPrimaryBuffer) return false; 217 218 // once all the disks have been scanned we should have the 219 // the best available TOC and also should be able to read 220 // the logical volume entries from any of the disks 221 AppleRAIDPrimaryOnDisk * primary = (AppleRAIDPrimaryOnDisk *)arPrimaryBuffer->getBytesNoCopy(); 222 if (!primary) return false; 223 224 arLogicalVolumeCount = primary->pri.volumeCount; 225 arLogicalVolumeActiveCount = 0; 226 227 if (!arLogicalVolumes) { 228 arLogicalVolumes = IONew(AppleLVMVolume *, 1024); // XXXTOC 229 if (!arLogicalVolumes) return false; 230 bzero(arLogicalVolumes, 1024 * sizeof(AppleLVMVolume *)); 231 } 232 233 if (arPrimaryNeedsUpdate) { 234 IOLog("AppleLVMGroup::startSet: updating primary meta data for LVG \"%s\" (%s)\n", getSetNameString(), getUUIDString()); 235 IOReturn rc = writePrimaryMetaData(arPrimaryBuffer); 236 if (rc) return false; 237 arPrimaryNeedsUpdate = false; 238 } 239 240 if (!initializeSecondary()) return false; 241 242 if (!initializeVolumes(primary)) return false; 243 244 return true; 245} 246 247bool AppleLVMGroup::publishSet(void) 248{ 249 IOLog1("AppleLVMGroup::publishSet called %p\n", this); 250 251 if (arExpectingLiveAdd || arActiveCount == 0) { 252 IOLog1("AppleLVMGroup::publishSet() publish ignored.\n"); 253 return false; 254 } 255 256 bool success = super::publishSet(); 257 258 UInt32 index; 259 for (index = 0; index < arLogicalVolumeCount; index++) { 260 261 AppleLVMVolume * lv = arLogicalVolumes[index]; 262 263 // XXX check for errors? 264 if (lv && lv->isAVolume()) publishVolume(lv); 265 if (lv && lv->isASnapShot()) publishVolume(lv); 266 } 267 268 return success; 269} 270 271bool AppleLVMGroup::unpublishSet(void) 272{ 273 UInt32 index; 274 for (index = 0; index < arLogicalVolumeCount; index++) { 275 276 AppleLVMVolume * lv = arLogicalVolumes[index]; 277 278 if (lv && lv->isPublished()) (void)unpublishVolume(lv); 279 } 280 281 return super::unpublishSet(); 282} 283 284void AppleLVMGroup::unpauseSet() 285{ 286 if (arExpectingLiveAdd) { 287 IOLog1("AppleLVMGroup::unpauseSet() unpause ignored.\n"); 288 return; 289 } 290 291 super::unpauseSet(); 292} 293 294bool AppleLVMGroup::handleOpen(IOService * client, IOOptionBits options, void * argument) 295{ 296 // only allow clients that are logical volumes to open (or ourself) 297 if (OSDynamicCast(AppleLVMVolume, client) || client == this) { 298 299 return super::handleOpen(client, options, argument); 300 } 301 302 return false; 303} 304 305UInt64 AppleLVMGroup::getMemberSize(UInt32 memberIndex) const 306{ 307 assert(arMemberBlockCounts); 308 assert(memberIndex < arMemberCount); 309 310 return arMemberBlockCounts[memberIndex] * arSetBlockSize;; 311} 312 313UInt64 AppleLVMGroup::getMemberStartingOffset(UInt32 memberIndex) const 314{ 315 assert(memberIndex < arMemberCount); 316 return arMemberStartingOffset[memberIndex]; 317} 318 319UInt32 AppleLVMGroup::getMemberIndexFromOffset(UInt64 offset) const 320{ 321 UInt32 index = 0; 322 UInt64 memberDataSize; 323 while (index < arMemberCount) { 324 325 memberDataSize = arMemberBlockCounts[index] * arSetBlockSize; 326 327 IOLog2("getMemberIndexFromOffset(%llu) index %u, start %llu, end %llu\n", 328 offset, (uint32_t)index, arMemberStartingOffset[index], arMemberStartingOffset[index] + memberDataSize); 329 330 if (offset < arMemberStartingOffset[index] + memberDataSize) break; 331 index++; 332 } 333 334 assert(index < arMemberCount); 335 336 return index; 337} 338 339 340bool AppleLVMGroup::memberOffsetFromLVGOffset(UInt64 lvgOffset, AppleRAIDMember ** member, UInt64 * memberOffset) 341{ 342 343 UInt32 index = getMemberIndexFromOffset(lvgOffset); 344 if (index >= arMemberCount) return false; 345 if (!arMembers[index]) return false; 346 347 *member = arMembers[index]; 348 *memberOffset = lvgOffset - getMemberStartingOffset(index); 349 350 return true; 351} 352 353 354OSDictionary * AppleLVMGroup::getSetProperties(void) 355{ 356 OSDictionary * props = super::getSetProperties(); 357 OSNumber * tmpNumber; 358 359 if (props) { 360 tmpNumber = OSNumber::withNumber(arExtentCount, 64); 361 if (tmpNumber) { 362 props->setObject(kAppleRAIDLVGExtentsKey, tmpNumber); 363 tmpNumber->release(); 364 } 365 366 tmpNumber = OSNumber::withNumber(arLogicalVolumeActiveCount, 32); 367 if (tmpNumber) { 368 props->setObject(kAppleRAIDLVGVolumeCountKey, tmpNumber); 369 tmpNumber->release(); 370 } 371 372 tmpNumber = OSNumber::withNumber(calculateFreeSpace(), 64); 373 if (tmpNumber) { 374 props->setObject(kAppleRAIDLVGFreeSpaceKey, tmpNumber); 375 tmpNumber->release(); 376 } 377 } 378 379 return props; 380} 381 382AppleRAIDMemoryDescriptor * AppleLVMGroup::allocateMemoryDescriptor(AppleRAIDStorageRequest *storageRequest, UInt32 memberIndex) 383{ 384 return AppleLVMMemoryDescriptor::withStorageRequest(storageRequest, memberIndex); 385} 386 387// AppleLVMMemoryDescriptor 388// AppleLVMMemoryDescriptor 389// AppleLVMMemoryDescriptor 390 391#undef super 392#define super AppleRAIDMemoryDescriptor 393OSDefineMetaClassAndStructors(AppleLVMMemoryDescriptor, AppleRAIDMemoryDescriptor); 394 395AppleRAIDMemoryDescriptor * AppleLVMMemoryDescriptor::withStorageRequest(AppleRAIDStorageRequest *storageRequest, UInt32 requestIndex) 396{ 397 AppleLVMMemoryDescriptor *memoryDescriptor = new AppleLVMMemoryDescriptor; 398 399 if (memoryDescriptor != 0) { 400 if (!memoryDescriptor->initWithStorageRequest(storageRequest, requestIndex)) { 401 memoryDescriptor->release(); 402 memoryDescriptor = 0; 403 } 404 } 405 406 memoryDescriptor->mdRequestIndex = requestIndex; 407 408 return memoryDescriptor; 409} 410 411bool AppleLVMMemoryDescriptor::initWithStorageRequest(AppleRAIDStorageRequest *storageRequest, UInt32 requestIndex) 412{ 413 if (!super::initWithStorageRequest(storageRequest, requestIndex)) return false; 414 415 return true; 416} 417 418bool AppleLVMMemoryDescriptor::configureForMemoryDescriptor(IOMemoryDescriptor *memoryDescriptor, UInt64 requestStart, UInt64 requestSize, AppleLVMVolume * lv) 419{ 420 IOLogRW("LVG bytestart=%llu requestSize=%llu\n", requestStart, requestSize); 421 422 AppleLVMLogicalExtent * extent = lv->findExtent(requestStart); 423 if (!extent) return false; 424 425 mdMemberIndex = extent->lvMemberIndex; 426 427 // find start within the extent 428 UInt64 startingOffset = requestStart - extent->lvExtentVolumeOffset; 429 mdMemberByteStart = extent->lvExtentMemberOffset + startingOffset; 430 431 // clip requests that go past the end of the extent 432 if (startingOffset + requestSize > extent->lvExtentSize) requestSize = extent->lvExtentSize - startingOffset; 433 _length = requestSize; 434 435 // find this extent's offset back to lv addressing 436 mdRequestOffset = (IOByteCount)(requestStart - mdStorageRequest->srByteStart); 437 438 mdMemoryDescriptor = memoryDescriptor; 439 440 _flags = (_flags & ~kIOMemoryDirectionMask) | memoryDescriptor->getDirection(); 441 442 IOLogRW("LVG mdbytestart=%llu _length=0x%x\n", requestStart, (uint32_t)_length); 443 444 return true; 445} 446 447addr64_t AppleLVMMemoryDescriptor::getPhysicalSegment(IOByteCount offset, IOByteCount *length, IOOptionBits options) 448{ 449 IOByteCount volumeOffset = offset + mdRequestOffset; 450 addr64_t physAddress; 451 452 physAddress = mdMemoryDescriptor->getPhysicalSegment(volumeOffset, length, options); 453 454 return physAddress; 455} 456 457//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 458//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 459//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 460 461#undef super 462#define super AppleRAIDSet 463 464IOBufferMemoryDescriptor * AppleLVMGroup::readPrimaryMetaData(AppleRAIDMember * member) 465{ 466 IOLog1("AppleLVMGroup::readPrimaryMetaData(%p) entered\n", member); 467 468 AppleRAIDPrimaryOnDisk * primary = NULL; 469 IOBufferMemoryDescriptor * primaryBuffer = super::readPrimaryMetaData(member); 470 if (!primaryBuffer) goto error; 471 472 primary = (AppleRAIDPrimaryOnDisk *)primaryBuffer->getBytesNoCopy(); 473 if (!primary) goto error; 474 475#if defined(__LITTLE_ENDIAN__) 476 { 477 ByteSwapPrimaryHeader(primary); 478 UInt64 index; 479 AppleLVGTOCEntryOnDisk * tocEntry = (AppleLVGTOCEntryOnDisk *)(primary + 1); 480 for (index = 0; index < primary->pri.volumeCount; index++) { 481 ByteSwapLVGTOCEntry(tocEntry + index); 482 } 483 } 484#endif 485 486 // compare against raid header sequence number 487 if (primary->priSequenceNumber > arSequenceNumber) { 488 IOLog("AppleLVMGroup::readPrimaryMetaData() sequence number in future, new volumes may have been lost.\n"); 489 goto error; 490 } 491 492 // compare against the current "best" primary 493 if (arPrimaryBuffer) { 494 495 AppleRAIDPrimaryOnDisk * current = (AppleRAIDPrimaryOnDisk *)arPrimaryBuffer->getBytesNoCopy(); 496 497 // if the sequence numbers match we are done 498 if (current->priSequenceNumber != primary->priSequenceNumber) { 499 IOLog("AppleLVMGroup::readPrimaryMetaData() the sequence number was out of date.\n"); 500 if (current->priSequenceNumber < primary->priSequenceNumber) goto error; 501 } 502 } 503 504 IOLog1("AppleLVMGroup::readPrimaryMetaData(%p) successful, volumes = %llu\n", member, primary->pri.volumeCount); 505 506 return primaryBuffer; 507 508error: 509 IOLog("AppleLVMGroup::readPrimaryMetaData() was unsuccessful for member %s.\n", member->getUUIDString()); 510 if (primaryBuffer) primaryBuffer->release(); 511 512 arPrimaryNeedsUpdate = true; 513 return NULL; 514} 515 516 517IOReturn AppleLVMGroup::writePrimaryMetaData(IOBufferMemoryDescriptor * primaryBuffer) 518{ 519 IOLog1("AppleLVMGroup::writePrimaryMetaData(%p) entered\n", this); 520 521 AppleRAIDPrimaryOnDisk * primary = (AppleRAIDPrimaryOnDisk *)primaryBuffer->getBytesNoCopy(); 522 if (!primary) return false; 523 524 // XXX 525 // 526 // only allow writes if all members are active 527 // 528 // disallow all changes to LVG (create, destroy, ...) 529 // 530 // XXX 531 532 primary->priSequenceNumber = arSequenceNumber; 533 534#if defined(__LITTLE_ENDIAN__) 535 UInt64 index; 536 AppleLVGTOCEntryOnDisk * tocEntry = (AppleLVGTOCEntryOnDisk *)(primary + 1); 537 for (index = 0; index < primary->pri.extentCount; index++) { 538 ByteSwapLVGTOCEntry(tocEntry + index); 539 } 540 ByteSwapPrimaryHeader(primary); 541#endif 542 543 IOReturn rc = super::writePrimaryMetaData(primaryBuffer); 544 545 // we hold onto this buffer so we need to should swap it back 546 // it is tempting to grab a new buffer, but that can fail and 547 // this can be called by the driver for non-user reasons. 548 549#if defined(__LITTLE_ENDIAN__) 550 ByteSwapPrimaryHeader(primary); 551 tocEntry = (AppleLVGTOCEntryOnDisk *)(primary + 1); 552 for (index = 0; index < primary->pri.extentCount; index++) { 553 ByteSwapLVGTOCEntry(tocEntry + index); 554 } 555#endif 556 557 IOLog1("AppleLVMGroup::writePrimaryMetaData(%p): was %ssuccessful\n", this, rc ? "un" : ""); 558 return rc; 559} 560 561 562 563//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 564//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 565//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 566 567IOBufferMemoryDescriptor * AppleLVMGroup::readLogicalVolumeEntry(UInt64 offset, UInt32 size) 568{ 569 bool autoSize = size ? false : true; 570 571 IOLog1("AppleLVMGroup::readLogicalVolumeEntry(%p) lve offset %llu size %u %s\n", this, offset, (uint32_t)size, autoSize ? "autosized = true" : ""); 572 573 if (autoSize) size = kAppleLVMVolumeOnDiskMinSize; 574 575 AppleRAIDMember * member; 576 UInt64 memberOffset; 577 if (!memberOffsetFromLVGOffset(offset, &member, &memberOffset)) { 578 return NULL; 579 } 580 581retry: 582 583 // Allocate a buffer to read into 584 IOBufferMemoryDescriptor * lveBuffer = IOBufferMemoryDescriptor::withCapacity(size, kIODirectionNone); 585 if (lveBuffer == 0) return NULL; 586 587 // read 588 if (!readIntoBuffer(member, lveBuffer, memberOffset)) { 589 lveBuffer->release(); 590 return NULL; 591 } 592 593 // Make sure the logical volume header contains the correct signature. 594 AppleLVMVolumeOnDisk * lve = (AppleLVMVolumeOnDisk *)lveBuffer->getBytesNoCopy(); 595 if (strncmp(lve->lvMagic, kAppleLVMVolumeMagic, sizeof(lve->lvMagic))) { 596 lveBuffer->release(); 597 return NULL; 598 } 599 600 ByteSwapLVMVolumeHeader(lve); 601 if (lve->lvHeaderSize != size) { 602 if (autoSize) { 603 autoSize = false; 604 size = lve->lvHeaderSize; 605 lveBuffer->release(); 606 goto retry; 607 } 608 IOLog("AppleLVMGroup::readLogicalVolumeEntry(): size mismatch %u <> %u\n", (uint32_t)lve->lvHeaderSize, (uint32_t)size); 609 if (lve->lvHeaderSize > size) { 610 lveBuffer->release(); 611 return NULL; 612 } 613 } 614 615#if defined(__LITTLE_ENDIAN__) 616 AppleRAIDExtentOnDisk *extent = (AppleRAIDExtentOnDisk *)((char *)lve + lve->lvExtentsStart); 617 UInt32 i; 618 for (i=0; i < lve->lvExtentsCount; i++) { 619 ByteSwapExtent(&extent[i]); 620 } 621#endif 622 623 IOLog1("AppleLVMGroup::readLogicalVolumeEntry(%p): was successful, extent count = %u\n", this, (uint32_t)lve->lvExtentsCount); 624 return lveBuffer; 625} 626 627IOReturn AppleLVMGroup::writeLogicalVolumeEntry(IOBufferMemoryDescriptor * lveBuffer, UInt64 offset) 628{ 629 IOLog1("AppleLVMGroup::writeLogicalVolumeEntry(%p) lve offset %llu\n", this, offset); 630 631 AppleLVMVolumeOnDisk * lve = (AppleLVMVolumeOnDisk *)lveBuffer->getBytesNoCopy(); 632 if (strncmp(lve->lvMagic, kAppleLVMVolumeMagic, sizeof(lve->lvMagic))) { 633 lveBuffer->release(); 634 return NULL; 635 } 636 637#if defined(__LITTLE_ENDIAN__) 638 AppleRAIDExtentOnDisk *extent = (AppleRAIDExtentOnDisk *)((char *)lve + lve->lvExtentsStart); 639 UInt32 i; 640 for (i=0; i < lve->lvExtentsCount; i++) { 641 ByteSwapExtent(&extent[i]); 642 } 643 ByteSwapLVMVolumeHeader(lve); 644#endif 645 646 AppleRAIDMember * member; 647 UInt64 memberOffset; 648 if (!memberOffsetFromLVGOffset(offset, &member, &memberOffset)) { 649 return NULL; 650 } 651 652 return writeFromBuffer(member, lveBuffer, memberOffset); 653} 654 655bool AppleLVMGroup::clearLogicalVolumeEntry(UInt64 offset, UInt32 size) 656{ 657 IOLog1("AppleLVMGroup::clearLogicalVolumeEntry(%p) lve offset %llu size %u\n", this, offset, (uint32_t)size); 658 659 // Allocate a buffer to read into 660 IOBufferMemoryDescriptor * lveBuffer = IOBufferMemoryDescriptor::withCapacity(size, kIODirectionNone); 661 if (lveBuffer == 0) return NULL; 662 663 AppleLVMVolumeOnDisk * lve = (AppleLVMVolumeOnDisk *)lveBuffer->getBytesNoCopy(); 664 bzero(lve, size); 665 strncpy((char *)kAppleLVMVolumeFreeMagic, lve->lvMagic, sizeof(lve->lvMagic)); 666 667 AppleRAIDMember * member; 668 UInt64 memberOffset; 669 if (!memberOffsetFromLVGOffset(offset, &member, &memberOffset)) { 670 return NULL; 671 } 672 IOReturn rc = writeFromBuffer(member, lveBuffer, memberOffset); 673 674 lveBuffer->release(); 675 676 return rc == kIOReturnSuccess; 677} 678 679 680//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 681//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 682//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 683 684 685bool AppleLVMGroup::initializeSecondary(void) 686{ 687 arExtentCount = 0; 688 689 UInt64 startingOffset = 0; 690 UInt32 index; 691 for (index = 0; index < arMemberCount; index++) { 692 693 AppleRAIDMember * member = arMembers[index]; 694 UInt64 memberDataSize = arMemberBlockCounts[index] * arSetBlockSize; 695 if (!member || !memberDataSize) return false; 696 697 member->setHeaderProperty(kAppleRAIDMemberStartKey, startingOffset, 64); 698 699 arMemberStartingOffset[index] = startingOffset; 700 701 // the first extent represents the secondary metadata (in case it gets fragmented) 702 UInt64 secondaryOffset = startingOffset + member->getUsableSize() - member->getSecondarySize(); 703 UInt64 secondarySize = member->getSecondarySize(); 704 705 if (!secondaryOffset || !secondarySize) return false; 706 IOBufferMemoryDescriptor * lveBuffer = readLogicalVolumeEntry(secondaryOffset, /* auto size */ 0); 707 if (!lveBuffer) return false; 708 AppleLVMVolumeOnDisk * lve = (AppleLVMVolumeOnDisk *)lveBuffer->getBytesNoCopy(); 709 710 // patch the secondary metadata lve to lvg relative 711 AppleRAIDExtentOnDisk *extent = (AppleRAIDExtentOnDisk *)((char *)lve + lve->lvExtentsStart); 712 UInt32 i; 713 for (i=0; i < lve->lvExtentsCount; i++) { 714 extent[i].extentByteOffset = extent[i].extentByteOffset + startingOffset; 715 716 IOLog1("LVG initializeSecondary(%u) adding secondary offset %llu, size %llu\n", 717 (uint32_t)i, extent[i].extentByteOffset, extent[i].extentByteCount); 718 } 719 720 AppleLVMVolume * lv = AppleLVMVolume::withHeader(lve, NULL); 721 if (!lv) return false; 722 723 // add extents for secondary lve the logical volume group 724 if (!lv->addExtents(this, lve)) return false; 725 726 // track and later release master logical volumes 727 arMetaDataVolumes[index] = lv; 728 729 startingOffset += memberDataSize; 730 } 731 732 return true; 733} 734 735bool AppleLVMGroup::addExtentToLVG(AppleLVMLogicalExtent * extentToAdd) 736{ 737 // adjacent extents are not combined here as they could 738 // belong to different logical volumes 739 740 IOLog1("AppleLVMGroup::addExtentToLVG(): new extent start %llu size %llu\n", extentToAdd->lvExtentGroupOffset, extentToAdd->lvExtentSize); 741 742 // no entries 743 if (!arExtents) { 744 arExtents = extentToAdd; 745 arExtentCount++; 746 return true; 747 } 748 749 // first entry 750 if ((extentToAdd->lvExtentGroupOffset + extentToAdd->lvExtentSize) <= arExtents->lvExtentGroupOffset) { 751 extentToAdd->lvgNext = arExtents; 752 arExtents = extentToAdd; 753 arExtentCount++; 754 return true; 755 } 756 757 // find the extent before and after the new extent 758 AppleLVMLogicalExtent * extent = arExtents; 759 AppleLVMLogicalExtent * nextExtent = extent->lvgNext; 760 while (nextExtent) { 761 if (nextExtent->lvExtentGroupOffset > extentToAdd->lvExtentGroupOffset) break; 762 extent = nextExtent; 763 nextExtent = nextExtent->lvgNext; 764 } 765 766 if (extent->lvExtentGroupOffset == extentToAdd->lvExtentGroupOffset) { 767 IOLog("AppleLVMGroup::addExtentToLVG(): failed, the start of the new extent is already in use\n"); 768 return false; 769 } 770 771 if ((extent->lvExtentGroupOffset + extent->lvExtentSize) > extentToAdd->lvExtentGroupOffset) { 772 IOLog("AppleLVMGroup::addExtentToLVG(): failed, the new extent overlaps the end of a current extent\n"); 773 return false; 774 } 775 776 if (nextExtent && ((extentToAdd->lvExtentGroupOffset + extentToAdd->lvExtentSize) > nextExtent->lvExtentGroupOffset)) { 777 IOLog("AppleLVMGroup::addExtentToLVG(): failed, the new extent overlaps the beginning of a current extent\n"); 778 return false; 779 } 780 781 // new entry can be inserted after this entry 782 extent->lvgNext = extentToAdd; 783 extentToAdd->lvgNext = nextExtent; 784 arExtentCount++; 785 return true; 786} 787 788bool AppleLVMGroup::removeExtentFromLVG(AppleLVMLogicalExtent * extentToRemove) 789{ 790 // are there any extents to remove? 791 if (!arExtents) return false; 792 793 // find the extent that contains this region 794 AppleLVMLogicalExtent * prevExtent = 0; 795 AppleLVMLogicalExtent * extent = arExtents; 796 while (extent) { 797 if (extent == extentToRemove) break; 798 if (extent->lvExtentGroupOffset > extentToRemove->lvExtentGroupOffset) break; 799 prevExtent = extent; 800 extent = extent->lvgNext; 801 } 802 803 if (extent != extentToRemove) return false; 804 805 if (prevExtent) { 806 prevExtent->lvgNext = extent->lvgNext; 807 } else { 808 arExtents = extent->lvgNext; 809 } 810 extent->lvgNext = 0; 811 arExtentCount--; 812 return true; 813} 814 815bool AppleLVMGroup::buildExtentList(AppleRAIDExtentOnDisk * extentList) 816{ 817 AppleLVMLogicalExtent * incoreExtent = arExtents; 818 while (incoreExtent) { 819 extentList->extentByteOffset = incoreExtent->lvExtentGroupOffset; 820 extentList->extentByteCount = incoreExtent->lvExtentSize; 821 822 IOLog1("LVG build extent at %lld, size %lld\n", extentList->extentByteOffset, extentList->extentByteCount); 823 824 extentList++; 825 incoreExtent = incoreExtent->lvgNext; 826 } 827 828 return true; 829} 830 831UInt64 AppleLVMGroup::calculateFreeSpace(void) 832{ 833 AppleLVMLogicalExtent dummy; 834 dummy.lvgNext = arExtents; 835 dummy.lvExtentGroupOffset = dummy.lvExtentSize = 0; 836 837 UInt64 freeSpace = 0; 838 AppleLVMLogicalExtent * extent = &dummy; 839 AppleLVMLogicalExtent * next; 840 while ((next = extent->lvgNext)) { 841 842 freeSpace += next->lvExtentGroupOffset - (extent->lvExtentGroupOffset + extent->lvExtentSize); 843 844 extent = next; 845 } 846 847 return freeSpace; 848} 849 850//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 851//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 852//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 853 854 855bool AppleLVMGroup::addLogicalVolumeToTOC(AppleLVMVolume * lv) 856{ 857 // find empty index for this volume 858 UInt32 index = 0; 859 while (index < arLogicalVolumeCount) { 860 if (!arLogicalVolumes[index]) break; 861 index++; 862 } 863 if (index == arLogicalVolumeCount) arLogicalVolumeCount++; 864 865 arLogicalVolumeActiveCount++; 866 assert(arLogicalVolumeActiveCount <= arLogicalVolumeCount); 867 868 arLogicalVolumes[index] = lv; 869 lv->retain(); 870 871 lv->setIndex(index); 872 873 return true; 874} 875 876bool AppleLVMGroup::removeLogicalVolumeFromTOC(AppleLVMVolume * lv) 877{ 878 UInt32 index = lv->getIndex(); 879 880 if (arLogicalVolumes[index] == lv) { 881 882 arLogicalVolumes[index] = NULL; 883 lv->release(); 884 885 if (index == arLogicalVolumeCount) arLogicalVolumeCount--; 886 arLogicalVolumeActiveCount--; 887 assert(arLogicalVolumeActiveCount <= arLogicalVolumeCount); 888 889 return true; 890 } 891 892 IOLog("AppleLVMGroup::removeLogicalVolumeFromTOC() failed for lv %p\n", lv); 893 894 return false; 895} 896 897 898OSArray * AppleLVMGroup::buildLogicalVolumeListFromTOC(AppleRAIDMember * member) 899{ 900 UInt32 index; 901 OSArray * array = OSArray::withCapacity(arLogicalVolumeCount); 902 if (!array) return NULL; 903 904 for (index = 0; index < arLogicalVolumeCount; index++) { 905 906 AppleLVMVolume * lv = arLogicalVolumes[index]; 907 if (!lv) continue; 908 909 if (member && !lv->hasExtentsOnMember(member)) continue; 910 911 const OSString * uuid = lv->getVolumeUUID(); 912 if (uuid) { 913 array->setObject(uuid); 914 } 915 } 916 return array; 917} 918 919bool AppleLVMGroup::initializeVolumes(AppleRAIDPrimaryOnDisk * primary) 920{ 921 AppleLVGTOCEntryOnDisk * firstEntry = (AppleLVGTOCEntryOnDisk *)((char *)primary + sizeof(AppleRAIDPrimaryOnDisk)); 922 923 UInt32 index; 924 for (index = 0; index < arLogicalVolumeCount; index++) { 925 926 AppleLVGTOCEntryOnDisk * tocEntry = &firstEntry[index]; 927 928 UInt64 lveOffset = tocEntry->lveEntryOffset; 929 UInt64 lveSize = tocEntry->lveEntrySize; 930 if (!lveOffset || !lveSize) continue; // empty entries are zeroed 931 932 IOLog1("AppleLVMGroup::initializeVolumes: reading volume[%u] %s, size %llu\n", (uint32_t)index, tocEntry->lveUUID, tocEntry->lveVolumeSize); 933 934 IOBufferMemoryDescriptor * lveBuffer = readLogicalVolumeEntry(lveOffset, lveSize); 935 if (!lveBuffer) continue; 936 937 AppleLVMVolumeOnDisk * lve = (AppleLVMVolumeOnDisk *)lveBuffer->getBytesNoCopy(); 938 assert(lve); 939 940 AppleLVMVolume * lv = AppleLVMVolume::withHeader(lve, NULL); 941 if (!lv) { 942 lveBuffer->release(); 943 continue; 944 } 945 946 lv->setIndex(index); 947 lv->setEntryOffset(lveOffset); 948 949 // add extents to the logical volume group 950 if (!lv->addExtents(this, lve)) { 951 // XXX set volume status to offline, need check other calls to addExtents 952 } 953 lveBuffer->release(); 954 955 arLogicalVolumes[index] = lv; // no release 956 arLogicalVolumeActiveCount++; 957 assert(arLogicalVolumeActiveCount <= arLogicalVolumeCount); 958 959 arController->addLogicalVolume(lv); 960 } 961 962 // rescan list to enable snapshots 963 for (index = 0; index < arLogicalVolumeCount; index++) { 964 965 AppleLVMVolume * lv = arLogicalVolumes[index]; 966 if (!lv) continue; 967 968 AppleLVMVolume * parent = NULL;; 969 const OSString * parentUUID = lv->getParentUUID(); 970 if (parentUUID) parent = arController->findLogicalVolume(parentUUID); 971 if (parent) { 972 lv->setParent(parent); 973 if (lv->isABitMap()) parent->setBitMap(lv); 974 if (lv->isASnapShot()) parent->setSnapShot(lv); 975 } 976 } 977 978 return true; 979} 980 981//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 982//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 983//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 984 985 986// this was lifted from osfmk/kern/bits.c, there are also some better looking asm files 987// XXX this code sucks and needs a serious rewrite. 988 989 990#include <mach/machine/vm_param.h> /* for BYTE_SIZE */ 991 992#define INT_SIZE (BYTE_SIZE * sizeof (UInt32)) 993 994/* 995 * Set indicated bit in bit string. 996 */ 997static void 998setbit(UInt32 bitno, UInt32 *s) 999{ 1000 for ( ; INT_SIZE <= bitno; bitno -= INT_SIZE, ++s) 1001 ; 1002 *s |= 1 << bitno; 1003} 1004 1005/* 1006 * Clear indicated bit in bit string. 1007 */ 1008static void 1009clrbit(UInt32 bitno, UInt32 *s) 1010{ 1011 for ( ; INT_SIZE <= bitno; bitno -= INT_SIZE, ++s) 1012 ; 1013 *s &= ~(1 << bitno); 1014} 1015 1016/* 1017 * Find first bit set in bit string. 1018 */ 1019static UInt32 1020ffsbit(UInt32 *s) 1021{ 1022 UInt32 offset, mask; 1023 1024 for (offset = 0; !*s; offset += INT_SIZE, ++s) 1025 ; 1026 for (mask = 1; mask; mask <<= 1, ++offset) 1027 if (mask & *s) 1028 return (offset); 1029 /* 1030 * Shouldn't get here 1031 */ 1032 return (0); 1033} 1034 1035/* 1036 * Test if indicated bit is set in bit string. 1037 */ 1038//static UInt32 1039//testbit(UInt32 bitno, UInt32 *s) 1040//{ 1041// for ( ; INT_SIZE <= bitno; bitno -= INT_SIZE, ++s) 1042// ; 1043// return(*s & (1 << bitno)); 1044//} 1045 1046 1047//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1048//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1049//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888 1050 1051 1052// it would be nice to do this at user level but we already have most this cached in kernel 1053 1054UInt64 AppleLVMGroup::findFreeLVEOffset(AppleLVMVolume * lvNew) 1055{ 1056 // find the member that this should this go on 1057 AppleLVMLogicalExtent * firstExtent = lvNew->findExtent(0); 1058 if (!firstExtent) return 0; 1059 UInt32 lveMemberIndex = firstExtent->lvMemberIndex; 1060 1061 IOLog1("AppleLVMGroup::findFreeLVEOffset(): member %u selected\n", (uint32_t)lveMemberIndex); 1062 1063 // find secondary range for that member 1064 AppleRAIDMember * member = arMembers[lveMemberIndex]; 1065 if (!member) return 0; 1066 UInt64 secondaryStart = member->getUsableSize() - member->getSecondarySize(); 1067 UInt64 secondaryEnd = member->getUsableSize(); 1068 1069 IOLog1("AppleLVMGroup::findFreeLVEOffset(): secondaryStart = %llu\n", secondaryStart); 1070 IOLog1("AppleLVMGroup::findFreeLVEOffset(): secondaryEnd = %llu\n", secondaryEnd); 1071 1072 // allocate temp bitmap (1024 volumes / 8 bits/byte -> 256 bytes) 1073 UInt32 bitmapSize = member->getSecondarySize() / kAppleLVMVolumeOnDiskMinSize / 32; 1074 UInt32 * bitmap = IONew(UInt32, bitmapSize + 1); 1075 if (!bitmap) return 0; 1076 bzero(bitmap, bitmapSize * sizeof(UInt32)); 1077 bitmap[bitmapSize] = 0x55555555; // the end (backwards) 1078 1079 IOLog1("AppleLVMGroup::findFreeLVEOffset(): bitmap %p, size %u\n", bitmap, (uint32_t)bitmapSize * 32); 1080 1081 // add in metadata lve 1082 UInt32 bitIndex = 0; 1083 UInt32 entrySize = arMetaDataVolumes[lveMemberIndex]->getEntrySize() / kAppleLVMVolumeOnDiskMinSize; 1084 while (entrySize--) { 1085 setbit(bitIndex, bitmap); 1086 bitIndex++; 1087 } 1088 1089 // build the free list bitmap 1090 UInt32 i; 1091 for (i = 0; i < arLogicalVolumeCount; i++) { 1092 AppleLVMVolume * lv = arLogicalVolumes[i]; 1093 if (lv) { 1094 if (lv == lvNew) continue; 1095 if (lv->getEntryOffset() < secondaryStart) continue; 1096 if (lv->getEntryOffset() > secondaryEnd) continue; 1097 1098 // got one, substract it from free list bitmap 1099 bitIndex = (lv->getEntryOffset() - secondaryStart) / kAppleLVMVolumeOnDiskMinSize; 1100 1101 assert(bitIndex < bitmapSize * 32); 1102 if (bitIndex >= bitmapSize * 32) goto error; 1103 1104 entrySize = lv->getEntrySize(); 1105 assert(entrySize % kAppleLVMVolumeOnDiskMinSize == 0); 1106 if (entrySize % kAppleLVMVolumeOnDiskMinSize) goto error; 1107 1108 entrySize /= kAppleLVMVolumeOnDiskMinSize; 1109 while (entrySize--) { 1110 setbit(bitIndex, bitmap); 1111 bitIndex++; 1112 } 1113 } 1114 } 1115 1116 IOLog1("AppleLVMGroup::findFreeLVEOffset(): bitmap (31-0) 0x%08x 0x%08x 0x%08x 0x%08x\n", (uint32_t)bitmap[0], (uint32_t)bitmap[1], (uint32_t)bitmap[2], (uint32_t)bitmap[3]); 1117 1118 { 1119 UInt32 bitsNeeded = lvNew->getEntrySize() / kAppleLVMVolumeOnDiskMinSize; 1120 UInt32 lastBit = bitmapSize * 32; 1121 1122 IOLog1("AppleLVMGroup::findFreeLVEOffset(): bitsNeeded %u, lastBit %u\n", (uint32_t)bitsNeeded, (uint32_t)lastBit); 1123 1124 UInt32 firstBit = ffsbit(bitmap); 1125 if (firstBit >= lastBit) goto full; 1126 clrbit(firstBit, bitmap); 1127 1128 UInt32 nextBit = ffsbit(bitmap); 1129 clrbit(nextBit, bitmap); 1130 1131 UInt32 bitsGap = nextBit - firstBit - 1; 1132 while (bitsGap < bitsNeeded) { 1133 1134 firstBit = nextBit; 1135 if (firstBit >= lastBit) goto full; 1136 1137 nextBit = ffsbit(bitmap); 1138 clrbit(nextBit, bitmap); 1139 bitsGap = nextBit - firstBit - 1; 1140 } 1141 1142 IOLog1("AppleLVMGroup::findFreeLVEOffset(): firstBit %u, nextBit %u\n", (uint32_t)firstBit, (uint32_t)nextBit); 1143 1144 if (bitsGap >= bitsNeeded) return (firstBit + 1) * kAppleLVMVolumeOnDiskMinSize + secondaryStart; 1145 } 1146 1147full: 1148 1149 IOLog("AppleLVMGroup::findFreeLVEOffset(): there is no room for more volume entries\n"); 1150 1151 // XXXTOC should have code to compact the logical volume entries 1152 // XXXTOC should have code to allocate a larger secondary metadata area 1153 1154error: 1155 if (bitmap) IODelete(bitmap, UInt32, bitmapSize + 1); 1156 1157 return 0; 1158} 1159 1160 1161bool AppleLVMGroup::updateLVGTOC(void) 1162{ 1163 if (!arPrimaryBuffer) return false; 1164 1165 AppleRAIDPrimaryOnDisk * header = (AppleRAIDPrimaryOnDisk *)arPrimaryBuffer->getBytesNoCopy(); 1166 header->priSequenceNumber = arSequenceNumber; 1167 header->pri.volumeCount = arLogicalVolumeCount; 1168 header->priUsed = sizeof(AppleRAIDPrimaryOnDisk); 1169 header->priUsed += sizeof(AppleLVGTOCEntryOnDisk) * arLogicalVolumeCount; 1170 1171 if (header->priUsed > header->priSize) return false; // XXXTOC the header has already been messed with 1172 // so this is basically a fatal condition 1173 1174 if (header->priSize < arPrimaryBuffer->getLength()) { 1175 1176 // XXXTOC need to resize the buffer 1177 1178 // vm_size_t IOBufferMemoryDescriptor::getCapacity() const 1179 // IOBufferMemoryDescriptor::appendBytes(const void * bytes, vm_size_t withLength) 1180 // void IOBufferMemoryDescriptor::setLength(vm_size_t length) 1181 1182 return false; 1183 } 1184 1185 AppleLVGTOCEntryOnDisk * firstEntry = (AppleLVGTOCEntryOnDisk *)((char *)header + sizeof(AppleRAIDPrimaryOnDisk)); 1186 1187 UInt32 i; 1188 for (i = 0; i < arLogicalVolumeCount; i++) { 1189 1190 AppleLVGTOCEntryOnDisk * tocEntry = &firstEntry[i]; 1191 AppleLVMVolume * lv = arLogicalVolumes[i]; 1192 if (lv) { 1193 strncpy(tocEntry->lveUUID, (char *)lv->getVolumeUUIDString(), sizeof(tocEntry->lveUUID)); 1194 tocEntry->lveVolumeSize = lv->getClaimedSize(); 1195 tocEntry->lveEntryOffset = lv->getEntryOffset(); 1196 tocEntry->lveEntrySize = lv->getEntrySize(); 1197 bzero(&tocEntry->reserved, sizeof(tocEntry->reserved)); 1198 } else { 1199 bzero(tocEntry, sizeof(AppleLVGTOCEntryOnDisk)); 1200 } 1201 } 1202 1203 return true; 1204} 1205 1206 1207IOReturn AppleLVMGroup::createLogicalVolume(OSDictionary * lveProps, AppleLVMVolumeOnDisk * lve) 1208{ 1209 const OSString * parentUUID; 1210 AppleLVMVolume * parent; 1211 IOReturn rc = 0; 1212 UInt64 lveOffset = 0; 1213 IOBufferMemoryDescriptor * lveBuffer = NULL; 1214 1215 1216 // make sure the sequence number is not out of date 1217 UInt32 sequenceNumber = 0; 1218 OSNumber * number = OSDynamicCast(OSNumber, lveProps->getObject(kAppleLVMVolumeSequenceKey)); 1219 if (number) sequenceNumber = number->unsigned32BitValue(); 1220 if (!sequenceNumber || sequenceNumber != arSequenceNumber) { 1221 IOLog("AppleLVMGroup::createLogicalVolume() sequenceNumber mismatch (%u) for group %s (%u)\n", 1222 (uint32_t)sequenceNumber, getUUIDString(), (uint32_t)arSequenceNumber); 1223 return kIOReturnBadArgument; 1224 } 1225 1226 // create logical volume object, set up lv extents 1227 AppleLVMVolume * lv = AppleLVMVolume::withHeader(lve, lveProps); 1228 if (!lv) { rc = kIOReturnBadArgument; goto error; } 1229 1230 // add extents to the logical volume group 1231 if (!lv->addExtents(this, lve)) { rc = kIOReturnInternalError; goto error; } 1232 1233 // find empty slot to write the lve 1234 lveOffset = findFreeLVEOffset(lv); 1235 if (!lveOffset) return kIOReturnInternalError; 1236 IOLog1("AppleLVMGroup::createLogicalVolume() writing logical volume entry for %s at loffset %llu\n", lv->getVolumeUUIDString(), lveOffset); 1237 1238 // update lv 1239 lv->setEntryOffset(lveOffset); 1240 1241 // write entry to disk 1242 lveBuffer = IOBufferMemoryDescriptor::withBytes(lve, lve->lvHeaderSize, kIODirectionOut); 1243 rc = writeLogicalVolumeEntry(lveBuffer, lveOffset); 1244 lveBuffer->release(); 1245 if (rc) goto error; 1246 1247 // add to internal lists 1248 addLogicalVolumeToTOC(lv); 1249 arController->addLogicalVolume(lv); 1250 1251 bumpSequenceNumber(); 1252 1253 if (!updateLVGTOC()) goto error; 1254 rc = writePrimaryMetaData(arPrimaryBuffer); 1255 if (rc) goto error; 1256 1257 // update raid header 1258 writeRAIDHeader(); 1259 1260 if (lv->isAVolume() && !publishVolume(lv)) { 1261 rc = kIOReturnError; // XXX better error ? 1262 goto error; 1263 } 1264 1265// IOSleep(1000); // uncomment for 4943003 a "#1 bug" 1266 1267 parent = NULL; 1268 parentUUID = lv->getParentUUID(); 1269 if (parentUUID) parent = arController->findLogicalVolume(parentUUID); 1270 if (parent) { 1271 1272 lv->setParent(parent); 1273 1274 if (lv->isABitMap()) { 1275 if (!lv->zeroVolume()) { 1276 rc = kIOReturnError; // XXX better error ? 1277 goto error; 1278 } 1279 parent->setBitMap(lv); 1280 } 1281 1282 if (lv->isASnapShot()) { 1283 parent->setSnapShot(lv); 1284 } 1285 } 1286 1287 lv->release(); // keep here 1288 1289 return kIOReturnSuccess; 1290 1291error: 1292 1293 if (lv) lv->release(); 1294 return rc; 1295} 1296 1297 1298IOReturn AppleLVMGroup::updateLogicalVolume(AppleLVMVolume * lv, OSDictionary * lveProps, AppleLVMVolumeOnDisk * lve) 1299{ 1300 // make sure the sequence number is not out of date 1301 UInt32 sequenceNumber = 0; 1302 OSNumber * number = OSDynamicCast(OSNumber, lveProps->getObject(kAppleLVMVolumeSequenceKey)); 1303 if (number) sequenceNumber = number->unsigned32BitValue(); 1304 if (!sequenceNumber || sequenceNumber != arSequenceNumber) { 1305 IOLog("AppleLVMGroup::updateLogicalVolume() sequenceNumber mismatch (%u) for group %s (%u)\n", 1306 (uint32_t)sequenceNumber, getUUIDString(), (uint32_t)arSequenceNumber); 1307 return kIOReturnBadArgument; 1308 } 1309 1310 // XXX pause set? pause volume 1311 1312 if (!lv->initWithHeader(lveProps)) { 1313 return kIOReturnBadArgument; 1314 } 1315 1316 // refresh extent lists 1317 lv->removeExtents(this); 1318 if (!lv->addExtents(this, lve)) return kIOReturnInternalError; 1319 1320 // XXXTOC need to double check that the entry is still the same size 1321 // or find a new place to put it or just always find a new place 1322 1323 // find the offset for this lve 1324 UInt64 lveOffset = lv->getEntryOffset(); 1325 1326 // write entry to disk 1327 IOBufferMemoryDescriptor * lveBuffer = IOBufferMemoryDescriptor::withBytes(lve, lve->lvHeaderSize, kIODirectionOut); 1328 IOReturn rc = writeLogicalVolumeEntry(lveBuffer, lveOffset); 1329 lveBuffer->release(); 1330 if (rc) goto error; 1331 1332 bumpSequenceNumber(); 1333 1334 if (!updateLVGTOC()) goto error; 1335 rc = writePrimaryMetaData(arPrimaryBuffer); 1336 if (rc) goto error; 1337 1338 // update raid header 1339 writeRAIDHeader(); 1340 1341 if (lv->isAVolume() && !publishVolume(lv)) { 1342 return kIOReturnError; // XXX better error ? 1343 } 1344 1345 lv->messageClients(kAppleLVMMessageVolumeChanged); 1346 1347 return kIOReturnSuccess; 1348 1349error: 1350 1351 return rc; 1352} 1353 1354 1355IOReturn AppleLVMGroup::destroyLogicalVolume(AppleLVMVolume * lv) 1356{ 1357 1358 //XXX set state to offline, block and drain i/o 1359 1360 AppleLVMVolume * parent = lv->parentVolume(); 1361 if (parent && lv->isASnapShot()) parent->setSnapShot(NULL); 1362 if (parent && lv->isABitMap()) parent->setBitMap(NULL); 1363 1364 AppleLVMVolume * snapshot = lv->snapShotVolume(); 1365 if (snapshot) { 1366 lv->setSnapShot(NULL); 1367 destroyLogicalVolume(snapshot); 1368 } 1369 1370 AppleLVMVolume * bitmap = lv->bitMapVolume(); 1371 if (bitmap) { 1372 lv->setBitMap(NULL); 1373 destroyLogicalVolume(bitmap); 1374 } 1375 1376 // clear lv entry on the disk 1377 UInt64 lveOffset = lv->getEntryOffset(); 1378 UInt32 lveSize = lv->getEntrySize(); 1379 IOReturn rc = clearLogicalVolumeEntry(lveOffset, lveSize); 1380 if (rc) { 1381 // log an error, keep going 1382 } 1383 1384 // terminate logical volume 1385 if (lv->isPublished()) (void)unpublishVolume(lv); 1386 1387 // remove extents from global list (XXX do this from terminate on lv object?) 1388 lv->removeExtents(this); 1389 1390 // clear the TOC entry 1391 if (!removeLogicalVolumeFromTOC(lv)) return kIOReturnError; 1392 1393 arController->removeLogicalVolume(lv); 1394 1395 bumpSequenceNumber(); 1396 1397 if (!updateLVGTOC()) return kIOReturnInternalError; 1398 rc = writePrimaryMetaData(arPrimaryBuffer); 1399 if (rc) return rc; 1400 1401 // update raid header 1402 writeRAIDHeader(); 1403 1404 return kIOReturnSuccess; 1405} 1406 1407 1408bool AppleLVMGroup::publishVolume(AppleLVMVolume * lv) 1409{ 1410 IOLog1("AppleLVMGroup::publishVolume called %p, volume = %p\n", this, lv); 1411 1412 // are we (still) connected to the io registry? 1413 if (arActiveCount == 0) { 1414 IOLog1("AppleLVMGroup::publishVolume: the set %p is empty, aborting.\n", this); 1415 return false; 1416 } 1417 1418 if (!lv->getSequenceNumber() || lv->getSequenceNumber() > getSequenceNumber()) { 1419 // XXX set lv state to broken? 1420 return false; 1421 } 1422 1423 if (!lv->isAVolume()) { 1424 IOLog1("AppleLVMGroup::publishVolume: ignoring %p it is not a volume.\n", lv); 1425 return true; 1426 } 1427 1428 // Create the member object for the raid set. 1429 UInt64 volumeSize = lv->getClaimedSize(); 1430 bool isWritable = (lv->getTypeID() == kLVMTypeSnapRO) ? false : arIsWritable; 1431 const OSString * theHint = lv->getHint(); 1432 const char * contentHint = 0; 1433 if (theHint) contentHint = theHint->getCStringNoCopy(); 1434 1435 IOMediaAttributeMask attributes = arIsEjectable ? (kIOMediaAttributeEjectableMask | kIOMediaAttributeRemovableMask) : 0; 1436 if (lv->init(/* base */ 0, 1437 /* size */ volumeSize, 1438 /* preferredBlockSize */ arNativeBlockSize, 1439 /* attributes */ attributes, 1440 /* isWhole */ true, 1441 /* isWritable */ isWritable, 1442 /* contentHint */ contentHint)) { 1443 1444 lv->setName(getSetNameString()); 1445 1446 // Set a location value (partition number) for this partition. XXX this doesn't work 1447 // IOMediaBSDClient::getWholeMedia makes assumptions about the 1448 // ioreg layout, this tries to hack around that. 1449 char location[12]; 1450 snprintf(location, sizeof(location), "%ss%d", getLocation(), (uint32_t)lv->getIndex()); 1451 lv->setLocation(location); 1452 1453 OSArray * bootArray = OSArray::withCapacity(arMemberCount); 1454 if (bootArray) { 1455 // if any of the devices are not in the device tree 1456 // just return an empty array 1457 (void)addBootDeviceInfo(bootArray); 1458 lv->setProperty(kIOBootDeviceKey, bootArray); 1459 bootArray->release(); 1460 } 1461 1462 lv->setProperty(kIOMediaUUIDKey, (OSObject *)lv->getVolumeUUID()); 1463 lv->setProperty(kAppleLVMIsLogicalVolumeKey, kOSBooleanTrue); 1464 1465 if (getSetState() < kAppleRAIDSetStateOnline) { 1466 lv->setProperty("autodiskmount", kOSBooleanFalse); 1467 } else { 1468 lv->removeProperty("autodiskmount"); 1469 } 1470 1471 if (!lv->isPublished()) { 1472 lv->attach(this); 1473 lv->registerService(); 1474 lv->setPublished(true); 1475 } else { 1476 lv->messageClients(kIOMessageServicePropertyChange); 1477 } 1478 } 1479 1480 IOLog1("AppleLVMGroup::publishVolume: was successful for %p.\n", lv); 1481 1482 return true; 1483} 1484 1485 1486bool AppleLVMGroup::unpublishVolume(AppleLVMVolume * lv) 1487{ 1488 IOLog1("AppleLVMGroup::unpublishSet(%p) entered, volume = %p\n", this, lv); 1489 1490 lv->setPublished(false); 1491 1492 return lv->terminate(kIOServiceRequired | kIOServiceSynchronous); 1493} 1494 1495 1496void AppleLVMGroup::completeRAIDRequest(AppleRAIDStorageRequest * storageRequest) 1497{ 1498 UInt32 cnt; 1499 UInt64 byteCount; 1500 IOReturn status; 1501 bool isWrite; 1502 1503 // this is running in the workloop, via a AppleRAIDEvent 1504 1505 isWrite = (storageRequest->srMemoryDescriptorDirection == kIODirectionOut); 1506 byteCount = 0; 1507 status = kIOReturnSuccess; 1508 1509 // Collect the status and byte count for each request 1510 for (cnt = 0; cnt < storageRequest->srRequestCount; cnt++) { 1511 1512 // Return any status errors. 1513 if (storageRequest->srRequestStatus[cnt] != kIOReturnSuccess) { 1514 status = storageRequest->srRequestStatus[cnt]; 1515 byteCount = 0; 1516 1517 AppleRAIDMemoryDescriptor * memoryDescriptor = storageRequest->srMemoryDescriptors[cnt]; 1518 AppleRAIDMember * member = arMembers[memoryDescriptor->mdMemberIndex]; 1519 1520 if (!member) continue; // XXX should have already logged an error 1521 1522 IOLog("AppleLVMGroup::completeRAIDRequest - error 0x%x detected for set \"%s\" (%s), member %s, near lv byte offset = %llu.\n", 1523 status, getSetNameString(), getUUIDString(), member->getUUIDString(), storageRequest->srByteStart); 1524 1525 // mark this member to be removed 1526 member->changeMemberState(kAppleRAIDMemberStateClosing); 1527 continue; 1528 } 1529 1530 byteCount += storageRequest->srRequestByteCounts[cnt]; 1531 1532 IOLogRW("AppleLVMGroup::completeRAIDRequest - [%u] tbc 0x%llx, sbc 0x%llx bc 0x%llx, member %p\n", 1533 (uint32_t)cnt, storageRequest->srByteCount, storageRequest->srRequestByteCounts[cnt], 1534 byteCount, arMembers[cnt]); 1535 } 1536 1537 // XXX before checking for an underrun, first check to see if we need to schedule more i/o 1538 // the check below should probably be checking the expected bytes for a partial i/o 1539 1540 // Return an underrun error if the byte count is not complete. 1541 // This can happen if one or more members reported a smaller byte count. 1542 if ((status == kIOReturnSuccess) && (byteCount != storageRequest->srByteCount)) { 1543 IOLog("AppleLVMGroup::completeRAIDRequest - underrun detected, expected = 0x%llx, actual = 0x%llx, set = \"%s\" (%s)\n", 1544 storageRequest->srByteCount, byteCount, getSetNameString(), getUUIDString()); 1545 status = kIOReturnUnderrun; 1546 byteCount = 0; 1547 } 1548 1549 storageRequest->srMemoryDescriptor->release(); 1550 returnRAIDRequest(storageRequest); 1551 1552 // Call the clients completion routine, bad status is also returned here. 1553 IOStorage::complete(&storageRequest->srClientsCompletion, status, byteCount); 1554} 1555