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