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 IOMedia
26OSDefineMetaClassAndStructors(AppleLVMVolume, IOMedia)
27
28
29OSDictionary * AppleLVMVolume::propsFromHeader(AppleLVMVolumeOnDisk * lve)
30{
31    OSString * errmsg = 0;
32    OSDictionary * lvProps = OSDynamicCast(OSDictionary, OSUnserializeXML(lve->plist, &errmsg));
33    if (!lvProps) {
34	if (errmsg) {
35	    IOLog("AppleLVMVolume::propsFromHeader - XML parsing failed with %s\n", errmsg->getCStringNoCopy());
36	    errmsg->release();
37	}
38	return NULL;
39    }
40
41    return lvProps;
42}
43
44
45AppleLVMVolume * AppleLVMVolume::withHeader(AppleLVMVolumeOnDisk * lve, OSDictionary * lvProps)
46{
47    if (!lve) return false;
48
49    if (!lvProps) lvProps = AppleLVMVolume::propsFromHeader(lve);
50    if (!lvProps) return false;
51
52    AppleLVMVolume *me = new AppleLVMVolume;
53    if (!me) return NULL;
54
55    if (!me->init() || !me->initWithHeader(lvProps)) {
56        me->release();
57        return NULL;
58    }
59
60    me->lvEntrySize = lve->lvHeaderSize;
61
62    return me;
63}
64
65
66//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
67//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
68//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
69
70
71void AppleLVMVolume::free()
72{
73    if (lvProps) lvProps->release();
74
75//    if (lvSnapShot) lvSnapShot->release();
76//    if (lvParent) lvParent->release();
77//    if (lvBitMap) lvBitMap->release();
78
79    AppleLVMLogicalExtent * extent = NULL;
80    AppleLVMLogicalExtent * nextExtent = lvExtent[0];
81    while (nextExtent) {
82	extent = nextExtent;
83	nextExtent = nextExtent->skip[0];
84	delete extent;
85    }
86
87    super::free();
88}
89
90
91bool AppleLVMVolume::init(void)
92{
93    if (!OSObject::init()) return false;  // why?  more "using" weirdness?
94
95    lvIndex = 0xffffffff;
96    lvSequenceNumber = 0;
97    lvClaimedSize = 0;
98    lvCalculatedSize = 0;
99    lvTypeID = 0;
100    lvEntryOffset = 0;
101
102    lvExtentCount = 0;
103    lvExtent[0] = NULL;
104
105    lvPublished = false;
106
107    lvParent = NULL;
108    lvSnapShot = NULL;
109    lvBitMap = NULL;
110
111    return true;
112}
113
114bool AppleLVMVolume::initWithHeader(OSDictionary * props)
115{
116    IOLog1("AppleLVMVolume::initWithHeader() entered\n");
117
118    if (lvProps) lvProps->release();
119    lvProps = props;
120    lvProps->retain();
121
122    if (!getVolumeUUID()) return false;
123    if (!getGroupUUID()) return false;
124
125    OSNumber * number;
126    number = OSDynamicCast(OSNumber, lvProps->getObject(kAppleLVMVolumeSequenceKey));
127    if (!number) return false;
128    lvSequenceNumber = number->unsigned32BitValue();
129
130    number = OSDynamicCast(OSNumber, lvProps->getObject(kAppleLVMVolumeExtentCountKey));
131    if (!number) return false;
132    lvExtentCount = number->unsigned64BitValue();
133
134    number = OSDynamicCast(OSNumber, lvProps->getObject(kAppleLVMVolumeSizeKey));
135    if (!number) return false;
136    lvClaimedSize = number->unsigned64BitValue();
137
138    OSString * type = OSDynamicCast(OSString, lvProps->getObject(kAppleLVMVolumeTypeKey));
139    if (!type) return false;
140    if (type->isEqualTo(kAppleLVMVolumeTypeConcat)) lvTypeID = kLVMTypeConcat;
141    if (type->isEqualTo(kAppleLVMVolumeTypeBitMap)) lvTypeID = kLVMTypeBitMap;
142    if (type->isEqualTo(kAppleLVMVolumeTypeSnapRO)) lvTypeID = kLVMTypeSnapRO;
143    if (type->isEqualTo(kAppleLVMVolumeTypeSnapRW)) lvTypeID = kLVMTypeSnapRW;
144    if (type->isEqualTo(kAppleLVMVolumeTypeMaster)) lvTypeID = kLVMTypeMaster;
145    if (!lvTypeID) return false;
146
147    lvSnapShot = NULL;  // just clear these, they might not exist yet.
148    lvBitMap = NULL;
149    lvParent = NULL;
150
151    IOLog1("AppleLVMVolume::initWithHeader() successful for %s, size = %llu extent count = %llu\n",
152	   getVolumeUUIDString(), lvClaimedSize, lvExtentCount);
153
154    return true;
155}
156
157
158//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
159//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
160//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
161
162
163OSDictionary * AppleLVMVolume::getVolumeProperties(void)
164{
165    // make a copy
166    assert(lvProps);
167    OSDictionary * props = OSDictionary::withDictionary(lvProps, lvProps->getCount() + 2);
168    if (!props) return NULL;
169
170    // not from header
171    OSString * status = NULL;
172    if (isPublished()) {
173	status = OSString::withCString(kAppleRAIDStatusOnline);
174    } else {
175	status = OSString::withCString(kAppleRAIDStatusOffline);
176    }
177    if (status) {
178	props->setObject(kAppleLVMVolumeStatusKey, status);
179	status->release();
180    }
181
182    props->setObject(kIOBSDNameKey, getDiskName());
183
184    return props;
185}
186
187
188const OSString * AppleLVMVolume::getVolumeUUID(void)
189{
190    assert(lvProps);
191    const OSString * string = OSDynamicCast(OSString, lvProps->getObject(kAppleLVMVolumeUUIDKey));
192
193    return string;
194}
195
196
197const char * AppleLVMVolume::getVolumeUUIDString(void)
198{
199    const OSString * uuid = getVolumeUUID();
200
201    return uuid ? uuid->getCStringNoCopy() : "--internal error, uuid not set--";
202}
203
204
205const OSString * AppleLVMVolume::getDiskName(void)
206{
207    if (!getPropertyTable()) return NULL;  // this panics if not set (unpublished)
208    const OSMetaClassBase * name = getProperty(kIOBSDNameKey);
209    if (!name) return NULL;
210    return OSDynamicCast(OSString, name);
211}
212
213
214const OSString * AppleLVMVolume::getGroupUUID(void)
215{
216    assert(lvProps);
217    const OSString * lvgUUID = OSDynamicCast(OSString, lvProps->getObject(kAppleLVMGroupUUIDKey));
218
219    return lvgUUID;
220}
221
222
223const OSString * AppleLVMVolume::getParentUUID(void)
224{
225    assert(lvProps);
226    const OSString * parentUUID = (OSDynamicCast(OSString, lvProps->getObject(kAppleLVMParentUUIDKey)));
227
228    return parentUUID;
229}
230
231
232const OSString * AppleLVMVolume::getHint(void)   // IOMedia also has getContentHint()
233{
234    assert(lvProps);
235    const OSString * hint = OSDynamicCast(OSString, lvProps->getObject(kAppleLVMVolumeContentHintKey));
236
237    return hint;
238}
239
240
241//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
242//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
243//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
244
245
246bool AppleLVMVolume::addExtents(AppleLVMGroup * lvg, AppleLVMVolumeOnDisk * lve)
247{
248
249    // XXX failure cases need to mark lv as broken
250
251    AppleRAIDExtentOnDisk * extent = (AppleRAIDExtentOnDisk *)((char *)lve + lve->lvExtentsStart);
252    if ((void *)(extent + lvExtentCount) > (void *)((char *)lve + lve->lvHeaderSize - sizeof(AppleRAIDExtentOnDisk))) {
253	IOLog("AppleLVMVolume::addExtents() too many extents detected for logical volume \"%s\"\n", getVolumeUUIDString());
254	return false;
255    }
256
257    UInt64 count = lvExtentCount;
258    while (count) {
259	AppleLVMLogicalExtent * newExtent = addExtent(lvg, extent);
260	if (!newExtent) {
261	    IOLog("AppleLVMVolume::addExtents() overlapping extent detected in logical volume \"%s\"\n", getVolumeUUIDString());
262	    return false;
263	}
264	if (!lvg->addExtentToLVG(newExtent)) {
265	    IOLog("AppleLVMVolume::addExtents() overlapping logical volumes detected for logical volume \"%s\"\n", getVolumeUUIDString());
266	    return false;
267	}
268	count--;
269	extent++;
270    }
271
272    if (lvClaimedSize != lvCalculatedSize) {
273	IOLog("AppleLVMVolume::addExtents() size error for extent list for logical volume \"%s\"\n", getVolumeUUIDString());
274	IOLog("AppleLVMVolume::addExtents() expected size %llu, calculated size %llu\n", lvClaimedSize, lvCalculatedSize);
275	return false;
276    }
277
278    IOLog1("AppleLVMVolume::addExtents() successful for %s, extent count = %llu, size = %llu\n",
279	   getVolumeUUIDString(), lvExtentCount, lvCalculatedSize);
280
281    return true;
282}
283
284AppleLVMLogicalExtent * AppleLVMVolume::addExtent(AppleLVMGroup * lvg, AppleRAIDExtentOnDisk * extentOnDisk)
285{
286    AppleLVMLogicalExtent ** extent = &lvExtent[0];
287    AppleLVMLogicalExtent * extentInCore = new AppleLVMLogicalExtent;
288    UInt64 volumeOffset = 0;
289
290    // find end of list
291    while (*extent) {
292	volumeOffset += (*extent)->lvExtentSize;
293	extent = &((*extent)->skip[0]);
294    }
295
296    // XXX hm, there is no range checking here
297
298    extentInCore->skip[0] = 0;
299    extentInCore->lvgNext = 0;
300
301    extentInCore->lvMemberIndex = lvg->getMemberIndexFromOffset(extentOnDisk->extentByteOffset);
302
303    extentInCore->lvExtentVolumeOffset = volumeOffset;
304    extentInCore->lvExtentGroupOffset = extentOnDisk->extentByteOffset;
305    extentInCore->lvExtentMemberOffset = extentOnDisk->extentByteOffset - lvg->getMemberStartingOffset(extentInCore->lvMemberIndex);
306
307    extentInCore->lvExtentSize = extentOnDisk->extentByteCount;
308
309    *extent = extentInCore;
310    lvCalculatedSize = volumeOffset + extentInCore->lvExtentSize;
311
312    IOLog1("AppleLVMVolume::addExtent() successful, offset = %llu, size = %llu totalSize = %llu\n",   // XXX <<<<<<<< log2
313	   extentInCore->lvExtentVolumeOffset, extentInCore->lvExtentSize, lvCalculatedSize);
314
315    return extentInCore;
316}
317
318bool AppleLVMVolume::removeExtents(AppleLVMGroup * lvg)
319{
320    AppleLVMLogicalExtent * extent = lvExtent[0];
321    AppleLVMLogicalExtent * prevExtent;
322    lvExtent[0] = NULL;
323    lvCalculatedSize = 0;
324    while (extent) {
325
326	lvg->removeExtentFromLVG(extent);
327
328	prevExtent = extent;
329	extent = extent->skip[0];
330
331	delete prevExtent;
332    }
333
334    return true;
335}
336
337AppleLVMLogicalExtent * AppleLVMVolume::findExtent(UInt64 offset)
338{
339    // find the extent relative to the offset in this volume
340
341    AppleLVMLogicalExtent * extent = lvExtent[0];
342    AppleLVMLogicalExtent * nextExtent = extent ? extent->skip[0] : NULL;
343    while (nextExtent) {
344	if (nextExtent->lvExtentVolumeOffset > offset) break;
345	extent = nextExtent;
346	nextExtent = nextExtent->skip[0];
347    }
348
349    return extent;
350}
351
352bool AppleLVMVolume::hasExtentsOnMember(AppleRAIDMember * member)
353{
354    UInt32 memberIndex = member->getMemberIndex();
355
356    AppleLVMLogicalExtent * extent = lvExtent[0];
357    while (extent) {
358	if (extent->lvMemberIndex == memberIndex) return true;
359	extent = extent->skip[0];
360    }
361
362    return false;
363}
364
365bool AppleLVMVolume::buildExtentList(AppleRAIDExtentOnDisk * extentList)
366{
367    AppleLVMLogicalExtent * incoreExtent = lvExtent[0];
368    while (incoreExtent) {
369	extentList->extentByteOffset = incoreExtent->lvExtentGroupOffset;
370	extentList->extentByteCount = incoreExtent->lvExtentSize;
371
372	extentList++;
373	incoreExtent = incoreExtent->skip[0];
374    }
375
376    return true;
377}
378
379
380//
381//  snapshot stuff
382//
383
384bool AppleLVMVolume::setParent(AppleLVMVolume * parent)
385{
386    lvParent = parent;
387
388    // XXXSNAP
389
390    return true;
391}
392
393bool AppleLVMVolume::setBitMap(AppleLVMVolume * bitmap)
394{
395    lvBitMap = bitmap;
396
397    // XXXSNAP
398
399    return true;
400}
401
402
403bool AppleLVMVolume::setSnapShot(AppleLVMVolume * snapshot)
404{
405    lvSnapShot = snapshot;
406
407    // XXXSNAP
408
409    return true;
410}
411
412
413bool AppleLVMVolume::zeroVolume()
414{
415    assert(isABitMap());
416
417    // XXXSNAP
418    // call into a bitmap object?
419
420    return true;
421}
422
423