2  * Copyright (c) 2008 Apple Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  27 #include "ExtentManager.h" 
  30 ExtentManager::Init(uint32_t theBlockSize
, uint32_t theNativeBlockSize
, off_t theTotalBytes
) 
  32         blockSize 
= theBlockSize
; 
  33         nativeBlockSize 
= theNativeBlockSize
; 
  34         totalBytes 
= theTotalBytes
; 
  35         totalBlocks 
= howmany(totalBytes
, blockSize
); 
  37         // add sentry empty extents at both sides so empty partition doesn't need to be handled specially 
  38         AddBlockRangeExtent(0, 0); 
  39         AddBlockRangeExtent(totalBlocks
, 0); 
  43 ExtentManager::MergeExtent(const ExtentInfo 
&a
, const ExtentInfo 
&b
, ExtentInfo 
*c
) 
  45         // merge ext into *curIt 
  46         c
->blockAddr 
= min(a
.blockAddr
, b
.blockAddr
); 
  47         c
->numBlocks 
= max(a
.blockAddr 
+ a
.numBlocks
, b
.blockAddr 
+ b
.numBlocks
) - c
->blockAddr
; 
  51 ExtentManager::AddBlockRangeExtent(off_t blockAddr
, off_t numBlocks
) 
  53         struct ExtentInfo ext
, newExt
; 
  54         ListExtIt curIt
, newIt
; 
  57         // make the range a valid range 
  58         if ((blockAddr 
> totalBlocks
) || (blockAddr 
+ numBlocks 
< 0)) { // totally out of range, do nothing 
  62                 numBlocks 
= blockAddr 
+ numBlocks
; 
  65         if (blockAddr 
+ numBlocks 
> totalBlocks
) { 
  66                 numBlocks 
= totalBlocks 
- blockAddr
; 
  69         ext
.blockAddr 
= blockAddr
; 
  70         ext
.numBlocks 
= numBlocks
; 
  72         for (curIt 
= extentList
.begin(); curIt 
!= extentList
.end(); curIt
++) { 
  73                 if (BeforeExtent(ext
, *curIt
)) 
  75                 if (!BeforeExtent(*curIt
, ext
)) { // overlapped extents 
  76                         MergeExtent(ext
, *curIt
, &newExt
); 
  83         // insert ext before curIt 
  85                 curIt 
= extentList
.insert(curIt
, ext
); // throws bad_alloc when out of memory 
  90         curIt 
= extentList
.begin(); 
  91         while (curIt 
!= extentList
.end()) { 
  92                 if (curIt 
== newIt 
|| BeforeExtent(*curIt
, *newIt
)) { // curIt is before newIt 
  96                 if (BeforeExtent(*newIt
, *curIt
)) { // curIt is after newIt now, we are done 
  99                 // merge the two extents 
 100                 MergeExtent(*curIt
, *newIt
, &newExt
); 
 102                 curIt 
= extentList
.erase(curIt
); 
 104         // printf("After %s(%lld, %lld)\n", __func__, blockAddr, numBlocks);     DebugPrint(); 
 105 } // ExtentManager::AddBlockRangeExtent 
 108 ExtentManager::RemoveBlockRangeExtent(off_t blockAddr
, off_t numBlocks
) 
 110         struct ExtentInfo ext
, newExt
; 
 113         ext
.blockAddr 
= blockAddr
; 
 114         ext
.numBlocks 
= numBlocks
; 
 116         curIt 
= extentList
.begin(); 
 117         while (curIt 
!= extentList
.end()) { 
 118                 if (BeforeExtent(*curIt
, ext
)) { 
 122                 if (BeforeExtent(ext
, *curIt
)) // we are done 
 124                 // overlapped extents 
 125                 if (curIt
->blockAddr 
>= ext
.blockAddr 
&& 
 126                         curIt
->blockAddr 
+ curIt
->numBlocks 
<= ext
.blockAddr 
+ ext
.numBlocks
) { 
 127                         // *curIt is totally within ext, remove curIt 
 128                         curIt 
= extentList
.erase(curIt
); 
 129                 } else if (curIt
->blockAddr 
< ext
.blockAddr 
&& 
 130                         curIt
->blockAddr 
+ curIt
->numBlocks 
> ext
.blockAddr 
+ ext
.numBlocks
) { 
 131                         // ext is totally within *curIt, split ext into two 
 132                         newExt
.blockAddr 
= ext
.blockAddr 
+ ext
.numBlocks
; 
 133                         newExt
.numBlocks 
= curIt
->blockAddr 
+ curIt
->numBlocks 
- newExt
.blockAddr
; 
 134                         curIt
->numBlocks 
= ext
.blockAddr 
- curIt
->blockAddr
; 
 136                         extentList
.insert(curIt
, newExt
); // throws bad_alloc when out of memory 
 138                 } else { // remove part of ext 
 139                         if (curIt
->blockAddr 
>= ext
.blockAddr
) { // remove the former part of *curIt 
 140                                 assert(curIt
->blockAddr 
+ curIt
->numBlocks 
> newExt
.blockAddr
); 
 141                                 newExt
.blockAddr 
= ext
.blockAddr 
+ ext
.numBlocks
; 
 142                                 newExt
.numBlocks 
= curIt
->blockAddr 
+ curIt
->numBlocks 
- newExt
.blockAddr
; 
 144                         } else { // remove the latter part of *curIt 
 145                                 curIt
->numBlocks 
= ext
.blockAddr 
- curIt
->blockAddr
; 
 150         //printf("After %s(%lld, %lld)\n", __func__, blockAddr, numBlocks);      DebugPrint(); 
 154 ExtentManager::AddByteRangeExtent(off_t byteAddr
, off_t numBytes
) 
 156         off_t blockAddr 
= byteAddr 
/ blockSize
; 
 157         off_t blockAddrOfLastByte 
= (byteAddr 
+ numBytes 
- 1) / blockSize
; 
 158         off_t numBlocks 
= blockAddrOfLastByte 
- blockAddr 
+ 1; 
 159         AddBlockRangeExtent(blockAddr
, numBlocks
); 
 163 ExtentManager::DebugPrint() 
 167         for (it 
= extentList
.begin(); it 
!= extentList
.end(); it
++) { 
 168                 printf("[%lld, %lld] ", it
->blockAddr
, it
->numBlocks
);