AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
inode.c
Go to the documentation of this file.
1
6
7#include <ext2.h>
8#include <ds/bitmap.h>
9
12static inline off_t ext2_inode_off(struct ext2 *desc, ino_t ino)
13{
14 /* invalid inode */
15 if (!ino || ino > desc->superblock->ninodes)
16 return -EINVAL;
17
18 uint32_t group_id = (ino - 1) / desc->superblock->ginodes;
19 uint32_t index = (ino - 1) % desc->superblock->ginodes;
20
21 struct ext2_group *group = &desc->groups[group_id];
22 return group->inodes * desc->bs + index * desc->inode_size;
23}
24
33int ext2_inode_read(struct ext2 *desc, ino_t ino, struct ext2_inode *ref)
34{
35 off_t off;
36
37 if ((off = ext2_inode_off(desc, ino)) < 0)
38 return off;
39
40 return ref ? ext2_io(desc, 0, off, sizeof(struct ext2_inode), ref) : 0;
41}
42
51int ext2_inode_write(struct ext2 *desc, ino_t ino, struct ext2_inode *ext2_inode)
52{
53 off_t off = ext2_inode_off(desc, ino);
54
55 if (off < 0)
56 return off;
57
58 return ext2_io(desc, 1, off, sizeof(struct ext2_inode), ext2_inode);
59}
60
61/* the inode's slot for its singly indirect pointer (12); the doubly and
62 * triply indirect ones follow */
63#define SLOT_SINGLY EXT2_DIRECT_POINTERS
64
73static int block_tree(struct ext2 *desc, size_t idx, int *slot, size_t *rel)
74{
75 size_t p = desc->bs / 4; /* pointers per block */
76
77 if (idx < EXT2_DIRECT_POINTERS) {
78 *slot = idx;
79 *rel = 0;
80 return 0;
81 }
82
84
85 for (size_t depth = 1, n = p; depth <= 3; ++depth, n *= p) {
86 if (idx < n) {
87 *slot = SLOT_SINGLY + depth - 1;
88 *rel = idx;
89 return depth;
90 }
91
92 idx -= n;
93 }
94
95 return -EFBIG;
96}
97
101static uint32_t slot_get(struct ext2_inode *inode, int slot)
102{
103 switch (slot) {
104 case SLOT_SINGLY: return inode->singly_indirect_pointer;
105 case SLOT_SINGLY + 1: return inode->doubly_indirect_pointer;
106 case SLOT_SINGLY + 2: return inode->triply_indirect_pointer;
107 default: return inode->direct_pointer[slot];
108 }
109}
110
112static void slot_set(struct ext2_inode *inode, int slot, uint32_t block)
113{
114 switch (slot) {
115 case SLOT_SINGLY: inode->singly_indirect_pointer = block; break;
116 case SLOT_SINGLY + 1: inode->doubly_indirect_pointer = block; break;
117 case SLOT_SINGLY + 2: inode->triply_indirect_pointer = block; break;
118 default: inode->direct_pointer[slot] = block; break;
119 }
120}
121
124static size_t tree_span(struct ext2 *desc, int depth)
125{
126 size_t span = 1;
127
128 while (depth-- > 1)
129 span *= desc->bs / 4;
130
131 return span;
132}
133
144int ext2_inode_block_read(struct ext2 *desc, struct ext2_inode *inode, size_t idx, void *buf)
145{
146 int slot;
147 size_t rel;
148 int depth = block_tree(desc, idx, &slot, &rel), err = 0;
149
150 if (depth < 0)
151 return depth;
152
153 uint32_t block = slot_get(inode, slot);
154
155 if (depth && block) {
156 uint32_t *table = kmalloc(desc->bs, &M_BUFFER, 0);
157
158 if (!table)
159 return -ENOMEM;
160
161 for (; depth && block; --depth) {
162 size_t span = tree_span(desc, depth);
163
164 if ((err = ext2_block_read(desc, block, table)))
165 break;
166
167 block = table[rel / span];
168 rel %= span;
169 }
170
171 kfree(table);
172
173 if (err)
174 return err;
175 }
176
177 if (!block) { /* a hole in a sparse file */
178 memset(buf, 0, desc->bs);
179 return 0;
180 }
181
182 return ext2_block_read(desc, block, buf);
183}
184
187static int ext2_inode_block_alloc(struct ext2 *desc, struct ext2_inode *inode, uint32_t *block)
188{
189 int err;
190
191 if ((err = ext2_block_alloc(desc, block)))
192 return err;
193
194 inode->blocks += desc->bs / 512;
195 return 0;
196}
197
200static int ext2_indirect_block_get(struct ext2 *desc, struct ext2_inode *inode, uint32_t table, size_t idx, uint32_t *block)
201{
202 int err = 0;
203 uint32_t *tmp = kmalloc(desc->bs, &M_BUFFER, 0);
204
205 if (!tmp)
206 return -ENOMEM;
207
208 if ((err = ext2_block_read(desc, table, tmp)))
209 goto done;
210
211 if (!(*block = tmp[idx])) { /* none yet: allocate one */
212 if (!(err = ext2_inode_block_alloc(desc, inode, block))) {
213 tmp[idx] = *block;
214 err = ext2_block_write(desc, table, tmp);
215 }
216 }
217
218done:
219 kfree(tmp);
220 return err;
221}
222
235int ext2_inode_block_write(struct ext2 *desc, struct ext2_inode *inode, uint32_t inode_nr, size_t idx, void *buf)
236{
237 uint32_t nblocks = inode->blocks;
238 int slot;
239 size_t rel;
240 int depth = block_tree(desc, idx, &slot, &rel), err = 0;
241
242 if (depth < 0)
243 return depth;
244
245 uint32_t block = slot_get(inode, slot);
246
247 if (!block && !(err = ext2_inode_block_alloc(desc, inode, &block)))
248 slot_set(inode, slot, block);
249
250 for (; !err && depth; --depth) {
251 size_t span = tree_span(desc, depth);
252 uint32_t next = 0;
253
254 err = ext2_indirect_block_get(desc, inode, block, rel / span, &next);
255 block = next;
256 rel %= span;
257 }
258
259 /* write the new block pointers and block count back to the inode */
260 if (inode->blocks != nblocks) {
261 int werr = ext2_inode_write(desc, inode_nr, inode);
262 err = err ? err : werr;
263 }
264
265 if (err)
266 return err;
267
268 return ext2_block_write(desc, block, buf);
269}
270
281int ext2_inode_alloc(struct ext2 *desc, ino_t *ino)
282{
283 vfs_log(LOG_DEBUG, "ext2_inode_alloc(desc=%p)\n", desc);
284
285 uint32_t *buf = kmalloc(desc->bs, &M_BUFFER, 0);
286 uint32_t idx = 0, group = 0;
287 struct bitmap bm = {0};
288 int err = -ENOSPC;
289
290 if (!buf)
291 return -ENOMEM;
292
293 for (unsigned i = 0; i < desc->ngroups; ++i) {
294 if (!desc->groups[i].free_inodes)
295 continue;
296
297 if ((err = ext2_block_read(desc, desc->groups[i].imap, buf)))
298 goto done;
299
300 bm.map = buf;
301 bm.max_idx = desc->superblock->ginodes;
302
303 /* look for a free inode */
304 for (idx = 0; idx < bm.max_idx && bitmap_check(&bm, idx); ++idx);
305
306 if (idx < bm.max_idx) {
307 group = i;
308 err = 0;
309 break;
310 }
311
312 err = -ENOSPC;
313 }
314
315 if (err)
316 goto done;
317
318 bitmap_set(&bm, idx);
319
320 if ((err = ext2_block_write(desc, desc->groups[group].imap, buf)))
321 goto done;
322
323 /* one inode fewer free, in the group and the filesystem */
324 desc->groups[group].free_inodes--;
325 desc->superblock->free_inodes--;
326
327 if (!(err = ext2_bgd_table_rewrite(desc)) && !(err = ext2_superblock_rewrite(desc)))
328 *ino = idx + group * desc->superblock->ginodes + 1;
329
330done:
331 kfree(buf);
332 return err;
333}
int ext2_block_write(struct ext2 *desc, uint32_t number, void *buf)
Writes a block to the disk.
Definition block.c:62
int ext2_io(struct ext2 *desc, int write, off_t off, size_t size, void *buf)
Reads or writes bytes of the filesystem's disk, all of them.
Definition block.c:19
int ext2_bgd_table_rewrite(struct ext2 *desc)
Writes the block group descriptor table back to the disk, after a change to a group's counts.
Definition block.c:34
int ext2_block_read(struct ext2 *desc, uint32_t number, void *buf)
Reads a block from the disk.
Definition block.c:49
int ext2_block_alloc(struct ext2 *desc, uint32_t *block)
Allocates a free block: its bit is set in its group's block bitmap, the free counts go down,...
Definition block.c:77
static void slot_set(struct ext2_inode *inode, int slot, uint32_t block)
Sets the block pointer in a slot of an inode.
Definition inode.c:112
static int ext2_indirect_block_get(struct ext2 *desc, struct ext2_inode *inode, uint32_t table, size_t idx, uint32_t *block)
Gets the block pointer at index idx of the indirect block table, allocating a block there if there's ...
Definition inode.c:200
static int ext2_inode_block_alloc(struct ext2 *desc, struct ext2_inode *inode, uint32_t *block)
Allocates a block for a file, and counts it in the inode's blocks, which counts 512-byte sectors.
Definition inode.c:187
static size_t tree_span(struct ext2 *desc, int depth)
Returns how many data blocks are under one pointer of an indirect block that is depth levels above th...
Definition inode.c:124
static off_t ext2_inode_off(struct ext2 *desc, ino_t ino)
Returns where an inode is on the disk, in bytes, or -EINVAL for an inode number that doesn't exist.
Definition inode.c:12
static int block_tree(struct ext2 *desc, size_t idx, int *slot, size_t *rel)
Finds where block idx of a file is in its tree: the slot of the inode it hangs from (0 to 11 for the ...
Definition inode.c:73
#define SLOT_SINGLY
Definition inode.c:63
static uint32_t slot_get(struct ext2_inode *inode, int slot)
Returns the block pointer in a slot of an inode.
Definition inode.c:101
int ext2_inode_alloc(struct ext2 *desc, ino_t *ino)
Allocates a free inode: its bit is set in its group's inode bitmap, and the free counts go down.
Definition inode.c:281
#define EXT2_DIRECT_POINTERS
Definition ext2.h:165
int ext2_inode_read(struct ext2 *desc, ino_t inode, struct ext2_inode *ref)
Reads an inode from the disk.
Definition inode.c:33
int ext2_inode_block_read(struct ext2 *desc, struct ext2_inode *inode, size_t idx, void *buf)
Reads a block of a file.
Definition inode.c:144
int ext2_inode_write(struct ext2 *desc, ino_t inode, struct ext2_inode *i)
Writes an inode to the disk.
Definition inode.c:51
int ext2_superblock_rewrite(struct ext2 *desc)
Writes the in-memory copy of the superblock back to the disk, after a change to its counts of free bl...
Definition super.c:14
int ext2_inode_block_write(struct ext2 *desc, struct ext2_inode *inode, uint32_t inode_nr, size_t idx, void *buf)
Writes a block of a file, allocating it and the indirect blocks above it if they don't exist yet.
Definition inode.c:235
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
static uint64_t * table(paddr_t paddr)
Returns a page table, through the direct map.
Definition pmap.c:72
#define LOG_DEBUG
Definition printk.h:19
unsigned int uint32_t
Definition stddef.h:22
A bitmap: its blocks, and its last bit's index.
Definition bitmap.h:17
size_t max_idx
Definition bitmap.h:19
bitmap_t * map
Definition bitmap.h:18
A block group descriptor, as it is on the disk.
Definition ext2.h:98
uint16_t free_inodes
number of unallocated inodes
Definition ext2.h:108
uint32_t imap
inodes bitmap
Definition ext2.h:102
uint32_t inodes
inode table
Definition ext2.h:104
An inode, as it is on the disk.
Definition ext2.h:114
uint32_t blocks
Definition ext2.h:124
uint32_t doubly_indirect_pointer
Definition ext2.h:130
uint32_t direct_pointer[12]
Definition ext2.h:128
uint32_t triply_indirect_pointer
Definition ext2.h:131
uint32_t singly_indirect_pointer
Definition ext2.h:129
uint32_t ginodes
number of inodes per block group
Definition ext2.h:56
uint32_t free_inodes
number of unallocated inodes
Definition ext2.h:44
uint32_t ninodes
number of inodes
Definition ext2.h:36
A mounted ext2 filesystem.
Definition ext2.h:168
struct ext2_superblock * superblock
Definition ext2.h:170
struct ext2_group * groups
Definition ext2.h:171
size_t ngroups
number of block group descriptors
Definition ext2.h:174
size_t bs
the block size
Definition ext2.h:177
size_t inode_size
an inode's size on the disk (revision 0's, or the superblock's)
Definition ext2.h:180
uintptr_t ino_t
Definition types.h:23
long int off_t
Definition types.h:10