PatchworkOS
Loading...
Searching...
No Matches
ramfs.c
Go to the documentation of this file.
1#include <kernel/fs/ramfs.h>
2
3#include <kernel/fs/dentry.h>
4#include <kernel/fs/mount.h>
6#include <kernel/fs/path.h>
7#include <kernel/fs/sysfs.h>
8#include <kernel/fs/vfs.h>
9#include <kernel/log/log.h>
10#include <kernel/log/panic.h>
11#include <kernel/sync/lock.h>
12#include <kernel/sync/mutex.h>
13#include <kernel/utils/ref.h>
14
15#include <boot/boot_info.h>
16
17#include <assert.h>
18#include <errno.h>
19#include <stdlib.h>
20#include <string.h>
21#include <sys/list.h>
22#include <sys/math.h>
23
24static mount_t* mount = NULL;
25
26static _Atomic(inode_number_t) newNumber = ATOMIC_VAR_INIT(1);
27
28static inode_t* ramfs_inode_new(superblock_t* superblock, inode_type_t type, void* buffer, uint64_t size);
29
30static uint64_t ramfs_dentry_init(dentry_t* dentry)
31{
32 ramfs_superblock_data_t* superData = dentry->superblock->private;
33
34 ramfs_dentry_data_t* dentryData = malloc(sizeof(ramfs_dentry_data_t));
35 if (dentryData == NULL)
36 {
37 return ERR;
38 }
39 list_entry_init(&dentryData->entry);
40 dentryData->dentry = REF(dentry);
41 dentry->private = dentryData;
42
43 lock_acquire(&superData->lock);
44 list_push(&superData->dentrys, &dentryData->entry);
45 lock_release(&superData->lock);
46 return 0;
47}
48
49static void ramfs_dentry_deinit(dentry_t* dentry)
50{
51 ramfs_superblock_data_t* superData = dentry->superblock->private;
52
53 ramfs_dentry_data_t* dentryData = dentry->private;
54 assert(dentryData != NULL);
55
56 DEREF(dentryData->dentry);
57 dentryData->dentry = NULL;
58
59 lock_acquire(&superData->lock);
60 list_remove(&superData->dentrys, &dentryData->entry);
61 lock_release(&superData->lock);
62
63 free(dentryData);
64}
65
67{
69
70 if (file->inode->private == NULL)
71 {
72 return 0;
73 }
74
75 return BUFFER_READ(buffer, count, offset, file->inode->private, file->inode->size);
76}
77
79{
81
82 if (*offset + count > file->inode->size)
83 {
84 void* newData = realloc(file->inode->private, *offset + count);
85 if (newData == NULL)
86 {
87 return ERR;
88 }
89 memset(newData + file->inode->size, 0, *offset + count - file->inode->size);
90 file->inode->private = newData;
91 file->inode->size = *offset + count;
92 }
93
94 memcpy(file->inode->private + *offset, buffer, count);
95 *offset += count;
96 return count;
97}
98
100 .read = ramfs_read,
101 .write = ramfs_write,
102 .seek = file_generic_seek,
103};
104
106{
107 (void)dir; // Unused
108 (void)target; // Unused
109
110 // All ramfs dentrys should always be in the cache, if lookup is called then the file/dir does not exist.
111 return 0;
112}
113
115{
116 inode_t* newInode = ramfs_inode_new(dir->superblock, flags & PATH_DIRECTORY ? INODE_DIR : INODE_FILE, NULL, 0);
117 if (newInode == NULL)
118 {
119 return ERR;
120 }
121 DEREF_DEFER(newInode);
122
123 if (ramfs_dentry_init(target) == ERR)
124 {
125 return ERR;
126 }
127
128 if (dentry_make_positive(target, newInode) == ERR)
129 {
130 return ERR;
131 }
132
133 return 0;
134}
135
136static void ramfs_truncate(inode_t* inode)
137{
138 if (inode->private != NULL)
139 {
140 free(inode->private);
141 inode->private = NULL;
142 }
143 inode->size = 0;
144}
145
146static uint64_t ramfs_link(dentry_t* old, inode_t* dir, dentry_t* target)
147{
148 (void)dir; // Unused
149
150 if (ramfs_dentry_init(target) == ERR)
151 {
152 return ERR;
153 }
154
155 old->inode->linkCount++;
156 dentry_make_positive(target, old->inode);
157
158 return 0;
159}
160
162{
163 (void)parent; // Unused
164
165 target->inode->linkCount--;
166 ramfs_dentry_deinit(target);
167 return 0;
168}
169
171{
172 (void)parent; // Unused
173
174 ramfs_dentry_deinit(target);
175 return 0;
176}
177
178static uint64_t ramfs_remove(inode_t* parent, dentry_t* target, path_flags_t flags)
179{
180 if (target->inode->type == INODE_FILE)
181 {
182 ramfs_remove_file(parent, target);
183 }
184 else if (target->inode->type == INODE_DIR)
185 {
186 if (flags & PATH_RECURSIVE)
187 {
188 MUTEX_SCOPE(&target->inode->mutex);
189
190 dentry_t* temp = NULL;
191 dentry_t* child = NULL;
192 LIST_FOR_EACH_SAFE(child, temp, &target->children, siblingEntry)
193 {
194 REF(child);
195 ramfs_remove(target->inode, child, flags);
196 DEREF(child);
197 }
198 }
199 else
200 {
201 if (!list_is_empty(&target->children))
202 {
204 return ERR;
205 }
206 }
207 ramfs_remove_directory(parent, target);
208 }
209 return 0;
210}
211
212static void ramfs_inode_cleanup(inode_t* inode)
213{
214 if (inode->private != NULL)
215 {
216 free(inode->private);
217 }
218}
219
222 .create = ramfs_create,
223 .truncate = ramfs_truncate,
224 .link = ramfs_link,
225 .remove = ramfs_remove,
226 .cleanup = ramfs_inode_cleanup,
227};
228
232
234{
235 (void)superblock; // Unused
236
237 panic(NULL, "ramfs unmounted\n");
238}
239
243
244static dentry_t* ramfs_load_file(superblock_t* superblock, dentry_t* parent, const char* name, const boot_file_t* in)
245{
246 dentry_t* dentry = dentry_new(superblock, parent, name);
247 if (dentry == NULL)
248 {
249 panic(NULL, "Failed to create ramfs file dentry");
250 }
251 DEREF_DEFER(dentry);
252
253 if (ramfs_dentry_init(dentry) == ERR)
254 {
255 panic(NULL, "Failed to initialize ramfs dentry");
256 }
257
258 inode_t* inode = ramfs_inode_new(superblock, INODE_FILE, in->data, in->size);
259 if (inode == NULL)
260 {
261 panic(NULL, "Failed to create ramfs file inode");
262 }
263 DEREF_DEFER(inode);
264
265 if (dentry_make_positive(dentry, inode) == ERR)
266 {
267 panic(NULL, "Failed to make ramfs file dentry positive");
268 }
269
270 return REF(dentry);
271}
272
273static dentry_t* ramfs_load_dir(superblock_t* superblock, dentry_t* parent, const char* name, const boot_dir_t* in)
274{
275 ramfs_superblock_data_t* superData = superblock->private;
276
277 dentry_t* dentry = dentry_new(superblock, parent, name);
278 if (dentry == NULL)
279 {
280 panic(NULL, "Failed to create ramfs dentry");
281 }
282 DEREF_DEFER(dentry);
283
284 if (ramfs_dentry_init(dentry) == ERR)
285 {
286 panic(NULL, "Failed to initialize ramfs dentry");
287 }
288
289 inode_t* inode = ramfs_inode_new(superblock, INODE_DIR, NULL, 0);
290 if (inode == NULL)
291 {
292 panic(NULL, "Failed to create ramfs inode");
293 }
294 DEREF_DEFER(inode);
295
296 if (dentry_make_positive(dentry, inode) == ERR)
297 {
298 panic(NULL, "Failed to make ramfs dentry positive");
299 }
300
302 LIST_FOR_EACH(file, &in->files, entry)
303 {
304 DEREF(ramfs_load_file(superblock, dentry, file->name, file));
305 }
306
307 boot_dir_t* child;
308 LIST_FOR_EACH(child, &in->children, entry)
309 {
310 DEREF(ramfs_load_dir(superblock, dentry, child->name, child));
311 }
312
313 return REF(dentry);
314}
315
316static dentry_t* ramfs_mount(filesystem_t* fs, const char* devName, void* private)
317{
318 (void)devName; // Unused
319
321 if (superblock == NULL)
322 {
323 return NULL;
324 }
325 DEREF_DEFER(superblock);
326
327 superblock->blockSize = 0;
328 superblock->maxFileSize = UINT64_MAX;
329
331 if (data == NULL)
332 {
333 return NULL;
334 }
335 list_init(&data->dentrys);
336 lock_init(&data->lock);
337 superblock->private = data;
338
339 boot_disk_t* disk = private;
340
341 superblock->root = ramfs_load_dir(superblock, NULL, VFS_ROOT_ENTRY_NAME, disk->root);
342 if (superblock->root == NULL)
343 {
344 return NULL;
345 }
346
347 return REF(superblock->root);
348}
349
350static inode_t* ramfs_inode_new(superblock_t* superblock, inode_type_t type, void* buffer, uint64_t size)
351{
352 inode_t* inode = inode_new(superblock, atomic_fetch_add(&newNumber, 1), type, &inodeOps, &fileOps);
353 if (inode == NULL)
354 {
355 return NULL;
356 }
357 DEREF_DEFER(inode);
358
359 inode->blocks = 0;
360
361 if (buffer != NULL)
362 {
363 inode->private = malloc(size);
364 if (inode->private == NULL)
365 {
366 return NULL;
367 }
368 memcpy(inode->private, buffer, size);
369 inode->size = size;
370 }
371 else
372 {
373 inode->private = NULL;
374 inode->size = 0;
375 }
376
377 return REF(inode);
378}
379
381 .name = RAMFS_NAME,
382 .mount = ramfs_mount,
383};
384
385void ramfs_init(const boot_disk_t* disk)
386{
387 LOG_INFO("registering ramfs\n");
388 if (vfs_register_fs(&ramfs) == ERR)
389 {
390 panic(NULL, "Failed to register ramfs");
391 }
392 LOG_INFO("mounting ramfs\n");
394 if (mount == NULL)
395 {
396 panic(NULL, "Failed to mount ramfs");
397 }
398 LOG_INFO("ramfs initialized\n");
399}
#define assert(expression)
Definition assert.h:29
static fd_t data
Definition dwm.c:21
dentry_t * dentry_new(superblock_t *superblock, dentry_t *parent, const char *name)
Create a new dentry.
Definition dentry.c:51
uint64_t dentry_make_positive(dentry_t *dentry, inode_t *inode)
Make a dentry positive by associating it with an inode.
Definition dentry.c:101
uint64_t dentry_generic_getdents(dentry_t *dentry, dirent_t *buffer, uint64_t count, uint64_t *offset, path_flags_t flags)
Helper function for a basic getdents.
Definition dentry.c:195
uint64_t file_generic_seek(file_t *file, int64_t offset, seek_origin_t origin)
Helper function for basic seeking.
Definition file.c:51
inode_t * inode_new(superblock_t *superblock, inode_number_t number, inode_type_t type, const inode_ops_t *ops, const file_ops_t *fileOps)
Create a new inode.
Definition inode.c:42
mount_t * namespace_mount(namespace_t *ns, path_t *mountpoint, const char *deviceName, const char *fsName, void *private)
Mount a filesystem in a namespace.
Definition namespace.c:107
path_flags_t
Path flags.
Definition path.h:83
@ PATH_DIRECTORY
Definition path.h:90
@ PATH_RECURSIVE
Definition path.h:91
#define RAMFS_NAME
The name of the ramfs filesystem.
Definition ramfs.h:26
void ramfs_init(const boot_disk_t *disk)
Registers the ramfs filesystem and mounts it as the root filesystem.
Definition ramfs.c:385
superblock_t * superblock_new(const filesystem_t *fs, const char *deviceName, const superblock_ops_t *ops, const dentry_ops_t *dentryOps)
Create a new superblock.
Definition superblock.c:32
uint64_t vfs_register_fs(filesystem_t *fs)
Registers a filesystem.
Definition vfs.c:102
#define VFS_ROOT_ENTRY_NAME
The name of the root entry.
Definition vfs.h:34
#define VFS_DEVICE_NAME_NONE
The name used to indicate no device.
Definition vfs.h:39
#define BUFFER_READ(buffer, count, offset, src, size)
Helper macros for implementing file operations dealing with simple buffers.
Definition vfs.h:372
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:362
#define LOG_INFO(format,...)
Definition log.h:87
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:80
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:140
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:97
#define MUTEX_SCOPE(mutex)
Acquires a mutex for the reminder of the current scope.
Definition mutex.h:23
#define DEREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:54
#define REF(ptr)
Increment reference count.
Definition ref.h:65
#define DEREF(ptr)
Decrement reference count.
Definition ref.h:80
#define ENOTEMPTY
Directory not empty.
Definition errno.h:227
#define errno
Error number variable.
Definition errno.h:27
inode_type_t
Inode type enum.
Definition io.h:344
uint64_t inode_number_t
Inode number enum.
Definition io.h:353
@ INODE_FILE
Is a file.
Definition io.h:345
@ INODE_DIR
Is a directory.
Definition io.h:346
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:65
#define LIST_FOR_EACH_SAFE(elem, temp, list, member)
Safely iterates over a list, allowing for element removal during iteration.
Definition list.h:81
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:317
static void list_push(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:345
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:229
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:184
static void list_init(list_t *list)
Initializes a list.
Definition list.h:198
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static dentry_t * file
Definition log_file.c:17
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static atomic_long count
Definition main.c:9
static inode_ops_t inodeOps
Definition ramfs.c:220
static void ramfs_superblock_cleanup(superblock_t *superblock)
Definition ramfs.c:233
static dentry_t * ramfs_load_file(superblock_t *superblock, dentry_t *parent, const char *name, const boot_file_t *in)
Definition ramfs.c:244
static dentry_ops_t dentryOps
Definition ramfs.c:229
static void ramfs_truncate(inode_t *inode)
Definition ramfs.c:136
static dentry_t * ramfs_mount(filesystem_t *fs, const char *devName, void *private)
Definition ramfs.c:316
static dentry_t * ramfs_load_dir(superblock_t *superblock, dentry_t *parent, const char *name, const boot_dir_t *in)
Definition ramfs.c:273
static filesystem_t ramfs
Definition ramfs.c:380
static void ramfs_inode_cleanup(inode_t *inode)
Definition ramfs.c:212
static uint64_t ramfs_link(dentry_t *old, inode_t *dir, dentry_t *target)
Definition ramfs.c:146
static uint64_t ramfs_remove(inode_t *parent, dentry_t *target, path_flags_t flags)
Definition ramfs.c:178
static uint64_t ramfs_remove_file(inode_t *parent, dentry_t *target)
Definition ramfs.c:161
static inode_t * ramfs_inode_new(superblock_t *superblock, inode_type_t type, void *buffer, uint64_t size)
Definition ramfs.c:350
static void ramfs_dentry_deinit(dentry_t *dentry)
Definition ramfs.c:49
static uint64_t ramfs_write(file_t *file, const void *buffer, uint64_t count, uint64_t *offset)
Definition ramfs.c:78
static uint64_t ramfs_create(inode_t *dir, dentry_t *target, path_flags_t flags)
Definition ramfs.c:114
static superblock_ops_t superOps
Definition ramfs.c:240
static uint64_t ramfs_lookup(inode_t *dir, dentry_t *target)
Definition ramfs.c:105
static uint64_t ramfs_read(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition ramfs.c:66
static mount_t * mount
Definition ramfs.c:24
static file_ops_t fileOps
Definition ramfs.c:99
static uint64_t ramfs_remove_directory(inode_t *parent, dentry_t *target)
Definition ramfs.c:170
#define _Atomic(T)
Definition stdatomic.h:59
#define ATOMIC_VAR_INIT(value)
Definition stdatomic.h:74
#define atomic_fetch_add(object, operand)
Definition stdatomic.h:283
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
#define UINT64_MAX
Definition stdint.h:74
_PUBLIC void * realloc(void *ptr, size_t size)
Definition realloc.c:13
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC void * memcpy(void *_RESTRICT s1, const void *_RESTRICT s2, size_t n)
Definition memcpy.c:4
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
list_t files
Definition boot_info.h:68
list_t children
Definition boot_info.h:67
char name[MAX_NAME]
Definition boot_info.h:66
boot_dir_t * root
Definition boot_info.h:73
void * data
Definition boot_info.h:59
uint64_t size
Definition boot_info.h:60
Dentry operations structure.
Definition dentry.h:70
uint64_t(* getdents)(dentry_t *dentry, dirent_t *buffer, uint64_t count, uint64_t *offset, path_flags_t flags)
Used to now what is in a directory.
Definition dentry.h:74
Directory entry structure.
Definition dentry.h:83
list_t children
Definition dentry.h:90
inode_t * inode
Definition dentry.h:87
char name[MAX_NAME]
Definition dentry.h:86
void * private
Definition dentry.h:94
superblock_t * superblock
Definition dentry.h:92
File operations structure.
Definition file.h:57
uint64_t(* read)(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition file.h:61
File structure.
Definition file.h:37
Filesystem structure, represents a filesystem type, e.g. fat32, ramfs, sysfs, etc.
Definition vfs.h:45
const char * name
Definition vfs.h:47
uint64_t(* lookup)(inode_t *dir, dentry_t *target)
Should set the target dentry to be positive (give it an inode), if the entry does not exist the opera...
Definition inode.h:87
Inode structure.
Definition inode.h:54
uint64_t blocks
Definition inode.h:61
mutex_t mutex
Definition inode.h:70
void * private
Definition inode.h:66
inode_type_t type
Constant after creation.
Definition inode.h:57
superblock_t * superblock
Constant after creation.
Definition inode.h:67
uint64_t size
Definition inode.h:60
uint64_t linkCount
Definition inode.h:59
Mount structure.
Definition mount.h:36
Dentry private data for ramfs.
Definition ramfs.h:41
dentry_t * dentry
Definition ramfs.h:43
list_entry_t entry
Definition ramfs.h:42
Superblock private data for ramfs.
Definition ramfs.h:32
Superblock operations structure.
Definition superblock.h:70
void(* cleanup)(superblock_t *superblock)
Definition superblock.h:85
Superblock structure.
Definition superblock.h:44
uint64_t blockSize
Definition superblock.h:48
uint64_t maxFileSize
Definition superblock.h:49
dentry_t * root
Definition superblock.h:51
void * private
Definition superblock.h:50