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);
48  groups->fill(ZERO);
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 
224 {
226  sendResponse(msg);
227 }
LinnSuperBlock::freeInodesCount
le32 freeInodesCount
Free inodes remaining.
Definition: LinnSuperBlock.h:128
LINN_MAX_BLOCK_SIZE
#define LINN_MAX_BLOCK_SIZE
Maximum blocksize.
Definition: LinnFileSystem.h:51
Types.h
NOTICE
#define NOTICE(msg)
Output a notice message.
Definition: Log.h:75
LinnFileSystem::inodes
HashTable< u32, LinnInode * > inodes
Inode cache.
Definition: LinnFileSystem.h:180
LinnSuperBlock::magic0
le32 magic0
Allows detection of valid superblocks.
Definition: LinnSuperBlock.h:115
FileSystemServer::setRoot
void setRoot(Directory *newRoot)
Change the filesystem root directory.
Definition: FileSystemServer.cpp:649
LINN_INODE_NUM_BLOCKS
#define LINN_INODE_NUM_BLOCKS(super, inode)
Calculate the number of blocks used in an LinnInode.
Definition: LinnInode.h:80
LinnInode::block
le32 block[LINN_INODE_BLOCKS]
Pointers to blocks.
Definition: LinnInode.h:104
LinnSuperBlock::magic1
le32 magic1
Allows detection of valid superblocks.
Definition: LinnSuperBlock.h:116
LinnFileSystem::groups
Vector< LinnGroup * > * groups
Group descriptors.
Definition: LinnFileSystem.h:177
Assert.h
FileSystemServer::sendResponse
void sendResponse(FileSystemMessage *msg) const
Send response for a FileSystemMessage.
Definition: FileSystemServer.cpp:536
LinnGroup
Structure of a group descriptor.
Definition: LinnGroup.h:129
FileSystemMessage
FileSystem IPC message.
Definition: FileSystemMessage.h:37
FileSystemServer
Abstract filesystem class.
Definition: FileSystemServer.h:44
FileSystem::Success
@ Success
Definition: FileSystem.h:54
LinnSuperBlock::inodesCount
le32 inodesCount
Total number of inodes.
Definition: LinnSuperBlock.h:125
FileSystemMessage::result
FileSystem::Result result
Result code.
Definition: FileSystemMessage.h:40
Sequence::fill
virtual void fill(T value)
Fill the Sequence with the given value.
Definition: Sequence.h:73
LinnGroup::inodeTable
le32 inodeTable
Inode table contains pre-allocated inodes.
Definition: LinnGroup.h:144
LinnSuperBlock::freeBlocksCount
le32 freeBlocksCount
Number of free data blocks.
Definition: LinnSuperBlock.h:127
LinnFileSystem::getInode
LinnInode * getInode(u32 inodeNum)
Read an inode from the filesystem.
Definition: LinnFileSystem.cpp:83
u64
unsigned long long u64
Unsigned 64-bit number.
Definition: Types.h:50
FileSystem::NotSupported
@ NotSupported
Definition: FileSystem.h:61
LinnFileSystem::super
LinnSuperBlock super
Describes the filesystem.
Definition: LinnFileSystem.h:174
LINN_SUPER_NUM_PTRS
#define LINN_SUPER_NUM_PTRS(sb)
Calculate the number of block address pointers fitting in one block.
Definition: LinnSuperBlock.h:103
FATAL
#define FATAL(msg)
Output a critical message and terminate program immediatly.
Definition: Log.h:50
Associative::contains
virtual bool contains(const K &key) const
Check if the given key exists.
Definition: Associative.h:111
LinnFileSystem::getGroup
LinnGroup * getGroup(u32 groupNum)
Read a group descriptor from the filesystem.
Definition: LinnFileSystem.cpp:122
LINN_SUPER_OFFSET
#define LINN_SUPER_OFFSET
Fixed offset in storage of the superblock.
Definition: LinnSuperBlock.h:85
LinnDirectory.h
LinnFileSystem::storage
Storage * storage
Provides storage.
Definition: LinnFileSystem.h:171
LinnInode.h
LINN_SUPER_MAGIC1
#define LINN_SUPER_MAGIC1
Second magic number (randomly chosen bytes).
Definition: LinnSuperBlock.h:40
INFO
#define INFO(msg)
Output a regular message to standard output.
Definition: Log.h:82
LINN_SUPER_MAGIC0
#define LINN_SUPER_MAGIC0
First magic number ('Linn').
Definition: LinnSuperBlock.h:37
NULL
#define NULL
NULL means zero.
Definition: Macros.h:39
u32
unsigned int u32
Unsigned 32-bit number.
Definition: Types.h:53
LinnInode
Structure of an inode on the disk in the LinnFS filesystem.
Definition: LinnInode.h:92
LinnFileSystem::notSupportedHandler
void notSupportedHandler(FileSystemMessage *msg)
Callback handler for unsupported operations.
Definition: LinnFileSystem.cpp:223
Size
unsigned int Size
Any sane size indicator cannot go negative.
Definition: Types.h:128
LinnFileSystem::getGroupByInode
LinnGroup * getGroupByInode(u32 inodeNum)
Read a group descriptor from the filesystem, given an inode number.
Definition: LinnFileSystem.cpp:127
Vector::insert
virtual int insert(const T &item)
Adds the given item to the Vector, if possible.
Definition: Vector.h:93
LinnSuperBlock::groupsTable
le32 groupsTable
Block address of the LinnGroup table.
Definition: LinnSuperBlock.h:135
LINN_GROUP_COUNT
#define LINN_GROUP_COUNT(sb)
Calculate the number of LinnGroups in a filesystem.
Definition: LinnGroup.h:64
LinnDirectory
Represents an directory on a LinnFS filesystem.
Definition: LinnDirectory.h:44
LINN_INODE_ROOT
#define LINN_INODE_ROOT
Root inode.
Definition: LinnInode.h:37
LINN_INODE_DIR_BLOCKS
#define LINN_INODE_DIR_BLOCKS
Direct blocks.
Definition: LinnInode.h:49
assert
#define assert(exp)
Insert program diagnostics.
Definition: assert.h:60
ERROR
#define ERROR(msg)
Output an error message.
Definition: Log.h:61
FileSystem::Result
Result
Result code for filesystem Actions.
Definition: FileSystem.h:52
LinnSuperBlock::blocksCount
le32 blocksCount
Total number of data blocks.
Definition: LinnSuperBlock.h:126
LinnSuperBlock::blockSize
le32 blockSize
Size of each data block.
Definition: LinnSuperBlock.h:121
Storage::read
virtual FileSystem::Result read(const u64 offset, void *buffer, const Size size) const =0
Read a contiguous set of data.
LinnInode
struct LinnInode LinnInode
Structure of an inode on the disk in the LinnFS filesystem.
LinnFileSystem::LinnFileSystem
LinnFileSystem(const char *path, Storage *storage)
Class constructor function.
Definition: LinnFileSystem.cpp:25
LinnFile.h
LinnGroup
struct LinnGroup LinnGroup
Structure of a group descriptor.
Vector< LinnGroup * >
ZERO
#define ZERO
Zero value.
Definition: Macros.h:43
Storage
Provides a storage device to build filesystems on top.
Definition: Storage.h:35
HashTable::insert
virtual bool insert(const K &key, const V &value)
Inserts the given item to the HashTable.
Definition: HashTable.h:133
LinnSuperBlock::inodesPerGroup
le32 inodesPerGroup
Number of inodes per group.
Definition: LinnSuperBlock.h:123
HashTable::value
virtual const V value(const K &key, const V defaultValue=V()) const
Return the first value for the given key.
Definition: HashTable.h:325
LinnFileSystem.h
LinnFileSystem::getOffsetRange
u64 getOffsetRange(const LinnInode *inode, const u32 blk, Size &numContiguous)
Calculates the offset inside storage for a given block.
Definition: LinnFileSystem.cpp:132