github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fsimpl/ext/disklayout/extent.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package disklayout 16 17 import ( 18 "github.com/SagerNet/gvisor/pkg/marshal" 19 ) 20 21 // Extents were introduced in ext4 and provide huge performance gains in terms 22 // data locality and reduced metadata block usage. Extents are organized in 23 // extent trees. The root node is contained in inode.BlocksRaw. 24 // 25 // Terminology: 26 // - Physical Block: 27 // Filesystem data block which is addressed normally wrt the entire 28 // filesystem (addressed with 48 bits). 29 // 30 // - File Block: 31 // Data block containing *only* file data and addressed wrt to the file 32 // with only 32 bits. The (i)th file block contains file data from 33 // byte (i * sb.BlockSize()) to ((i+1) * sb.BlockSize()). 34 35 const ( 36 // ExtentHeaderSize is the size of the header of an extent tree node. 37 ExtentHeaderSize = 12 38 39 // ExtentEntrySize is the size of an entry in an extent tree node. 40 // This size is the same for both leaf and internal nodes. 41 ExtentEntrySize = 12 42 43 // ExtentMagic is the magic number which must be present in the header. 44 ExtentMagic = 0xf30a 45 ) 46 47 // ExtentEntryPair couples an in-memory ExtendNode with the ExtentEntry that 48 // points to it. We want to cache these structs in memory to avoid repeated 49 // disk reads. 50 // 51 // Note: This struct itself does not represent an on-disk struct. 52 type ExtentEntryPair struct { 53 // Entry points to the child node on disk. 54 Entry ExtentEntry 55 // Node points to child node in memory. Is nil if the current node is a leaf. 56 Node *ExtentNode 57 } 58 59 // ExtentNode represents an extent tree node. For internal nodes, all Entries 60 // will be ExtendIdxs. For leaf nodes, they will all be Extents. 61 // 62 // Note: This struct itself does not represent an on-disk struct. 63 type ExtentNode struct { 64 Header ExtentHeader 65 Entries []ExtentEntryPair 66 } 67 68 // ExtentEntry represents an extent tree node entry. The entry can either be 69 // an ExtentIdx or Extent itself. This exists to simplify navigation logic. 70 type ExtentEntry interface { 71 marshal.Marshallable 72 73 // FileBlock returns the first file block number covered by this entry. 74 FileBlock() uint32 75 76 // PhysicalBlock returns the child physical block that this entry points to. 77 PhysicalBlock() uint64 78 } 79 80 // ExtentHeader emulates the ext4_extent_header struct in ext4. Each extent 81 // tree node begins with this and is followed by `NumEntries` number of: 82 // - Extent if `Depth` == 0 83 // - ExtentIdx otherwise 84 // 85 // +marshal 86 type ExtentHeader struct { 87 // Magic in the extent magic number, must be 0xf30a. 88 Magic uint16 89 90 // NumEntries indicates the number of valid entries following the header. 91 NumEntries uint16 92 93 // MaxEntries that could follow the header. Used while adding entries. 94 MaxEntries uint16 95 96 // Height represents the distance of this node from the farthest leaf. Please 97 // note that Linux incorrectly calls this `Depth` (which means the distance 98 // of the node from the root). 99 Height uint16 100 _ uint32 101 } 102 103 // ExtentIdx emulates the ext4_extent_idx struct in ext4. Only present in 104 // internal nodes. Sorted in ascending order based on FirstFileBlock since 105 // Linux does a binary search on this. This points to a block containing the 106 // child node. 107 // 108 // +marshal 109 type ExtentIdx struct { 110 FirstFileBlock uint32 111 ChildBlockLo uint32 112 ChildBlockHi uint16 113 _ uint16 114 } 115 116 // Compiles only if ExtentIdx implements ExtentEntry. 117 var _ ExtentEntry = (*ExtentIdx)(nil) 118 119 // FileBlock implements ExtentEntry.FileBlock. 120 func (ei *ExtentIdx) FileBlock() uint32 { 121 return ei.FirstFileBlock 122 } 123 124 // PhysicalBlock implements ExtentEntry.PhysicalBlock. It returns the 125 // physical block number of the child block. 126 func (ei *ExtentIdx) PhysicalBlock() uint64 { 127 return (uint64(ei.ChildBlockHi) << 32) | uint64(ei.ChildBlockLo) 128 } 129 130 // Extent represents the ext4_extent struct in ext4. Only present in leaf 131 // nodes. Sorted in ascending order based on FirstFileBlock since Linux does a 132 // binary search on this. This points to an array of data blocks containing the 133 // file data. It covers `Length` data blocks starting from `StartBlock`. 134 // 135 // +marshal 136 type Extent struct { 137 FirstFileBlock uint32 138 Length uint16 139 StartBlockHi uint16 140 StartBlockLo uint32 141 } 142 143 // Compiles only if Extent implements ExtentEntry. 144 var _ ExtentEntry = (*Extent)(nil) 145 146 // FileBlock implements ExtentEntry.FileBlock. 147 func (e *Extent) FileBlock() uint32 { 148 return e.FirstFileBlock 149 } 150 151 // PhysicalBlock implements ExtentEntry.PhysicalBlock. It returns the 152 // physical block number of the first data block this extent covers. 153 func (e *Extent) PhysicalBlock() uint64 { 154 return (uint64(e.StartBlockHi) << 32) | uint64(e.StartBlockLo) 155 }