AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
ext2.c
Go to the documentation of this file.
1
6#include <core/panic.h>
7#include <core/module.h>
8#include <fs/vfs.h>
9#include <fs/posix.h>
10#include <fs/vcache.h>
11#include <aquila/errno.h>
12#include <ds/bitmap.h>
13
14#include <ext2.h>
15
16MALLOC_DEFINE(M_EXT2, "ext2", "ext2 filesystem structure");
17MALLOC_DEFINE(M_EXT2_SB, "ext2-sb", "ext2 filesystem superblock structure");
18MALLOC_DEFINE(M_EXT2_GROUP, "ext2-group", "ext2 block group descriptor");
19
29int ext2_inode_build(struct ext2 *desc, ino_t ino, struct vnode **ref_inode)
30{
31 int err = 0;
32 struct vnode *inode = NULL;
33
34 /* is it in use already? */
35 if ((inode = vcache_find(desc->vcache, ino)))
36 goto found;
37
38 vfs_log(LOG_DEBUG, "ext2_inode_build(desc=%p, ino=%d, ref_inode=%p)\n", desc, ino, ref_inode);
39
40 struct ext2_inode einode;
41
42 /* nothing is cached of an inode that couldn't be read */
43 if ((err = ext2_inode_read(desc, ino, &einode)))
44 return err;
45
46 inode = kmalloc(sizeof(struct vnode), &M_VNODE, M_ZERO);
47
48 if (!inode)
49 return -ENOMEM;
50
51 inode->ino = ino;
52 inode->size = einode.size;
53 inode->mode = einode.mode;
54 inode->uid = einode.uid;
55 inode->gid = einode.gid;
56 inode->nlink = einode.nlink;
57
58 /* a device node's number is in its first block pointer, as Linux
59 * keeps it (major << 8 | minor, which is AquilaOS's dev_t); if that's
60 * 0, it's in the second, in Linux's newer encoding of larger numbers */
61 if (S_ISCHR(einode.mode) || S_ISBLK(einode.mode)) {
62 uint32_t old = einode.direct_pointer[0], new = einode.direct_pointer[1];
63
64 inode->rdev = old ? (dev_t) old :
65 DEV((new & 0xFFF00) >> 8, (new & 0xFF) | ((new >> 12) & 0xFFF00));
66 }
67
68 inode->atime.tv_sec = einode.atime;
69 inode->atime.tv_nsec = 0;
70 inode->mtime.tv_sec = einode.mtime;
71 inode->mtime.tv_nsec = 0;
72 inode->ctime.tv_sec = einode.ctime;
73 inode->ctime.tv_nsec = 0;
74
75 inode->fs = &ext2fs;
76 inode->p = desc;
77
78 vcache_insert(desc->vcache, inode);
79
80found:
81 if (ref_inode)
82 *ref_inode = inode;
83
84 return 0;
85}
86
93int ext2_inode_sync(struct vnode *inode)
94{
95 vfs_log(LOG_DEBUG, "ext2_inode_sync(inode=%p)\n", inode);
96
97 int err = 0;
98
99 struct ext2 *desc = (struct ext2 *) inode->p;
100 struct ext2_inode ext2_inode;
101
102 /* read the on-disk inode first so that fields we don't track in the
103 * vnode (block pointers, flags, ...) are preserved */
104 if ((err = ext2_inode_read(desc, inode->ino, &ext2_inode)))
105 return err;
106
107 ext2_inode.size = inode->size;
108 ext2_inode.mode = inode->mode;
109 ext2_inode.uid = inode->uid;
110 ext2_inode.gid = inode->gid;
111 ext2_inode.nlink = inode->nlink;
112
113 ext2_inode.atime = inode->atime.tv_sec;
114 ext2_inode.mtime = inode->mtime.tv_sec;
115 ext2_inode.ctime = inode->ctime.tv_sec;
116
117 if ((err = ext2_inode_write(desc, inode->ino, &ext2_inode)) < 0)
118 return err;
119
120 return 0;
121}
122
123/* The filesystem's operations */
124
131{
132 return vfs_install(&ext2fs);
133}
134
144int ext2_load(struct vnode *dev, struct vnode **super)
145{
146 int err = 0;
147 ssize_t r;
148
149 struct ext2_superblock *sb = NULL;
150 struct ext2 *desc = NULL;
151
152 sb = kmalloc(sizeof(struct ext2_superblock), &M_EXT2_SB, M_ZERO);
153 if (!sb) goto e_nomem;
154
155 /* the superblock: all of it, a short read is an I/O error */
156 if ((r = vfs_read(dev, 1024, sizeof(struct ext2_superblock), sb)) != (ssize_t) sizeof(struct ext2_superblock)) {
157 err = r < 0 ? (int) r : -EIO;
158 goto error;
159 }
160
161 /* is it ext2, with blocks of 1, 2 or 4 KiB (the code keeps blocks in
162 * buffers, some of them on the stack) and groups of blocks? */
163 if (sb->ext2_signature != EXT2_SIGNATURE || sb->block_size > 2 ||
164 !sb->gblocks) {
165 err = -EINVAL;
166 goto error;
167 }
168
169 /* the mounted filesystem's structure */
170 desc = kmalloc(sizeof(struct ext2), &M_EXT2, M_ZERO);
171 if (!desc) goto e_nomem;
172
173 desc->supernode = dev;
174 desc->superblock = sb;
175 desc->bs = 1024UL << sb->block_size;
177
178 /* revision 1 has an inode size, and features AquilaOS must know */
179 if (sb->major_version >= 1) {
180 desc->inode_size = sb->inode_size;
181
182 if (desc->inode_size < EXT2_GOOD_OLD_INODE_SIZE || desc->inode_size > desc->bs ||
183 (desc->inode_size & (desc->inode_size - 1))) {
184 err = -EINVAL;
185 goto error;
186 }
187
189
192
193 if (incompat || ro) {
194 printk("ext2: features it can't use: incompat %x, ro_compat %x\n", incompat, ro);
195 err = -EINVAL;
196 goto error;
197 }
198 }
199
200 /* the block group descriptor table, after the superblock */
201 uint32_t groups = (desc->bs == 1024)? 2048 : desc->bs;
202 size_t ngroups = (sb->nblocks + sb->gblocks - 1)/ sb->gblocks;
203 size_t groups_sz = ngroups * sizeof(struct ext2_group);
204
205 desc->ngroups = ngroups;
206 desc->groups = kmalloc(groups_sz, &M_EXT2_GROUP, 0);
207 if (!desc->groups) goto e_nomem;
208
209 if ((r = vfs_read(desc->supernode, groups, groups_sz, desc->groups)) != (ssize_t) groups_sz) {
210 err = r < 0 ? (int) r : -EIO;
211 goto error;
212 }
213
214 desc->vcache = kmalloc(sizeof(struct vcache), &M_VCACHE, M_ZERO);
215 if (!desc->vcache) goto e_nomem;
216
217 vcache_init(desc->vcache);
218
219 if (!desc->vcache->hashmap) goto e_nomem;
220
221 /* the root directory (if its inode can't be read, there's no
222 * filesystem) */
223 if (super && (err = ext2_inode_build(desc, 2, super)))
224 goto error;
225
226 return 0;
227
228e_nomem:
229 err = -ENOMEM;
230error:
231 /* nothing of it is in use yet, since the root comes last */
232 if (desc) {
233 if (desc->vcache && desc->vcache->hashmap)
234 hashmap_free(desc->vcache->hashmap);
235
236 kfree(desc->vcache);
237 kfree(desc->groups);
238 kfree(desc);
239 }
240
241 kfree(sb);
242 return err;
243}
244
253int ext2_mount(struct vnode *dir, int flags, void *_args)
254{
255 struct {
256 char *dev;
257 char *opt;
258 } *args = _args;
259
260 struct vnode *dev = NULL;
261 int err;
262
263 struct uio uio = {0}; /* the device is looked up as root */
264
265 if (!args || !args->dev)
266 return -EINVAL;
267
268 if ((err = vfs_lookup(args->dev, &uio, &dev)))
269 goto error;
270
271 struct vnode *fs;
272
273 if ((err = ext2fs.load(dev, &fs)))
274 goto error;
275
276 return vfs_bind(dir, fs);
277
278error:
279 return err;
280}
281
282struct fs ext2fs = {
283 .name = "ext2",
284 .init = ext2_init,
285 .load = ext2_load,
286 .mount = ext2_mount,
287
288 .vops = {
289 .read = ext2_read,
290 .write = ext2_write,
291 .readdir = ext2_readdir,
292 .finddir = ext2_finddir,
293
294 .trunc = ext2_trunc,
295
296 .vmknod = ext2_vmknod,
297 .vunlink = ext2_vunlink,
298 .vlink = ext2_vlink,
299 .vrename = ext2_vrename,
300 .vget = ext2_vget,
301 .setattr = ext2_setattr,
302 .close = ext2_close,
303 },
304
305 .fops = {
306 .open = posix_file_open,
307 .read = posix_file_read,
308 .write = posix_file_write,
309 .readdir = posix_file_readdir,
310 .lseek = posix_file_lseek,
311 .trunc = posix_file_trunc,
312
313 .eof = posix_file_eof,
314 }
315};
316
#define DEV(major, minor)
Definition dev.h:76
struct fs ext2fs
Definition ext2.c:282
int ext2_inode_build(struct ext2 *desc, ino_t ino, struct vnode **ref_inode)
Gets the vnode of an inode: the cached one if it's in use, or a new one made from the inode on the di...
Definition ext2.c:29
int ext2_inode_sync(struct vnode *inode)
Writes a vnode's attributes back to its inode on the disk.
Definition ext2.c:93
int ext2_init()
Installs the ext2 filesystem at boot.
Definition ext2.c:130
int ext2_load(struct vnode *dev, struct vnode **super)
Loads an ext2 filesystem from a device: its superblock, its block group descriptors,...
Definition ext2.c:144
int ext2_mount(struct vnode *dir, int flags, void *_args)
Mounts the ext2 filesystem of a device on a directory.
Definition ext2.c:253
ssize_t ext2_write(struct vnode *node, off_t offset, struct iobuf *io)
Writes to a file, which grows if the write goes past its end.
Definition vops.c:83
#define EXT2_SIGNATURE
Definition ext2.h:16
ssize_t ext2_read(struct vnode *node, off_t offset, struct iobuf *io)
Reads from a file.
Definition vops.c:23
int ext2_vget(struct vnode *super, ino_t ino, struct vnode **ref)
Gets the vnode of an inode, by its number.
Definition vops.c:443
#define EXT2_GOOD_OLD_INODE_SIZE
Definition ext2.h:31
#define EXT2_INCOMPAT_FILETYPE
Definition ext2.h:21
int ext2_close(struct vnode *vnode)
Releases a vnode when its last reference goes.
Definition remove.c:158
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_vlink(struct vnode *dir, const char *fn, struct vnode *vnode, struct uio *uio)
Adds an entry for an existing file (a hard link) to a directory.
Definition remove.c:298
int ext2_trunc(struct vnode *inode, off_t len)
Changes a file's length.
Definition vops.c:252
#define EXT2_RO_COMPAT_SUPPORTED
Definition ext2.h:27
int ext2_vrename(struct vnode *odir, const char *ofn, struct vnode *ndir, const char *nfn, struct uio *uio)
Renames an entry, possibly to another directory, replacing an entry at the new name (the VFS checked ...
Definition remove.c:337
int ext2_vmknod(struct vnode *dir, const char *fn, mode_t mode, dev_t dev, struct uio *uio, struct vnode **ref)
Makes a node in a directory: a new inode, and an entry for it.
Definition vops.c:312
#define EXT2_INCOMPAT_SUPPORTED
Definition ext2.h:26
int ext2_inode_write(struct ext2 *desc, ino_t inode, struct ext2_inode *i)
Writes an inode to the disk.
Definition inode.c:51
ssize_t ext2_readdir(struct vnode *dir, off_t offset, struct dirent *dirent)
Reads a directory's entry at an offset; unused entries don't count.
Definition vops.c:174
int ext2_setattr(struct vnode *vnode)
Stores a vnode's attributes (mode, owner, times) in its inode.
Definition vops.c:456
int ext2_vunlink(struct vnode *dir, const char *fn, struct uio *uio)
Removes an entry from a directory, and drops a link to its file.
Definition remove.c:249
int ext2_finddir(struct vnode *dir, const char *fn, struct dirent *dirent)
Finds the entry of a directory that has a name.
Definition vops.c:414
int posix_file_eof(struct file *file)
Says whether a file's offset is at or past its end, so that a read returns nothing.
Definition helpers.c:17
#define MALLOC_DEFINE(type, _name, _desc)
Definition kvmem.h:30
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
int vfs_lookup(const char *path, struct uio *uio, struct vnode **ref)
Finds the vnode a path names.
Definition lookup.c:349
off_t posix_file_lseek(struct file *file, off_t offset, int whence)
Moves an open file's offset: to offset (SEEK_SET), by offset from where it is (SEEK_CUR),...
Definition lseek.c:22
#define MODULE_INIT(name, i, f)
Definition module.h:10
int posix_file_open(struct file *file)
Finishes opening a file: with O_TRUNC, a regular file is truncated to 0 bytes.
Definition open.c:17
ssize_t posix_file_read(struct file *file, struct iobuf *io)
Reads from an open file at its offset, and moves the offset past what was read.
Definition read.c:29
ssize_t posix_file_readdir(struct file *file, struct dirent *dirent)
Reads the directory entry at an open directory's offset, and moves the offset past it.
Definition readdir.c:22
int posix_file_trunc(struct file *file, off_t len)
Truncates (or extends) an open file to a new length.
Definition trunc.c:16
ssize_t posix_file_write(struct file *file, struct iobuf *io)
Writes to an open file at its offset, and moves the offset past what was written.
Definition write.c:25
int printk(const char *fmt,...)
Writes a kernel message, to the message buffer and the consoles.
Definition printk.c:249
#define LOG_DEBUG
Definition printk.h:19
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
#define NULL
Definition stddef.h:27
unsigned int uint32_t
Definition stddef.h:22
A device driver: its operations, any of which may be NULL.
Definition dev.h:28
A block group descriptor, as it is on the disk.
Definition ext2.h:98
An inode, as it is on the disk.
Definition ext2.h:114
uint32_t ctime
Definition ext2.h:119
uint16_t nlink
Definition ext2.h:123
uint16_t gid
Definition ext2.h:122
uint32_t size
Definition ext2.h:117
uint32_t mtime
Definition ext2.h:120
uint32_t direct_pointer[12]
Definition ext2.h:128
uint16_t mode
Definition ext2.h:115
uint32_t atime
Definition ext2.h:118
uint16_t uid
Definition ext2.h:116
The superblock, as it is on the disk, 1024 bytes into it.
Definition ext2.h:34
uint16_t ext2_signature
Definition ext2.h:64
uint32_t major_version
Definition ext2.h:71
uint16_t inode_size
Definition ext2.h:77
uint32_t nblocks
number of blocks
Definition ext2.h:38
uint32_t feature_ro_compat
Definition ext2.h:82
uint32_t feature_incompat
Definition ext2.h:81
uint32_t gblocks
number of blocks per block group
Definition ext2.h:52
uint32_t block_size
log(block size)
Definition ext2.h:48
A mounted ext2 filesystem.
Definition ext2.h:168
struct ext2_superblock * superblock
Definition ext2.h:170
struct ext2_group * groups
Definition ext2.h:171
struct vcache * vcache
its vnodes in use, by inode number
Definition ext2.h:187
size_t ngroups
number of block group descriptors
Definition ext2.h:174
struct vnode * supernode
Definition ext2.h:169
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
int filetype
directory entries have their file's type (EXT2_INCOMPAT_FILETYPE); without it, the byte is 0
Definition ext2.h:184
A filesystem type.
Definition vfs.h:98
int(*) load(struct vnode *dev, struct vnode **super)
Definition vfs.h:101
uint32_t tv_nsec
Definition types.h:32
time_t tv_sec
Definition types.h:31
Who does a filesystem operation: where its paths start, and its credentials and umask.
Definition vfs.h:60
A filesystem's vnode cache (fs/vcache.c): its vnodes in memory, by their inode number,...
Definition vcache.h:10
struct hashmap * hashmap
Definition vcache.h:11
A file in memory (a vnode): what its inode says, and the kernel's own state.
Definition vfs.h:113
ino_t ino
Definition vfs.h:114
_time_t atime
Definition vfs.h:123
_time_t ctime
Definition vfs.h:125
nlink_t nlink
Definition vfs.h:121
struct fs * fs
Definition vfs.h:127
_time_t mtime
Definition vfs.h:124
gid_t gid
Definition vfs.h:120
size_t size
Definition vfs.h:115
void * p
the filesystem's own data
Definition vfs.h:130
mode_t mode
Definition vfs.h:118
uid_t uid
Definition vfs.h:119
dev_t rdev
Definition vfs.h:117
uint16_t dev_t
Definition types.h:18
uintptr_t ino_t
Definition types.h:23
long int ssize_t
Definition types.h:12
void vcache_init(struct vcache *vcache)
Sets up an empty vnode cache.
Definition vcache.c:25
struct vnode * vcache_find(struct vcache *vcache, ino_t ino)
Finds the cached vnode of an inode.
Definition vcache.c:80
int vcache_insert(struct vcache *vcache, struct vnode *vnode)
Adds a vnode to a cache.
Definition vcache.c:37
int vfs_bind(struct vnode *dir, struct vnode *root)
Mounts a filesystem on a directory: a lookup that reaches dir goes on in root instead.
Definition vfs.c:53
int vfs_install(struct fs *fs)
Installs a filesystem, so that it can be mounted by name.
Definition vfs.c:85