1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // This file describes the on-disk format of MinFS
6 
7 #pragma once
8 
9 #include <bitmap/raw-bitmap.h>
10 #include <bitmap/storage.h>
11 #include <fbl/macros.h>
12 
13 #include <zircon/types.h>
14 
15 #include <assert.h>
16 #include <limits.h>
17 #include <limits>
18 #include <stdbool.h>
19 #include <stdint.h>
20 
21 // clang-format off
22 
23 namespace minfs {
24 
25 // Type of a reference to block number, either absolute (able to index
26 // into disk directly) or relative to some entity (such as a file).
27 typedef uint32_t blk_t;
28 
29 // The type of an inode number, which may be used as an
30 // index into the inode table.
31 typedef uint32_t ino_t;
32 
33 constexpr uint64_t kMinfsMagic0         = (0x002153466e694d21ULL);
34 constexpr uint64_t kMinfsMagic1         = (0x385000d3d3d3d304ULL);
35 constexpr uint32_t kMinfsVersion        = 0x00000007;
36 
37 constexpr ino_t    kMinfsRootIno        = 1;
38 constexpr uint32_t kMinfsFlagClean      = 0x00000001; // Currently unused
39 constexpr uint32_t kMinfsFlagFVM        = 0x00000002; // Mounted on FVM
40 constexpr uint32_t kMinfsBlockSize      = 8192;
41 constexpr uint32_t kMinfsBlockBits      = (kMinfsBlockSize * 8);
42 constexpr uint32_t kMinfsInodeSize      = 256;
43 constexpr uint32_t kMinfsInodesPerBlock = (kMinfsBlockSize / kMinfsInodeSize);
44 
45 constexpr uint32_t kMinfsDirect         = 16;
46 constexpr uint32_t kMinfsIndirect       = 31;
47 constexpr uint32_t kMinfsDoublyIndirect = 1;
48 
49 constexpr uint32_t kMinfsDirectPerIndirect  = (kMinfsBlockSize / sizeof(blk_t));
50 constexpr uint32_t kMinfsDirectPerDindirect = kMinfsDirectPerIndirect * kMinfsDirectPerIndirect;
51 // not possible to have a block at or past this one
52 // due to the limitations of the inode and indirect blocks
53 // constexpr uint64_t kMinfsMaxFileBlock = (kMinfsDirect +
54 //                                         (kMinfsIndirect * kMinfsDirectPerIndirect)
55 //                                         + (kMinfsDoublyIndirect * kMinfsDirectPerIndirect
56 //                                         * kMinfsDirectPerIndirect));
57 // TODO(ZX-1523): Remove this artificial cap when MinFS can safely deal
58 // with files larger than 4GB.
59 constexpr uint64_t kMinfsMaxFileBlock = (std::numeric_limits<uint32_t>::max() / kMinfsBlockSize)
60                                         - 1;
61 constexpr uint64_t kMinfsMaxFileSize  = kMinfsMaxFileBlock * kMinfsBlockSize;
62 
63 constexpr uint32_t kMinfsTypeFile = 8;
64 constexpr uint32_t kMinfsTypeDir  = 4;
65 
MinfsMagic(uint32_t T)66 constexpr uint32_t MinfsMagic(uint32_t T) { return 0xAA6f6e00 | T; }
67 constexpr uint32_t kMinfsMagicDir  = MinfsMagic(kMinfsTypeDir);
68 constexpr uint32_t kMinfsMagicFile = MinfsMagic(kMinfsTypeFile);
MinfsMagicType(uint32_t n)69 constexpr uint32_t MinfsMagicType(uint32_t n) { return n & 0xFF; }
70 
71 constexpr size_t kFVMBlockInodeBmStart = 0x10000;
72 constexpr size_t kFVMBlockDataBmStart  = 0x20000;
73 constexpr size_t kFVMBlockInodeStart   = 0x30000;
74 constexpr size_t kFVMBlockJournalStart = 0x40000;
75 constexpr size_t kFVMBlockDataStart    = 0x50000;
76 
77 constexpr blk_t kJournalEntryHeaderMaxBlocks = 2040;
78 
79 struct Superblock {
80     uint64_t magic0;
81     uint64_t magic1;
82     uint32_t version;
83     uint32_t flags;
84     uint32_t block_size;    // 8K typical
85     uint32_t inode_size;    // 256
86     uint32_t block_count;   // total number of data blocks
87     uint32_t inode_count;   // total number of inodes
88     uint32_t alloc_block_count; // total number of allocated data blocks
89     uint32_t alloc_inode_count; // total number of allocated inodes
90     blk_t ibm_block;           // first blockno of inode allocation bitmap
91     blk_t abm_block;           // first blockno of block allocation bitmap
92     blk_t ino_block;           // first blockno of inode table
93     blk_t journal_start_block; // first blockno available for journal
94     blk_t dat_block;           // first blockno available for file data
95     // The following flags are only valid with (flags & kMinfsFlagFVM):
96     uint64_t slice_size;     // Underlying slice size
97     uint64_t vslice_count;   // Number of allocated underlying slices
98     uint32_t ibm_slices;     // Slices allocated to inode bitmap
99     uint32_t abm_slices;     // Slices allocated to block bitmap
100     uint32_t ino_slices;     // Slices allocated to inode table
101     uint32_t journal_slices; // Slices allocated to journal section
102     uint32_t dat_slices;     // Slices allocated to file data section
103 
104     ino_t unlinked_head;    // Index to the first unlinked (but open) inode.
105     ino_t unlinked_tail;    // Index to the last unlinked (but open) inode.
106 };
107 
108 static_assert(sizeof(Superblock) <= kMinfsBlockSize,
109               "minfs info size is wrong");
110 // Notes:
111 // - the inode bitmap, block bitmap, inode table, journal, and data
112 //   regions must be in that order and may not overlap
113 // - the abm has an entry for every block on the volume, including
114 //   the info block (0), the bitmaps, etc
115 // - data blocks referenced from direct and indirect block tables
116 //   in inodes are also relative to (0), but it is not legal for
117 //   a block number of less than dat_block (start of data blocks)
118 //   to be used
119 // - inode numbers refer to the inode in block:
120 //     ino_block + ino / kMinfsInodesPerBlock
121 //   at offset: ino % kMinfsInodesPerBlock
122 // - inode 0 is never used, should be marked allocated but ignored
123 
124 constexpr uint64_t kJournalMagic = (0x6d696e6a75726e6cULL);
125 
126 // The minimal number of slices to allocate a MinFS partition:
127 // Superblock, Inode bitmap, Data bitmap, Inode Table, Journal (2), and actual data.
128 constexpr size_t kMinfsMinimumSlices = 7;
129 
130 constexpr uint64_t kMinfsDefaultInodeCount = 32768;
131 
132 struct JournalInfo {
133     uint64_t magic;
134     uint64_t reserved0;
135     uint64_t reserved1;
136     uint64_t reserved2;
137     uint64_t reserved3;
138 };
139 
140 static_assert(sizeof(JournalInfo) <= kMinfsBlockSize, "Journal info size is too large");
141 
142 struct Inode {
143     uint32_t magic;
144     uint32_t size;
145     uint32_t block_count;
146     uint32_t link_count;
147     uint64_t create_time;
148     uint64_t modify_time;
149     uint32_t seq_num;               // bumped when modified
150     uint32_t gen_num;               // bumped when deleted
151     uint32_t dirent_count;          // for directories
152     ino_t last_inode;               // index to the previous unlinked inode
153     ino_t next_inode;               // index to the next unlinked inode
154     uint32_t rsvd[3];
155     blk_t dnum[kMinfsDirect];    // direct blocks
156     blk_t inum[kMinfsIndirect];  // indirect blocks
157     blk_t dinum[kMinfsDoublyIndirect]; // doubly indirect blocks
158 };
159 
160 static_assert(sizeof(Inode) == kMinfsInodeSize,
161               "minfs inode size is wrong");
162 
163 struct Dirent {
164     ino_t ino;                      // inode number
165     uint32_t reclen;                // Low 28 bits: Length of record
166                                     // High 4 bits: Flags
167     uint8_t namelen;                // length of the filename
168     uint8_t type;                   // kMinfsType*
169     char name[];                    // name does not have trailing \0
170 };
171 
172 constexpr uint32_t MINFS_DIRENT_SIZE = sizeof(Dirent);
173 
DirentSize(uint8_t namelen)174 constexpr uint32_t DirentSize(uint8_t namelen) {
175     return MINFS_DIRENT_SIZE + ((namelen + 3) & (~3));
176 }
177 
178 constexpr uint8_t kMinfsMaxNameSize       = 255;
179 // The largest acceptable value of DirentSize(dirent->namelen).
180 // The 'dirent->reclen' field may be larger after coalescing
181 // entries.
182 constexpr uint32_t kMinfsMaxDirentSize    = DirentSize(kMinfsMaxNameSize);
183 constexpr uint32_t kMinfsMaxDirectorySize = (((1 << 20) - 1) & (~3));
184 
185 static_assert(kMinfsMaxNameSize >= NAME_MAX,
186               "MinFS names must be large enough to hold NAME_MAX characters");
187 
188 constexpr uint32_t kMinfsReclenMask = 0x0FFFFFFF;
189 constexpr uint32_t kMinfsReclenLast = 0x80000000;
190 
MinfsReclen(Dirent * de,size_t off)191 constexpr uint32_t MinfsReclen(Dirent* de, size_t off) {
192     return (de->reclen & kMinfsReclenLast) ?
193            kMinfsMaxDirectorySize - static_cast<uint32_t>(off) :
194            de->reclen & kMinfsReclenMask;
195 }
196 
197 static_assert(kMinfsMaxDirectorySize <= kMinfsReclenMask,
198               "MinFS directory size must be smaller than reclen mask");
199 
200 // Notes:
201 // - dirents with ino of 0 are free, and skipped over on lookup
202 // - reclen must be a multiple of 4
203 // - the last record in a directory has the "kMinfsReclenLast" flag set. The
204 //   actual size of this record can be computed from the offset at which this
205 //   record starts. If the MAX_DIR_SIZE is increased, this 'last' record will
206 //   also increase in size.
207 
208 // blocksize   8K    16K    32K
209 // 16 dir =  128K   256K   512K
210 // 32 ind =  512M  1024M  2048M
211 
212 //  1GB ->  128K blocks ->  16K bitmap (2K qword)
213 //  4GB ->  512K blocks ->  64K bitmap (8K qword)
214 // 32GB -> 4096K blocks -> 512K bitmap (64K qwords)
215 
216 // Block Cache (bcache.c)
217 constexpr uint32_t kMinfsHashBits = (8);
218 
219 } // namespace minfs
220