PatchworkOS  dbbdc99
A non-POSIX operating system.
Loading...
Searching...
No Matches
tmpfs.c
Go to the documentation of this file.
1#include <kernel/fs/tmpfs.h>
2
3#include <kernel/fs/dentry.h>
4#include <kernel/fs/devfs.h>
5#include <kernel/fs/file.h>
7#include <kernel/fs/mount.h>
9#include <kernel/fs/path.h>
10#include <kernel/fs/vfs.h>
11#include <kernel/fs/vnode.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/fs.h>
25#include <sys/list.h>
26#include <sys/math.h>
27
28static bool initialized = false;
29
30static vnode_t* tmpfs_vnode_new(superblock_t* superblock, vtype_t type, void* buffer, uint64_t size);
31
32static void tmpfs_dentry_add(dentry_t* dentry)
33{
34 tmpfs_superblock_data_t* super = dentry->superblock->data;
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 tmpfs_dentry_remove(dentry_t* dentry)
43{
44 tmpfs_superblock_data_t* super = dentry->superblock->data;
45
46 lock_acquire(&super->lock);
47 list_remove(&dentry->otherEntry);
48 UNREF(dentry);
49 lock_release(&super->lock);
50
51 dentry_remove(dentry);
52}
53
54static size_t tmpfs_read(file_t* file, void* buffer, size_t count, size_t* offset)
55{
56 MUTEX_SCOPE(&file->vnode->mutex);
57
58 if (file->vnode->data == NULL)
59 {
60 return 0;
61 }
62
63 return BUFFER_READ(buffer, count, offset, file->vnode->data, file->vnode->size);
64}
65
66static size_t tmpfs_write(file_t* file, const void* buffer, size_t count, size_t* offset)
67{
68 MUTEX_SCOPE(&file->vnode->mutex);
69
70 size_t requiredSize = *offset + count;
71 if (requiredSize > file->vnode->size)
72 {
73 void* newData = realloc(file->vnode->data, requiredSize);
74 if (newData == NULL)
75 {
76 return ERR;
77 }
78 memset(newData + file->vnode->size, 0, requiredSize - file->vnode->size);
79 file->vnode->data = newData;
80 file->vnode->size = requiredSize;
81 }
82
83 return BUFFER_WRITE(buffer, count, offset, file->vnode->data, file->vnode->size);
84}
85
88 .write = tmpfs_write,
89 .seek = file_generic_seek,
90};
91
93{
94 MUTEX_SCOPE(&dir->mutex);
95
97 if (vnode == NULL)
98 {
99 return ERR;
100 }
101 UNREF_DEFER(vnode);
102
103 dentry_make_positive(target, vnode);
104 tmpfs_dentry_add(target);
105
106 return 0;
107}
108
109static void tmpfs_truncate(vnode_t* vnode)
110{
111 MUTEX_SCOPE(&vnode->mutex);
112
113 if (vnode->data != NULL)
114 {
115 free(vnode->data);
116 vnode->data = NULL;
117 }
118 vnode->size = 0;
119}
120
122{
123 MUTEX_SCOPE(&dir->mutex);
124
125 dentry_make_positive(target, old->vnode);
126 tmpfs_dentry_add(target);
127
128 return 0;
129}
130
132{
133 MUTEX_SCOPE(&vnode->mutex);
134
135 if (vnode->data == NULL)
136 {
137 errno = EINVAL;
138 return ERR;
139 }
140
141 uint64_t copySize = MIN(count, vnode->size);
142 memcpy(buffer, vnode->data, copySize);
143 return copySize;
144}
145
146static uint64_t tmpfs_symlink(vnode_t* dir, dentry_t* target, const char* dest)
147{
148 MUTEX_SCOPE(&dir->mutex);
149
150 vnode_t* vnode = tmpfs_vnode_new(dir->superblock, VSYMLINK, (void*)dest, strlen(dest));
151 if (vnode == NULL)
152 {
153 return ERR;
154 }
155 UNREF_DEFER(vnode);
156
157 dentry_make_positive(target, vnode);
158 tmpfs_dentry_add(target);
159
160 return 0;
161}
162
164{
165 MUTEX_SCOPE(&dir->mutex);
166
167 if (target->vnode->type == VREG || target->vnode->type == VSYMLINK)
168 {
169 tmpfs_dentry_remove(target);
170 }
171 else if (target->vnode->type == VDIR)
172 {
173 if (!list_is_empty(&target->children))
174 {
176 return ERR;
177 }
178
179 tmpfs_dentry_remove(target);
180 }
181
182 return 0;
183}
184
185static void tmpfs_vnode_cleanup(vnode_t* vnode)
186{
187 if (vnode->data != NULL)
188 {
189 free(vnode->data);
190 vnode->data = NULL;
191 vnode->size = 0;
192 }
193}
194
197 .truncate = tmpfs_truncate,
198 .link = tmpfs_link,
199 .readlink = tmpfs_readlink,
200 .symlink = tmpfs_symlink,
201 .remove = tmpfs_remove,
202 .cleanup = tmpfs_vnode_cleanup,
203};
204
208
210{
211 UNUSED(superblock);
212
213 panic(NULL, "tmpfs unmounted\n");
214}
215
219
220static dentry_t* tmpfs_load_file(superblock_t* superblock, dentry_t* parent, const char* name, const boot_file_t* in)
221{
222 dentry_t* dentry = dentry_new(superblock, parent, name);
223 if (dentry == NULL)
224 {
225 panic(NULL, "Failed to create tmpfs file dentry");
226 }
227 UNREF_DEFER(dentry);
228
229 tmpfs_dentry_add(dentry);
230
231 vnode_t* vnode = tmpfs_vnode_new(superblock, VREG, in->data, in->size);
232 if (vnode == NULL)
233 {
234 panic(NULL, "Failed to create tmpfs file vnode");
235 }
236 UNREF_DEFER(vnode);
237
238 dentry_make_positive(dentry, vnode);
239
240 return REF(dentry);
241}
242
243static dentry_t* tmpfs_load_dir(superblock_t* superblock, dentry_t* parent, const char* name, const boot_dir_t* in)
244{
245 tmpfs_superblock_data_t* superData = superblock->data;
246
247 dentry_t* dentry = dentry_new(superblock, parent, name);
248 if (dentry == NULL)
249 {
250 panic(NULL, "Failed to create tmpfs dentry");
251 }
252 UNREF_DEFER(dentry);
253
254 vnode_t* vnode = tmpfs_vnode_new(superblock, VDIR, NULL, 0);
255 if (vnode == NULL)
256 {
257 panic(NULL, "Failed to create tmpfs vnode");
258 }
259 UNREF_DEFER(vnode);
260
261 tmpfs_dentry_add(dentry);
262 dentry_make_positive(dentry, vnode);
263
264 boot_file_t* file;
265 LIST_FOR_EACH(file, &in->files, entry)
266 {
267 UNREF(tmpfs_load_file(superblock, dentry, file->name, file));
268 }
269
270 boot_dir_t* child;
271 LIST_FOR_EACH(child, &in->children, entry)
272 {
273 UNREF(tmpfs_load_dir(superblock, dentry, child->name, child));
274 }
275
276 return REF(dentry);
277}
278
279static dentry_t* tmpfs_mount(filesystem_t* fs, const char* options, void* data)
280{
281 UNUSED(data);
282
283 if (options != NULL)
284 {
285 errno = EINVAL;
286 return NULL;
287 }
288
289 superblock_t* superblock = superblock_new(fs, &superOps, &dentryOps);
290 if (superblock == NULL)
291 {
292 return NULL;
293 }
294 UNREF_DEFER(superblock);
295
296 superblock->blockSize = 0;
297 superblock->maxFileSize = UINT64_MAX;
298
300 if (tmpfsData == NULL)
301 {
302 return NULL;
303 }
304 list_init(&tmpfsData->dentrys);
305 lock_init(&tmpfsData->lock);
306 superblock->data = tmpfsData;
307
308 if (!initialized)
309 {
311 const boot_disk_t* disk = &bootInfo->disk;
312
313 dentry_t* root = tmpfs_load_dir(superblock, NULL, NULL, disk->root);
314 if (root == NULL)
315 {
316 return NULL;
317 }
318
319 superblock->root = root;
320 return REF(superblock->root);
321 }
322
323 dentry_t* dentry = dentry_new(superblock, NULL, NULL);
324 if (dentry == NULL)
325 {
326 return NULL;
327 }
328 UNREF_DEFER(dentry);
329
330 vnode_t* vnode = tmpfs_vnode_new(superblock, VDIR, NULL, 0);
331 if (vnode == NULL)
332 {
333 return NULL;
334 }
335 UNREF_DEFER(vnode);
336
337 tmpfs_dentry_add(dentry);
338 dentry_make_positive(dentry, vnode);
339
340 superblock->root = dentry;
341 return REF(superblock->root);
342}
343
344static vnode_t* tmpfs_vnode_new(superblock_t* superblock, vtype_t type, void* buffer, uint64_t size)
345{
346 vnode_t* vnode = vnode_new(superblock, type, &vnodeOps, &fileOps);
347 if (vnode == NULL)
348 {
349 return NULL;
350 }
351 UNREF_DEFER(vnode);
352
353 if (buffer != NULL)
354 {
355 vnode->data = malloc(size);
356 if (vnode->data == NULL)
357 {
358 return NULL;
359 }
360 memcpy(vnode->data, buffer, size);
361 vnode->size = size;
362 }
363 else
364 {
365 vnode->data = NULL;
366 vnode->size = 0;
367 }
368
369 return REF(vnode);
370}
371
373 .name = TMPFS_NAME,
374 .mount = tmpfs_mount,
375};
376
377void tmpfs_init(void)
378{
379 LOG_INFO("registering tmpfs\n");
381 {
382 panic(NULL, "Failed to register tmpfs");
383 }
384 LOG_INFO("mounting tmpfs\n");
385
386 process_t* process = process_current();
387 assert(process != NULL);
388
389 namespace_t* ns = process_get_ns(process);
390 if (ns == NULL)
391 {
392 panic(NULL, "Failed to get process namespace");
393 }
394 UNREF_DEFER(ns);
395
397 if (temp == NULL)
398 {
399 panic(NULL, "Failed to mount tmpfs");
400 }
401 UNREF(temp);
402 LOG_INFO("tmpfs initialized\n");
403
404 initialized = true;
405}
#define assert(expression)
Definition assert.h:29
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
boot_info_t * bootInfo
Definition boot_info.c:14
static dentry_t * root
Definition devfs.c:25
static fd_t data
Definition dwm.c:21
static dentry_t * dir
Definition fb.c:16
dentry_t * dentry_new(superblock_t *superblock, dentry_t *parent, const char *name)
Create a new dentry.
Definition dentry.c:134
uint64_t dentry_generic_iterate(dentry_t *dentry, dir_ctx_t *ctx)
Helper function for a basic iterate.
Definition dentry.c:325
void dentry_make_positive(dentry_t *dentry, vnode_t *vnode)
Make a dentry positive by associating it with an vnode.
Definition dentry.c:289
void dentry_remove(dentry_t *dentry)
Remove a dentry from the dentry cache.
Definition dentry.c:178
size_t file_generic_seek(file_t *file, ssize_t offset, seek_origin_t origin)
Helper function for basic seeking.
Definition file.c:76
uint64_t filesystem_register(filesystem_t *fs)
Registers a filesystem.
Definition filesystem.c:233
mount_t * namespace_mount(namespace_t *ns, path_t *target, filesystem_t *fs, const char *options, mode_t mode, void *data)
Mount a filesystem in a namespace.
Definition namespace.c:387
mode_t
Path flags and permissions.
Definition path.h:79
@ MODE_ALL_PERMS
Definition path.h:96
@ MODE_PROPAGATE
Definition path.h:94
@ MODE_DIRECTORY
Definition path.h:90
superblock_t * superblock_new(filesystem_t *fs, const superblock_ops_t *ops, const dentry_ops_t *dentryOps)
Create a new superblock.
Definition superblock.c:33
void tmpfs_init(void)
Registers the tmpfs filesystem and mounts an instance of it containing the boot ram disk as root.
Definition tmpfs.c:377
#define TMPFS_NAME
The name of the tmpfs filesystem.
Definition tmpfs.h:25
vnode_t * vnode_new(superblock_t *superblock, vtype_t type, const vnode_ops_t *ops, const file_ops_t *fileOps)
Create a new vnode.
Definition vnode.c:51
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:292
#define LOG_INFO(format,...)
Definition log.h:91
static process_t * process_current(void)
Retrieves the process of the currently running thread.
Definition process.h:131
namespace_t * process_get_ns(process_t *process)
Gets the namespace of a process.
Definition process.c:206
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:79
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:175
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:96
#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:122
#define REF(ptr)
Increment reference count.
Definition ref.h:82
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:109
#define BUFFER_WRITE(buffer, count, offset, dest, size)
Helper macro for implementing file operations dealing with simple buffer writes.
Definition vfs.h:227
#define BUFFER_READ(buffer, count, offset, src, size)
Helper macros for implementing file operations dealing with simple buffers.
Definition vfs.h:209
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ENOTEMPTY
Directory not empty.
Definition errno.h:227
#define errno
Error number variable.
Definition errno.h:27
#define UNUSED(x)
Mark a variable as unused.
Definition defs.h:96
vtype_t
Vnode type enum.
Definition fs.h:342
@ VSYMLINK
Is a symbolic link.
Definition fs.h:345
@ VREG
Is a regular file.
Definition fs.h:343
@ VDIR
Is a directory.
Definition fs.h:344
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:58
static void list_remove(list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:290
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:322
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:210
static void list_init(list_t *list)
Initializes a list.
Definition list.h:185
#define MIN(x, y)
Definition math.h:18
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
static uint64_t offset
Definition screen.c:19
static atomic_long count
Definition main.c:11
__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 size_t strlen(const char *s)
Definition strlen.c:3
_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
size_t size
Definition boot_info.h:69
void * data
Definition boot_info.h:68
char name[MAX_NAME]
Definition boot_info.h:67
boot_disk_t disk
Definition boot_info.h:104
Dentry operations structure.
Definition dentry.h:122
uint64_t(* iterate)(dentry_t *dentry, dir_ctx_t *ctx)
Iterate over the entries in a directory dentry.
Definition dentry.h:138
Directory entry structure.
Definition dentry.h:155
list_t children
Definition dentry.h:162
list_entry_t otherEntry
Made available for use by any other subsystems for convenience.
Definition dentry.h:169
vnode_t * vnode
Will be NULL if the dentry is negative, once positive it will never be modified.
Definition dentry.h:159
superblock_t * superblock
Definition dentry.h:163
File operations structure.
Definition file.h:54
size_t(* read)(file_t *file, void *buffer, size_t count, size_t *offset)
Definition file.h:58
File structure.
Definition file.h:39
vnode_t * vnode
Definition file.h:43
Filesystem structure, represents a filesystem type, e.g. fat32, tmpfs, devfs, etc.
Definition filesystem.h:53
const char * name
Definition filesystem.h:58
Mount structure.
Definition mount.h:48
Namespace structure.
Definition namespace.h:57
Process structure.
Definition process.h:76
Superblock operations structure.
Definition superblock.h:59
void(* cleanup)(superblock_t *superblock)
Definition superblock.h:64
Superblock structure.
Definition superblock.h:33
uint64_t blockSize
Definition superblock.h:37
uint64_t maxFileSize
Definition superblock.h:38
dentry_t * root
Root dentry of the filesystem, should not take a reference.
Definition superblock.h:40
void * data
Definition superblock.h:39
Superblock private data for tmpfs.
Definition tmpfs.h:31
vnode operations structure.
Definition vnode.h:69
uint64_t(* create)(vnode_t *dir, dentry_t *target, mode_t mode)
Handles both directories and files depending on mode.
Definition vnode.h:91
vnode structure.
Definition vnode.h:48
mutex_t mutex
Definition vnode.h:59
uint64_t size
Used for convenience by certain filesystems, does not represent the file size.
Definition vnode.h:53
vtype_t type
Definition vnode.h:50
void * data
Filesystem defined data.
Definition vnode.h:52
static uint64_t tmpfs_symlink(vnode_t *dir, dentry_t *target, const char *dest)
Definition tmpfs.c:146
static dentry_t * tmpfs_load_file(superblock_t *superblock, dentry_t *parent, const char *name, const boot_file_t *in)
Definition tmpfs.c:220
static dentry_ops_t dentryOps
Definition tmpfs.c:205
static dentry_t * tmpfs_load_dir(superblock_t *superblock, dentry_t *parent, const char *name, const boot_dir_t *in)
Definition tmpfs.c:243
static filesystem_t tmpfs
Definition tmpfs.c:372
static void tmpfs_dentry_remove(dentry_t *dentry)
Definition tmpfs.c:42
static uint64_t tmpfs_link(vnode_t *dir, dentry_t *old, dentry_t *target)
Definition tmpfs.c:121
static size_t tmpfs_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition tmpfs.c:54
static void tmpfs_superblock_cleanup(superblock_t *superblock)
Definition tmpfs.c:209
static vnode_ops_t vnodeOps
Definition tmpfs.c:195
static void tmpfs_vnode_cleanup(vnode_t *vnode)
Definition tmpfs.c:185
static uint64_t tmpfs_remove(vnode_t *dir, dentry_t *target)
Definition tmpfs.c:163
static void tmpfs_dentry_add(dentry_t *dentry)
Definition tmpfs.c:32
static uint64_t tmpfs_create(vnode_t *dir, dentry_t *target, mode_t mode)
Definition tmpfs.c:92
static size_t tmpfs_write(file_t *file, const void *buffer, size_t count, size_t *offset)
Definition tmpfs.c:66
static superblock_ops_t superOps
Definition tmpfs.c:216
static uint64_t tmpfs_readlink(vnode_t *vnode, char *buffer, uint64_t count)
Definition tmpfs.c:131
static vnode_t * tmpfs_vnode_new(superblock_t *superblock, vtype_t type, void *buffer, uint64_t size)
Definition tmpfs.c:344
static dentry_t * tmpfs_mount(filesystem_t *fs, const char *options, void *data)
Definition tmpfs.c:279
static file_ops_t fileOps
Definition tmpfs.c:86
static void tmpfs_truncate(vnode_t *vnode)
Definition tmpfs.c:109
static bool initialized
Definition tmpfs.c:28