PatchworkOS  966e257
A non-POSIX operating system.
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/file.h>
6#include <kernel/fs/inode.h>
7#include <kernel/fs/mount.h>
9#include <kernel/fs/path.h>
10#include <kernel/fs/sysfs.h>
11#include <kernel/fs/vfs.h>
13#include <kernel/log/log.h>
14#include <kernel/log/panic.h>
15#include <kernel/sched/sched.h>
16#include <kernel/sync/lock.h>
17#include <kernel/sync/mutex.h>
18#include <kernel/utils/ref.h>
19
20#include <assert.h>
21#include <errno.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/io.h>
25#include <sys/list.h>
26#include <sys/math.h>
27
28static mount_t* mount = NULL;
29
30static inode_t* ramfs_inode_new(superblock_t* superblock, inode_type_t type, void* buffer, uint64_t size);
31
32static void ramfs_dentry_add(dentry_t* dentry)
33{
35
36 lock_acquire(&super->lock);
37 list_push_back(&super->dentrys, &dentry->otherEntry);
38 REF(dentry);
39 lock_release(&super->lock);
40}
41
42static void ramfs_dentry_remove(dentry_t* dentry)
43{
45
46 lock_acquire(&super->lock);
47 list_remove(&super->dentrys, &dentry->otherEntry);
48 UNREF(dentry);
49 lock_release(&super->lock);
50}
51
53{
55
56 if (file->inode->private == NULL)
57 {
58 return 0;
59 }
60
61 return BUFFER_READ(buffer, count, offset, file->inode->private, file->inode->size);
62}
63
65{
67
68 uint64_t requiredSize = *offset + count + 1;
69 if (requiredSize > file->inode->size)
70 {
71 void* newData = realloc(file->inode->private, requiredSize);
72 if (newData == NULL)
73 {
74 return ERR;
75 }
76 memset(newData + file->inode->size, 0, requiredSize - file->inode->size);
77 file->inode->private = newData;
78 file->inode->size = requiredSize;
79 }
80
81 return BUFFER_WRITE(file->inode->private, count, offset, buffer, file->inode->size);
82}
83
86 .write = ramfs_write,
87 .seek = file_generic_seek,
88};
89
90static uint64_t ramfs_create(inode_t* dir, dentry_t* target, mode_t mode)
91{
92 MUTEX_SCOPE(&dir->mutex);
93
95 if (inode == NULL)
96 {
97 return ERR;
98 }
99 UNREF_DEFER(inode);
100
101 dentry_make_positive(target, inode);
102 ramfs_dentry_add(target);
103
104 return 0;
105}
106
107static void ramfs_truncate(inode_t* inode)
108{
109 MUTEX_SCOPE(&inode->mutex);
110
111 if (inode->private != NULL)
112 {
113 free(inode->private);
114 inode->private = NULL;
115 }
116 inode->size = 0;
117}
118
119static uint64_t ramfs_link(inode_t* dir, dentry_t* old, dentry_t* target)
120{
121 MUTEX_SCOPE(&dir->mutex);
122
123 dentry_make_positive(target, old->inode);
124 ramfs_dentry_add(target);
125
126 return 0;
127}
128
129static uint64_t ramfs_remove(inode_t* dir, dentry_t* target, mode_t mode)
130{
131 MUTEX_SCOPE(&dir->mutex);
132
133 if (target->inode->type == INODE_FILE)
134 {
135 ramfs_dentry_remove(target);
136 }
137 else if (target->inode->type == INODE_DIR)
138 {
139 if (mode & MODE_RECURSIVE)
140 {
141 dentry_t* temp = NULL;
142 dentry_t* child = NULL;
143 LIST_FOR_EACH_SAFE(child, temp, &target->children, siblingEntry)
144 {
145 REF(child);
146 ramfs_remove(target->inode, child, mode);
147 UNREF(child);
148 }
149 }
150 else
151 {
152 if (!list_is_empty(&target->children))
153 {
155 return ERR;
156 }
157 }
158 ramfs_dentry_remove(target);
159 }
160 return 0;
161}
162
163static void ramfs_inode_cleanup(inode_t* inode)
164{
165 if (inode->private != NULL)
166 {
167 free(inode->private);
168 inode->private = NULL;
169 inode->size = 0;
170 }
171}
172
175 .truncate = ramfs_truncate,
176 .link = ramfs_link,
177 .remove = ramfs_remove,
178 .cleanup = ramfs_inode_cleanup,
179};
180
184
186{
187 (void)superblock; // Unused
188
189 panic(NULL, "ramfs unmounted\n");
190}
191
195
196static dentry_t* ramfs_load_file(superblock_t* superblock, dentry_t* parent, const char* name, const boot_file_t* in)
197{
198 dentry_t* dentry = dentry_new(superblock, parent, name);
199 if (dentry == NULL)
200 {
201 panic(NULL, "Failed to create ramfs file dentry");
202 }
203 UNREF_DEFER(dentry);
204
205 ramfs_dentry_add(dentry);
206
207 inode_t* inode = ramfs_inode_new(superblock, INODE_FILE, in->data, in->size);
208 if (inode == NULL)
209 {
210 panic(NULL, "Failed to create ramfs file inode");
211 }
212 UNREF_DEFER(inode);
213
214 dentry_make_positive(dentry, inode);
215
216 return REF(dentry);
217}
218
219static dentry_t* ramfs_load_dir(superblock_t* superblock, dentry_t* parent, const char* name, const boot_dir_t* in)
220{
221 ramfs_superblock_data_t* superData = superblock->private;
222
223 dentry_t* dentry = dentry_new(superblock, parent, name);
224 if (dentry == NULL)
225 {
226 panic(NULL, "Failed to create ramfs dentry");
227 }
228 UNREF_DEFER(dentry);
229
230 ramfs_dentry_add(dentry);
231
232 inode_t* inode = ramfs_inode_new(superblock, INODE_DIR, NULL, 0);
233 if (inode == NULL)
234 {
235 panic(NULL, "Failed to create ramfs inode");
236 }
237 UNREF_DEFER(inode);
238
239 dentry_make_positive(dentry, inode);
240
242 LIST_FOR_EACH(file, &in->files, entry)
243 {
244 UNREF(ramfs_load_file(superblock, dentry, file->name, file));
245 }
246
247 boot_dir_t* child;
248 LIST_FOR_EACH(child, &in->children, entry)
249 {
250 UNREF(ramfs_load_dir(superblock, dentry, child->name, child));
251 }
252
253 return REF(dentry);
254}
255
256static dentry_t* ramfs_mount(filesystem_t* fs, const char* devName, void* private)
257{
258 (void)devName; // Unused
259 (void)private; // Unused
260
262 if (superblock == NULL)
263 {
264 return NULL;
265 }
266 UNREF_DEFER(superblock);
267
268 superblock->blockSize = 0;
269 superblock->maxFileSize = UINT64_MAX;
270
272 if (data == NULL)
273 {
274 return NULL;
275 }
276 list_init(&data->dentrys);
277 lock_init(&data->lock);
278 superblock->private = data;
279
281 const boot_disk_t* disk = &bootInfo->disk;
282
283 superblock->root = ramfs_load_dir(superblock, NULL, VFS_ROOT_ENTRY_NAME, disk->root);
284 if (superblock->root == NULL)
285 {
286 return NULL;
287 }
288
289 return REF(superblock->root);
290}
291
292static inode_t* ramfs_inode_new(superblock_t* superblock, inode_type_t type, void* buffer, uint64_t size)
293{
294 inode_t* inode = inode_new(superblock, vfs_id_get(), type, &inodeOps, &fileOps);
295 if (inode == NULL)
296 {
297 return NULL;
298 }
299 UNREF_DEFER(inode);
300
301 inode->blocks = 0;
302
303 if (buffer != NULL)
304 {
305 inode->private = malloc(size);
306 if (inode->private == NULL)
307 {
308 return NULL;
309 }
310 memcpy(inode->private, buffer, size);
311 inode->size = size;
312 }
313 else
314 {
315 inode->private = NULL;
316 inode->size = 0;
317 }
318
319 return REF(inode);
320}
321
323 .name = RAMFS_NAME,
324 .mount = ramfs_mount,
325};
326
327void ramfs_init(void)
328{
329 LOG_INFO("registering ramfs\n");
331 {
332 panic(NULL, "Failed to register ramfs");
333 }
334 LOG_INFO("mounting ramfs\n");
335
336 process_t* process = sched_process();
339 if (mount == NULL)
340 {
341 panic(NULL, "Failed to mount ramfs");
342 }
343 LOG_INFO("ramfs initialized\n");
344}
boot_info_t * bootInfo
Definition boot_info.c:14
static fd_t data
Definition dwm.c:21
void dentry_make_positive(dentry_t *dentry, inode_t *inode)
Make a dentry positive by associating it with an inode.
Definition dentry.c:226
dentry_t * dentry_new(superblock_t *superblock, dentry_t *parent, const char *name)
Create a new dentry.
Definition dentry.c:114
uint64_t dentry_generic_getdents(dentry_t *dentry, dirent_t *buffer, uint64_t count, uint64_t *offset, mode_t mode)
Helper function for a basic getdents.
Definition dentry.c:345
uint64_t file_generic_seek(file_t *file, int64_t offset, seek_origin_t origin)
Helper function for basic seeking.
Definition file.c:92
uint64_t filesystem_register(filesystem_t *fs)
Registers a filesystem.
Definition filesystem.c:40
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:41
mode_t
Path flags and permissions.
Definition path.h:74
@ MODE_ALL_PERMS
Definition path.h:87
@ MODE_RECURSIVE
Definition path.h:85
@ MODE_DIRECTORY
Definition path.h:84
#define RAMFS_NAME
The name of the ramfs filesystem.
Definition ramfs.h:26
void ramfs_init(void)
Registers the ramfs filesystem and mounts it as the root filesystem.
Definition ramfs.c:327
superblock_t * superblock_new(filesystem_t *fs, const char *deviceName, const superblock_ops_t *ops, const dentry_ops_t *dentryOps)
Create a new superblock.
Definition superblock.c:35
boot_info_t * boot_info_get(void)
Gets the boot info structure.
Definition boot_info.c:16
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:266
#define LOG_INFO(format,...)
Definition log.h:106
process_t * sched_process(void)
Retrieves the process of the currently running thread.
Definition sched.c:620
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:86
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:146
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:103
#define MUTEX_SCOPE(mutex)
Acquires a mutex for the reminder of the current scope.
Definition mutex.h:23
#define UNREF_DEFER(ptr)
RAII-style cleanup for scoped references.
Definition ref.h:54
#define REF(ptr)
Increment reference count.
Definition ref.h:65
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:80
#define VFS_ROOT_ENTRY_NAME
The name of the root entry.
Definition vfs.h:32
#define VFS_DEVICE_NAME_NONE
The name used to indicate no device.
Definition vfs.h:37
#define BUFFER_READ(buffer, count, offset, src, size)
Helper macros for implementing file operations dealing with simple buffers.
Definition vfs.h:194
#define BUFFER_WRITE(buffer, count, offset, src, size)
Helper macro for implementing file operations dealing with simple buffer writes.
Definition vfs.h:212
uint64_t vfs_id_get(void)
Generates a new unique ID, to be used for any VFS object.
Definition vfs.c:765
#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:313
@ MOUNT_PROPAGATE_PARENT
Propagate the mount to parent namespaces.
Definition io.h:490
@ MOUNT_PROPAGATE_CHILDREN
Propagate the mount to child namespaces.
Definition io.h:491
@ INODE_FILE
Is a file.
Definition io.h:314
@ INODE_DIR
Is a directory.
Definition io.h:315
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:63
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:343
#define LIST_FOR_EACH_SAFE(elem, temp, list, member)
Safely iterates over a list, allowing for element removal during iteration.
Definition list.h:79
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:315
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:227
static void list_init(list_t *list)
Initializes a list.
Definition list.h:196
#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:22
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static atomic_long count
Definition main.c:10
static inode_ops_t inodeOps
Definition ramfs.c:173
static void ramfs_superblock_cleanup(superblock_t *superblock)
Definition ramfs.c:185
static void ramfs_dentry_add(dentry_t *dentry)
Definition ramfs.c:32
static void ramfs_dentry_remove(dentry_t *dentry)
Definition ramfs.c:42
static dentry_t * ramfs_load_file(superblock_t *superblock, dentry_t *parent, const char *name, const boot_file_t *in)
Definition ramfs.c:196
static dentry_ops_t dentryOps
Definition ramfs.c:181
static void ramfs_truncate(inode_t *inode)
Definition ramfs.c:107
static dentry_t * ramfs_mount(filesystem_t *fs, const char *devName, void *private)
Definition ramfs.c:256
static dentry_t * ramfs_load_dir(superblock_t *superblock, dentry_t *parent, const char *name, const boot_dir_t *in)
Definition ramfs.c:219
static filesystem_t ramfs
Definition ramfs.c:322
static void ramfs_inode_cleanup(inode_t *inode)
Definition ramfs.c:163
static uint64_t ramfs_link(inode_t *dir, dentry_t *old, dentry_t *target)
Definition ramfs.c:119
static inode_t * ramfs_inode_new(superblock_t *superblock, inode_type_t type, void *buffer, uint64_t size)
Definition ramfs.c:292
static uint64_t ramfs_create(inode_t *dir, dentry_t *target, mode_t mode)
Definition ramfs.c:90
static uint64_t ramfs_write(file_t *file, const void *buffer, uint64_t count, uint64_t *offset)
Definition ramfs.c:64
static superblock_ops_t superOps
Definition ramfs.c:192
static uint64_t ramfs_read(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition ramfs.c:52
static mount_t * mount
Definition ramfs.c:28
static uint64_t ramfs_remove(inode_t *dir, dentry_t *target, mode_t mode)
Definition ramfs.c:129
static file_ops_t fileOps
Definition ramfs.c:84
__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:61
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
list_t files
Definition boot_info.h:77
list_t children
Definition boot_info.h:76
char name[MAX_NAME]
Definition boot_info.h:75
boot_dir_t * root
Definition boot_info.h:82
void * data
Definition boot_info.h:68
uint64_t size
Definition boot_info.h:69
boot_disk_t disk
Definition boot_info.h:104
Dentry operations structure.
Definition dentry.h:72
uint64_t(* getdents)(dentry_t *dentry, dirent_t *buffer, uint64_t count, uint64_t *offset, mode_t mode)
Definition dentry.h:73
Directory entry structure.
Definition dentry.h:84
list_t children
Definition dentry.h:92
inode_t * inode
Will be NULL if the dentry is negative, once positive it will never be NULL.
Definition dentry.h:88
char name[MAX_NAME]
Constant after creation.
Definition dentry.h:87
list_entry_t otherEntry
Made available for use by any other subsystems for convenience.
Definition dentry.h:98
superblock_t * superblock
Definition dentry.h:93
File operations structure.
Definition file.h:54
uint64_t(* read)(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition file.h:58
File structure.
Definition file.h:39
Filesystem structure, represents a filesystem type, e.g. fat32, ramfs, sysfs, etc.
Definition filesystem.h:31
const char * name
Definition filesystem.h:35
Inode operations structure.
Definition inode.h:82
uint64_t(* create)(inode_t *dir, dentry_t *target, mode_t mode)
Handles both directories and files depending on mode.
Definition inode.h:104
Inode structure.
Definition inode.h:56
uint64_t blocks
Definition inode.h:63
mutex_t mutex
Definition inode.h:72
void * private
Definition inode.h:68
inode_type_t type
Constant after creation.
Definition inode.h:59
superblock_t * superblock
Constant after creation.
Definition inode.h:69
uint64_t size
Definition inode.h:62
Mount structure.
Definition mount.h:44
A mount in a namespace.
Process structure.
Definition process.h:205
namespace_t ns
Definition process.h:211
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