FreeNOS
LinnFileSystem.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2009 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <Types.h>
19#include <Assert.h>
20#include "LinnFileSystem.h"
21#include "LinnInode.h"
22#include "LinnFile.h"
23#include "LinnDirectory.h"
24
26 : FileSystemServer(ZERO, p), storage(s), groups(ZERO)
27{
28 LinnInode *rootInode;
29 LinnGroup *group;
30 Size offset;
32
33 // Read out the superblock.
34 if ((e = s->read(LINN_SUPER_OFFSET, &super,
35 sizeof(super))) != FileSystem::Success)
36 {
37 FATAL("reading superblock failed: result = " << (int) e);
38 }
39 // Verify magic.
42 {
43 FATAL("magic mismatch");
44 }
45 // Create groups vector.
47 assert(groups != NULL);
49
50 // Read out group descriptors.
51 for (Size i = 0; i < LINN_GROUP_COUNT(&super); i++)
52 {
53 // Allocate buffer.
54 group = new LinnGroup;
55 assert(group != NULL);
56 offset = (super.groupsTable * super.blockSize) +
57 (sizeof(LinnGroup) * i);
58
59 // Read from storage.
60 if ((e = s->read(offset, group, sizeof(LinnGroup))) != FileSystem::Success)
61 {
62 FATAL("reading group descriptor failed: result = " << (int) e);
63 }
64 // Insert in the groups vector.
65 groups->insert(i, group);
66 }
67 // Print out superblock information.
68
69 INFO(LINN_GROUP_COUNT(&super) << " group descriptors");
70 INFO(super.inodesCount - super.freeInodesCount << " inodes, " <<
71 super.blocksCount - super.freeBlocksCount << " blocks");
72
73 // Read out the root directory.
74 rootInode = getInode(LINN_INODE_ROOT);
75 LinnDirectory *dir = new LinnDirectory(this, LINN_INODE_ROOT, rootInode);
76 assert(dir != NULL);
77 setRoot(dir);
78
79 // Done.
80 NOTICE("mounted at " << p);
81}
82
84{
85 LinnGroup *group;
86 LinnInode *inode;
87 Size offset;
89
90 // Validate the inode number.
91 if (inodeNum >= super.inodesCount)
92 {
93 return ZERO;
94 }
95 // Do we have this Inode cached already?
96 if (inodes.contains(inodeNum))
97 {
98 return inodes.value(inodeNum);
99 }
100 // Get the group descriptor.
101 if (!(group = getGroupByInode(inodeNum)))
102 {
103 return ZERO;
104 }
105 // Allocate inode buffer.
106 inode = new LinnInode;
107 assert(inode != NULL);
108 offset = (group->inodeTable * super.blockSize) +
109 ((inodeNum % super.inodesPerGroup) * sizeof(LinnInode));
110
111 // Read inode from storage.
112 if ((e = storage->read(offset, inode, sizeof(LinnInode))) != FileSystem::Success)
113 {
114 ERROR("reading inode failed: result = " << (int) e);
115 return ZERO;
116 }
117 // Insert into the cache.
118 inodes.insert(inodeNum, inode);
119 return inode;
120}
121
123{
124 return (*groups)[groupNum];
125}
126
128{
129 return getGroup(inodeNum ? inodeNum / super.inodesPerGroup : 0);
130}
131
133 const u32 blk,
134 Size & numContiguous)
135{
136 static u32 block[LINN_MAX_BLOCK_SIZE / sizeof(u32)];
137 const u64 numPerBlock = LINN_SUPER_NUM_PTRS(&super);
138 const Size numBlocks = LINN_INODE_NUM_BLOCKS(&super, inode);
139 Size depth = ZERO, remain = 1;
140 u64 offset;
141
142 assert(LINN_SUPER_NUM_PTRS(&super) <= sizeof(block) / sizeof(u32));
143
144 // Direct blocks.
145 if (blk < LINN_INODE_DIR_BLOCKS)
146 {
147 const u32 offsetBlock = inode->block[blk];
148 numContiguous = 1;
149
150 for (Size i = blk + 1; i < numBlocks && i < LINN_INODE_DIR_BLOCKS; i++)
151 {
152 if (inode->block[i] == offsetBlock + numContiguous)
153 numContiguous++;
154 else
155 break;
156 }
157
158 return offsetBlock * super.blockSize;
159 }
160 // Indirect blocks.
161 if (blk - LINN_INODE_DIR_BLOCKS < numPerBlock)
162 {
163 depth = 1;
164 }
165 // Double indirect blocks.
166 else if (blk - LINN_INODE_DIR_BLOCKS < numPerBlock * numPerBlock)
167 {
168 depth = 2;
169 }
170 // Triple indirect blocks.
171 else
172 {
173 depth = 3;
174 }
175
176 // Prepare read offset for the lookup
177 offset = inode->block[(LINN_INODE_DIR_BLOCKS + depth - 1)];
178 offset *= super.blockSize;
179
180 // Lookup the block number.
181 while (true)
182 {
183 // Fetch block.
184 if (storage->read(offset, block, super.blockSize) != FileSystem::Success)
185 {
186 return 0;
187 }
188 // Calculate the number of blocks remaining per entry.
189 for (Size i = 0; i < depth - 1; i++)
190 {
191 remain *= LINN_SUPER_NUM_PTRS(&super);
192 }
193 // More indirection?
194 if (remain == 1)
195 {
196 break;
197 }
198 // Calculate the next offset.
199 offset = block[ (blk - LINN_INODE_DIR_BLOCKS) / remain ];
200 offset *= super.blockSize;
201 remain = 1;
202 depth--;
203 }
204
205 // Calculate the final offset.
206 const u32 offsetBlock = block[(blk - LINN_INODE_DIR_BLOCKS) % numPerBlock];
207
208 // Calculate number of contiguous blocks following this block
209 numContiguous = 1;
210
211 for (Size i = blk + 1; i < numBlocks && (i % numPerBlock) != 0; i++)
212 {
213 if (block[(i - LINN_INODE_DIR_BLOCKS) % numPerBlock] == offsetBlock + numContiguous)
214 numContiguous++;
215 else
216 break;
217 }
218
219 // All done.
220 return offsetBlock * super.blockSize;
221}
222
virtual bool contains(const K &key) const
Check if the given key exists.
Abstract filesystem class.
void setRoot(Directory *newRoot)
Change the filesystem root directory.
void sendResponse(FileSystemMessage *msg) const
Send response for a FileSystemMessage.
virtual const V value(const K &key, const V defaultValue=V()) const
Return the first value for the given key.
Definition HashTable.h:325
virtual bool insert(const K &key, const V &value)
Inserts the given item to the HashTable.
Definition HashTable.h:133
Represents an directory on a LinnFS filesystem.
void notSupportedHandler(FileSystemMessage *msg)
Callback handler for unsupported operations.
LinnInode * getInode(u32 inodeNum)
Read an inode from the filesystem.
LinnSuperBlock super
Describes the filesystem.
Storage * storage
Provides storage.
LinnGroup * getGroupByInode(u32 inodeNum)
Read a group descriptor from the filesystem, given an inode number.
LinnFileSystem(const char *path, Storage *storage)
Class constructor function.
Vector< LinnGroup * > * groups
Group descriptors.
LinnGroup * getGroup(u32 groupNum)
Read a group descriptor from the filesystem.
u64 getOffsetRange(const LinnInode *inode, const u32 blk, Size &numContiguous)
Calculates the offset inside storage for a given block.
HashTable< u32, LinnInode * > inodes
Inode cache.
virtual void fill(T value)
Fill the Sequence with the given value.
Definition Sequence.h:73
Provides a storage device to build filesystems on top.
Definition Storage.h:36
virtual FileSystem::Result read(const u64 offset, void *buffer, const Size size) const =0
Read a contiguous set of data.
Vectors are dynamically resizeable Arrays.
Definition Vector.h:42
virtual int insert(const T &item)
Adds the given item to the Vector, if possible.
Definition Vector.h:93
#define assert(exp)
Insert program diagnostics.
Definition assert.h:60
#define NULL
NULL means zero.
Definition Macros.h:39
unsigned int u32
Unsigned 32-bit number.
Definition Types.h:53
#define INFO(msg)
Output a regular message to standard output.
Definition Log.h:82
#define ERROR(msg)
Output an error message.
Definition Log.h:61
#define NOTICE(msg)
Output a notice message.
Definition Log.h:75
#define FATAL(msg)
Output a critical message and terminate program immediatly.
Definition Log.h:50
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define ZERO
Zero value.
Definition Macros.h:43
unsigned long long u64
Unsigned 64-bit number.
Definition Types.h:50
#define LINN_MAX_BLOCK_SIZE
Maximum blocksize.
#define LINN_SUPER_MAGIC1
Second magic number (randomly chosen bytes).
#define LINN_SUPER_MAGIC0
First magic number ('Linn').
#define LINN_INODE_DIR_BLOCKS
Direct blocks.
Definition LinnInode.h:49
#define LINN_GROUP_COUNT(sb)
Calculate the number of LinnGroups in a filesystem.
Definition LinnGroup.h:64
#define LINN_SUPER_OFFSET
Fixed offset in storage of the superblock.
#define LINN_INODE_ROOT
Root inode.
Definition LinnInode.h:37
#define LINN_SUPER_NUM_PTRS(sb)
Calculate the number of block address pointers fitting in one block.
#define LINN_INODE_NUM_BLOCKS(super, inode)
Calculate the number of blocks used in an LinnInode.
Definition LinnInode.h:80
Result
Result code for filesystem Actions.
Definition FileSystem.h:53
FileSystem IPC message.
FileSystem::Result result
Result code.
Structure of a group descriptor.
Definition LinnGroup.h:130
le32 inodeTable
Inode table contains pre-allocated inodes.
Definition LinnGroup.h:144
Structure of an inode on the disk in the LinnFS filesystem.
Definition LinnInode.h:93
le32 block[LINN_INODE_BLOCKS]
Pointers to blocks.
Definition LinnInode.h:104
le32 groupsTable
Block address of the LinnGroup table.
le32 inodesCount
Total number of inodes.
le32 magic0
Allows detection of valid superblocks.
le32 freeInodesCount
Free inodes remaining.
le32 blockSize
Size of each data block.
le32 magic1
Allows detection of valid superblocks.
le32 inodesPerGroup
Number of inodes per group.
le32 blocksCount
Total number of data blocks.
le32 freeBlocksCount
Number of free data blocks.