AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
inode.c
Go to the documentation of this file.
1
7
8#include <ds/bitmap.h>
9#include <minix.h>
10
13static inline off_t minix_inode_off(struct minix *desc, ino_t ino)
14{
15 /* inodes are numbered from 1 to ninodes */
16 if (!ino || ino > desc->superblock->ninodes)
17 return -EINVAL;
18
19 return desc->inode_table + (ino - 1) * desc->inode_size;
20}
21
31int minix_inode_read(struct minix *desc, ino_t ino, struct minix_inode *ref)
32{
33 off_t off;
34
35 if ((off = minix_inode_off(desc, ino)) < 0)
36 return off;
37
38 if (ref) {
39 size_t size = sizeof(struct minix_inode);
40 ssize_t r;
41
42 if ((r = vfs_read(desc->supernode, off, size, ref)) != (ssize_t) size) {
43 if (r < 0)
44 return r;
45
46 /* a short read */
47 return -EINVAL;
48 }
49 }
50
51 return 0;
52}
53
63int minix_inode_write(struct minix *desc, ino_t ino, struct minix_inode *ref)
64{
65 off_t off;
66
67 if ((off = minix_inode_off(desc, ino)) < 0)
68 return off;
69
70 if (ref) {
71 size_t size = sizeof(struct minix_inode);
72 ssize_t r;
73
74 if ((r = vfs_write(desc->supernode, off, size, ref)) != (ssize_t) size) {
75 if (r < 0)
76 return r;
77
78 /* a short write */
79 return -EINVAL;
80 }
81 }
82
83 return 0;
84}
85
94static int zone_tree(struct minix *desc, size_t idx, int *slot, size_t *rel)
95{
96 size_t p = desc->bs / sizeof(uint16_t); /* pointers per zone */
97
98 if (idx < MINIX_DIRECT_ZONES) {
99 *slot = idx;
100 *rel = 0;
101 return 0;
102 }
103
104 idx -= MINIX_DIRECT_ZONES;
105
106 if (idx < p) {
107 *slot = MINIX_DIRECT_ZONES;
108 *rel = idx;
109 return 1;
110 }
111
112 idx -= p;
113
114 if (idx < p * p) {
115 *slot = MINIX_DIRECT_ZONES + 1;
116 *rel = idx;
117 return 2;
118 }
119
120 return -EFBIG;
121}
122
125static size_t zone_span(struct minix *desc, int depth)
126{
127 return depth == 2 ? desc->bs / sizeof(uint16_t) : 1;
128}
129
141ssize_t minix_inode_block_read(struct minix *desc, struct minix_inode *m_inode, size_t idx, void *buf)
142{
143 size_t bs = desc->bs;
144 size_t nr_blocks = (m_inode->size + bs - 1) / bs;
145 int slot, err;
146 size_t rel;
147
148 if (idx >= nr_blocks)
149 return -EINVAL;
150
151 int depth = zone_tree(desc, idx, &slot, &rel);
152
153 if (depth < 0)
154 return depth;
155
156 blk_t zone = m_inode->zones[slot];
157
158 for (; depth && zone; --depth) {
159 size_t span = zone_span(desc, depth);
161
162 if ((err = minix_bcache_get(desc, zone, (void **) &table)))
163 return err;
164
165 zone = table[rel / span];
166 rel %= span;
167 }
168
169 if (!zone) { /* a hole in a sparse file */
170 memset(buf, 0, bs);
171 return 0;
172 }
173
174 ssize_t r = minix_block_read(desc, zone, buf);
175 return r == (ssize_t) bs ? 0 : r < 0 ? r : -EIO;
176}
177
180static int table_alloc(struct minix *desc, blk_t *zone)
181{
182 if (!(*zone = minix_block_alloc(desc)))
183 return -ENOSPC;
184
185 uint16_t *zero = kmalloc(desc->bs, &M_BUFFER, M_ZERO);
186
187 if (!zero)
188 return -ENOMEM;
189
190 ssize_t r = minix_block_write(desc, *zone, zero);
191 kfree(zero);
192
193 bcache_remove(desc->bcache, *zone);
194 return r == (ssize_t) desc->bs ? 0 : r < 0 ? r : -EIO;
195}
196
208ssize_t minix_inode_block_write(struct minix *desc, struct minix_inode *inode, ino_t ino, size_t idx, void *buf)
209{
210 int slot, err = 0, changed = 0;
211 size_t rel;
212 int depth = zone_tree(desc, idx, &slot, &rel);
213
214 if (depth < 0)
215 return depth;
216
217 blk_t zone = inode->zones[slot];
218
219 if (!zone) {
220 if (depth)
221 err = table_alloc(desc, &zone);
222 else if (!(zone = minix_block_alloc(desc)))
223 err = -ENOSPC;
224
225 if (!err) {
226 inode->zones[slot] = zone;
227 changed = 1;
228 }
229 }
230
231 /* go down the tables, through the cache, so that readers see the new
232 * pointers */
233 for (; !err && depth; --depth) {
234 size_t span = zone_span(desc, depth);
236 blk_t next;
237
238 if ((err = minix_bcache_get(desc, zone, (void **) &table)))
239 break;
240
241 if (!(next = table[rel / span])) {
242 if (depth > 1)
243 err = table_alloc(desc, &next);
244 else if (!(next = minix_block_alloc(desc)))
245 err = -ENOSPC;
246
247 if (err)
248 break;
249
250 /* allocating the new table may have dropped this table's copy
251 * from the cache: get it again */
252 if ((err = minix_bcache_get(desc, zone, (void **) &table)))
253 break;
254
255 table[rel / span] = next;
256 minix_block_write(desc, zone, table);
257 }
258
259 zone = next;
260 rel %= span;
261 }
262
263 if (changed) {
264 int werr = minix_inode_write(desc, ino, inode);
265 err = err ? err : werr;
266 }
267
268 if (err)
269 return err;
270
271 ssize_t r = minix_block_write(desc, zone, buf);
272 return r == (ssize_t) desc->bs ? 0 : r < 0 ? r : -EIO;
273}
274
281static blk_t free_tree(struct minix *desc, blk_t zone, int depth, size_t from)
282{
283 if (!zone)
284 return 0;
285
286 if (depth) {
287 size_t span = zone_span(desc, depth), p = desc->bs / sizeof(uint16_t);
289
290 if (minix_bcache_get(desc, zone, (void **) &table))
291 return zone;
292
293 for (size_t i = from / span; i < p; ++i)
294 table[i] = free_tree(desc, table[i], depth - 1, i == from / span ? from % span : 0);
295
296 /* the first part of the tree stays */
297 if (from) {
298 minix_block_write(desc, zone, table);
299 return zone;
300 }
301 }
302
303 minix_block_free(desc, zone);
304 return 0;
305}
306
315void minix_zones_free(struct minix *desc, struct minix_inode *inode, size_t from)
316{
317 size_t p = desc->bs / sizeof(uint16_t), base = MINIX_DIRECT_ZONES;
318
319 /* a device node keeps its number in its first zone: it has no zones */
320 if (S_ISCHR(inode->mode) || S_ISBLK(inode->mode))
321 return;
322
323 for (size_t i = from; i < MINIX_DIRECT_ZONES; ++i)
324 inode->zones[i] = free_tree(desc, inode->zones[i], 0, 0);
325
326 inode->zones[MINIX_DIRECT_ZONES] =
327 free_tree(desc, inode->zones[MINIX_DIRECT_ZONES], 1, from > base ? from - base : 0);
328 base += p;
329 inode->zones[MINIX_DIRECT_ZONES + 1] =
330 free_tree(desc, inode->zones[MINIX_DIRECT_ZONES + 1], 2, from > base ? from - base : 0);
331}
332
341{
342 /* look for a free inode: bit i of the bitmap is inode i, from 1 to
343 * ninodes (bit 0 is reserved) */
344 ino_t ino = 1;
345 for (; ino <= desc->imap.max_idx && bitmap_check(&desc->imap, ino); ++ino);
346
347 /* out of inodes */
348 if (ino > desc->imap.max_idx)
349 return 0;
350
351 bitmap_set(&desc->imap, ino);
352
353 /* write the bitmap back now (it could be deferred) */
354 vfs_write(desc->supernode, desc->imap_off, desc->superblock->imap_blocks * desc->bs, desc->imap.map);
355
356 return ino;
357}
358
366void minix_inode_free(struct minix *desc, ino_t ino)
367{
368 /* not an inode: nothing to free */
369 if (!ino || ino > desc->imap.max_idx)
370 return;
371
372 bitmap_clear(&desc->imap, ino);
373
374 /* write the bitmap back now (it could be deferred) */
375 vfs_write(desc->supernode, desc->imap_off, desc->superblock->imap_blocks * desc->bs, desc->imap.map);
376}
int bcache_remove(struct bcache *bcache, uint64_t off)
Takes a block out of a cache.
Definition bcache.c:73
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
#define M_ZERO
Definition kvmem.h:26
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
ssize_t minix_block_write(struct minix *desc, blk_t blk, void *buf)
Writes a block to the disk.
Definition block.c:83
void minix_block_free(struct minix *desc, blk_t blk)
Frees a zone: its bit is cleared in the zone bitmap, which is written back at once,...
Definition block.c:42
ssize_t minix_block_read(struct minix *desc, blk_t blk, void *buf)
Reads a block from the disk.
Definition block.c:70
int minix_bcache_get(struct minix *desc, blk_t blk, void **data)
Gets a block from the block cache, reading it from the disk into the cache if it isn't there.
Definition block.c:97
blk_t minix_block_alloc(struct minix *desc)
Allocates a free zone: its bit is set in the zone bitmap, which is written back to the disk at once.
Definition block.c:16
static off_t minix_inode_off(struct minix *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:13
static blk_t free_tree(struct minix *desc, blk_t zone, int depth, size_t from)
Frees the zones of the tree at zone (a data zone at depth 0, or an indirect zone depth levels above t...
Definition inode.c:281
ssize_t minix_inode_block_write(struct minix *desc, struct minix_inode *inode, ino_t ino, size_t idx, void *buf)
Writes a zone of a file, allocating it and the indirect zones above it if they don't exist yet.
Definition inode.c:208
ssize_t minix_inode_block_read(struct minix *desc, struct minix_inode *m_inode, size_t idx, void *buf)
Reads a zone of a file.
Definition inode.c:141
int minix_inode_read(struct minix *desc, ino_t ino, struct minix_inode *ref)
Reads an inode from the disk.
Definition inode.c:31
int minix_inode_write(struct minix *desc, ino_t ino, struct minix_inode *ref)
Writes an inode to the disk.
Definition inode.c:63
void minix_zones_free(struct minix *desc, struct minix_inode *inode, size_t from)
Frees a file's zones, from a zone on, when the file is truncated or removed.
Definition inode.c:315
void minix_inode_free(struct minix *desc, ino_t ino)
Frees an inode: its bit is cleared in the inode bitmap, which is written back at once.
Definition inode.c:366
static int zone_tree(struct minix *desc, size_t idx, int *slot, size_t *rel)
Finds where zone idx of a file is in its tree: the slot of zones[] it hangs from (0 to 6 for the dire...
Definition inode.c:94
static size_t zone_span(struct minix *desc, int depth)
Returns how many data zones are under one pointer of an indirect zone that is depth levels above them...
Definition inode.c:125
ino_t minix_inode_alloc(struct minix *desc)
Allocates a free inode: its bit is set in the inode bitmap, which is written back to the disk at once...
Definition inode.c:340
uint32_t blk_t
Definition minix.h:113
#define MINIX_DIRECT_ZONES
Definition minix.h:29
static uint64_t * table(paddr_t paddr)
Returns a page table, through the direct map.
Definition pmap.c:72
static paddr_t table_alloc(void)
Allocates an empty page table.
Definition pmap.c:79
ssize_t vfs_read(struct vnode *vnode, off_t off, size_t size, void *buf)
Reads from a vnode into a kernel buffer.
Definition read.c:52
unsigned short int uint16_t
Definition stddef.h:21
size_t max_idx
Definition bitmap.h:19
bitmap_t * map
Definition bitmap.h:18
A minix v1 inode, as it is on the disk.
Definition minix.h:64
uint32_t size
Definition minix.h:67
uint16_t mode
Definition minix.h:65
uint16_t zones[9]
Definition minix.h:71
uint16_t imap_blocks
Definition minix.h:35
uint16_t ninodes
Definition minix.h:33
A mounted minix filesystem.
Definition minix.h:82
size_t bs
Definition minix.h:101
struct minix_superblock * superblock
Definition minix.h:84
struct vnode * supernode
Definition minix.h:83
uint32_t inode_table
Definition minix.h:99
size_t inode_size
Definition minix.h:86
struct bcache * bcache
Definition minix.h:104
struct bitmap imap
Definition minix.h:93
uint32_t imap_off
Definition minix.h:90
uintptr_t ino_t
Definition types.h:23
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10
ssize_t vfs_write(struct vnode *vnode, off_t off, size_t size, void *buf)
Writes to a vnode from a kernel buffer.
Definition write.c:60