PatchworkOS  10941b4
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/inode.h>
8#include <kernel/fs/mount.h>
10#include <kernel/fs/path.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 bool initialized = false;
29
30static inode_t* tmpfs_inode_new(superblock_t* superblock, itype_t type, void* buffer, uint64_t size);
31
32static void tmpfs_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 tmpfs_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 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->inode->mutex);
57
58 if (file->inode->private == NULL)
59 {
60 return 0;
61 }
62
63 return BUFFER_READ(buffer, count, offset, file->inode->private, file->inode->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->inode->mutex);
69
70 size_t requiredSize = *offset + count;
71 if (requiredSize > file->inode->size)
72 {
73 void* newData = realloc(file->inode->private, requiredSize);
74 if (newData == NULL)
75 {
76 return ERR;
77 }
78 memset(newData + file->inode->size, 0, requiredSize - file->inode->size);
79 file->inode->private = newData;
80 file->inode->size = requiredSize;
81 }
82
83 return BUFFER_WRITE(buffer, count, offset, file->inode->private, file->inode->size);
84}
85
88 .write = tmpfs_write,
89 .seek = file_generic_seek,
90};
91
93{
94 MUTEX_SCOPE(&dir->mutex);
95
97 if (inode == NULL)
98 {
99 return ERR;
100 }
101 UNREF_DEFER(inode);
102
103 dentry_make_positive(target, inode);
104 tmpfs_dentry_add(target);
105
106 return 0;
107}
108
109static void tmpfs_truncate(inode_t* inode)
110{
111 MUTEX_SCOPE(&inode->mutex);
112
113 if (inode->private != NULL)
114 {
115 free(inode->private);
116 inode->private = NULL;
117 }
118 inode->size = 0;
119}
120
122{
123 MUTEX_SCOPE(&dir->mutex);
124
126 tmpfs_dentry_add(target);
127
128 return 0;
129}
130
132{
133 MUTEX_SCOPE(&inode->mutex);
134
135 if (inode->private == NULL)
136 {
137 errno = EINVAL;
138 return ERR;
139 }
140
141 uint64_t copySize = MIN(count, inode->size);
142 memcpy(buffer, inode->private, copySize);
143 return copySize;
144}
145
146static uint64_t tmpfs_symlink(inode_t* dir, dentry_t* target, const char* dest)
147{
148 MUTEX_SCOPE(&dir->mutex);
149
150 inode_t* inode = tmpfs_inode_new(dir->superblock, INODE_SYMLINK, (void*)dest, strlen(dest));
151 if (inode == NULL)
152 {
153 return ERR;
154 }
155 UNREF_DEFER(inode);
156
157 dentry_make_positive(target, inode);
158 tmpfs_dentry_add(target);
159
160 return 0;
161}
162
164{
165 MUTEX_SCOPE(&dir->mutex);
166
167 if (target->inode->type == INODE_FILE || target->inode->type == INODE_SYMLINK)
168 {
169 tmpfs_dentry_remove(target);
170 }
171 else if (target->inode->type == INODE_DIR)
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_inode_cleanup(inode_t* inode)
186{
187 if (inode->private != NULL)
188 {
189 free(inode->private);
190 inode->private = NULL;
191 inode->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_inode_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 inode_t* inode = tmpfs_inode_new(superblock, INODE_FILE, in->data, in->size);
232 if (inode == NULL)
233 {
234 panic(NULL, "Failed to create tmpfs file inode");
235 }
236 UNREF_DEFER(inode);
237
238 dentry_make_positive(dentry, inode);
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{
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 inode_t* inode = tmpfs_inode_new(superblock, INODE_DIR, NULL, 0);
255 if (inode == NULL)
256 {
257 panic(NULL, "Failed to create tmpfs inode");
258 }
259 UNREF_DEFER(inode);
260
261 tmpfs_dentry_add(dentry);
262 dentry_make_positive(dentry, inode);
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
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, block_device_t* device, void* private)
280{
281 UNUSED(private);
282
283 superblock_t* superblock = superblock_new(fs, device, &superOps, &dentryOps);
284 if (superblock == NULL)
285 {
286 return NULL;
287 }
288 UNREF_DEFER(superblock);
289
290 superblock->blockSize = 0;
291 superblock->maxFileSize = UINT64_MAX;
292
294 if (data == NULL)
295 {
296 return NULL;
297 }
298 list_init(&data->dentrys);
299 lock_init(&data->lock);
300 superblock->private = data;
301
302 if (!initialized)
303 {
305 const boot_disk_t* disk = &bootInfo->disk;
306
307 dentry_t* root = tmpfs_load_dir(superblock, NULL, NULL, disk->root);
308 if (root == NULL)
309 {
310 return NULL;
311 }
312
313 superblock->root = root;
314 return REF(superblock->root);
315 }
316
317 dentry_t* dentry = dentry_new(superblock, NULL, NULL);
318 if (dentry == NULL)
319 {
320 return NULL;
321 }
322 UNREF_DEFER(dentry);
323
324 inode_t* inode = tmpfs_inode_new(superblock, INODE_DIR, NULL, 0);
325 if (inode == NULL)
326 {
327 return NULL;
328 }
329 UNREF_DEFER(inode);
330
331 tmpfs_dentry_add(dentry);
332 dentry_make_positive(dentry, inode);
333
334 superblock->root = dentry;
335 return REF(superblock->root);
336}
337
338static inode_t* tmpfs_inode_new(superblock_t* superblock, itype_t type, void* buffer, uint64_t size)
339{
340 inode_t* inode = inode_new(superblock, vfs_id_get(), type, &inodeOps, &fileOps);
341 if (inode == NULL)
342 {
343 return NULL;
344 }
345 UNREF_DEFER(inode);
346
347 inode->blocks = 0;
348
349 if (buffer != NULL)
350 {
351 inode->private = malloc(size);
352 if (inode->private == NULL)
353 {
354 return NULL;
355 }
356 memcpy(inode->private, buffer, size);
357 inode->size = size;
358 }
359 else
360 {
361 inode->private = NULL;
362 inode->size = 0;
363 }
364
365 return REF(inode);
366}
367
369 .name = TMPFS_NAME,
370 .mount = tmpfs_mount,
371};
372
373void tmpfs_init(void)
374{
375 LOG_INFO("registering tmpfs\n");
377 {
378 panic(NULL, "Failed to register tmpfs");
379 }
380 LOG_INFO("mounting tmpfs\n");
381
382 process_t* process = sched_process();
383 assert(process != NULL);
384
385 namespace_t* ns = process_get_ns(process);
386 if (ns == NULL)
387 {
388 panic(NULL, "Failed to get process namespace");
389 }
390 UNREF_DEFER(ns);
391
393 if (temp == NULL)
394 {
395 panic(NULL, "Failed to mount tmpfs");
396 }
397 UNREF(temp);
398 LOG_INFO("tmpfs initialized\n");
399
400 initialized = true;
401}
#define assert(expression)
Definition assert.h:29
boot_info_t * bootInfo
Definition boot_info.c:14
int64_t y
Definition main.c:153
static dentry_t * root
Definition devfs.c:25
static fd_t data
Definition dwm.c:21
static dentry_t * dir
Definition fb.c:16
void dentry_make_positive(dentry_t *dentry, inode_t *inode)
Make a dentry positive by associating it with an inode.
Definition dentry.c:277
dentry_t * dentry_new(superblock_t *superblock, dentry_t *parent, const char *name)
Create a new dentry.
Definition dentry.c:116
uint64_t dentry_generic_iterate(dentry_t *dentry, dir_ctx_t *ctx)
Helper function for a basic iterate.
Definition dentry.c:313
void dentry_remove(dentry_t *dentry)
Remove a dentry from the filesystem hierarchy.
Definition dentry.c:176
size_t file_generic_seek(file_t *file, ssize_t offset, seek_origin_t origin)
Helper function for basic seeking.
Definition file.c:69
uint64_t filesystem_register(filesystem_t *fs)
Registers a filesystem.
Definition filesystem.c:232
inode_t * inode_new(superblock_t *superblock, ino_t number, itype_t type, const inode_ops_t *ops, const file_ops_t *fileOps)
Create a new inode.
Definition inode.c:41
mount_t * namespace_mount(namespace_t *ns, path_t *target, filesystem_t *fs, const char *deviceName, mode_t mode, void *private)
Mount a filesystem in a namespace.
Definition namespace.c:357
mode_t
Path flags and permissions.
Definition path.h:78
@ MODE_ALL_PERMS
Definition path.h:95
@ MODE_PROPAGATE
Definition path.h:93
@ MODE_DIRECTORY
Definition path.h:89
superblock_t * superblock_new(filesystem_t *fs, block_device_t *device, 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:373
#define TMPFS_NAME
The name of the tmpfs filesystem.
Definition tmpfs.h:25
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:267
#define LOG_INFO(format,...)
Definition log.h:91
namespace_t * process_get_ns(process_t *process)
Gets the namespace of a process.
Definition process.c:164
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:87
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:184
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:104
#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:69
#define REF(ptr)
Increment reference count.
Definition ref.h:80
#define UNREF(ptr)
Decrement reference count.
Definition ref.h:95
#define BUFFER_WRITE(buffer, count, offset, dest, size)
Helper macro for implementing file operations dealing with simple buffer writes.
Definition vfs.h:224
#define BUFFER_READ(buffer, count, offset, src, size)
Helper macros for implementing file operations dealing with simple buffers.
Definition vfs.h:206
uint64_t vfs_id_get(void)
Generates a new unique ID, to be used for any VFS object.
Definition vfs.c:1277
#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:100
itype_t
Inode type enum.
Definition io.h:341
@ INODE_FILE
Is a file.
Definition io.h:342
@ INODE_DIR
Is a directory.
Definition io.h:343
@ INODE_SYMLINK
Is a symbolic link.
Definition io.h:344
#define LIST_FOR_EACH(elem, list, member)
Iterates over a list.
Definition list.h:60
static void list_push_back(list_t *list, list_entry_t *entry)
Pushes an entry to the end of the list.
Definition list.h:324
static void list_remove(list_t *list, list_entry_t *entry)
Removes a list entry from its current list.
Definition list.h:297
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:214
static void list_init(list_t *list)
Initializes a list.
Definition list.h:185
#define MIN(x, y)
Definition math.h:16
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static uint64_t offset
Definition screen.c:19
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
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
Block device type.
Definition superblock.h:40
boot_dir_t * root
Definition boot_info.h:82
char name[MAX_NAME]
Definition boot_info.h:67
boot_disk_t disk
Definition boot_info.h:104
Dentry operations structure.
Definition dentry.h:121
uint64_t(* iterate)(dentry_t *dentry, dir_ctx_t *ctx)
Iterate over the entries in a directory dentry.
Definition dentry.h:137
Directory entry structure.
Definition dentry.h:153
list_t children
Definition dentry.h:160
inode_t * inode
Will be NULL if the dentry is negative, once positive it will never be modified.
Definition dentry.h:157
char name[MAX_NAME]
Constant after creation.
Definition dentry.h:156
list_entry_t otherEntry
Made available for use by any other subsystems for convenience.
Definition dentry.h:166
superblock_t * superblock
Definition dentry.h:161
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
inode_t * inode
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
Inode operations structure.
Definition inode.h:74
uint64_t(* create)(inode_t *dir, dentry_t *target, mode_t mode)
Handles both directories and files depending on mode.
Definition inode.h:96
Inode structure.
Definition inode.h:49
mutex_t mutex
Definition inode.h:64
size_t blocks
Definition inode.h:55
void * private
Definition inode.h:60
itype_t type
Definition inode.h:52
size_t size
Definition inode.h:54
Mount structure.
Definition mount.h:39
Namespace structure.
Definition namespace.h:57
Process structure.
Definition process.h:72
Superblock operations structure.
Definition superblock.h:75
void(* cleanup)(superblock_t *superblock)
Definition superblock.h:90
Superblock structure.
Definition superblock.h:49
uint64_t blockSize
Definition superblock.h:53
uint64_t maxFileSize
Definition superblock.h:54
dentry_t * root
Root dentry of the filesystem, should not take a reference.
Definition superblock.h:56
void * private
Definition superblock.h:55
Superblock private data for tmpfs.
Definition tmpfs.h:31
static inode_ops_t inodeOps
Definition tmpfs.c:195
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 void tmpfs_inode_cleanup(inode_t *inode)
Definition tmpfs.c:185
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:368
static void tmpfs_dentry_remove(dentry_t *dentry)
Definition tmpfs.c:42
static dentry_t * tmpfs_mount(filesystem_t *fs, block_device_t *device, void *private)
Definition tmpfs.c:279
static uint64_t tmpfs_readlink(inode_t *inode, char *buffer, uint64_t count)
Definition tmpfs.c:131
static uint64_t tmpfs_symlink(inode_t *dir, dentry_t *target, const char *dest)
Definition tmpfs.c:146
static uint64_t tmpfs_remove(inode_t *dir, dentry_t *target)
Definition tmpfs.c:163
static size_t tmpfs_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition tmpfs.c:54
static void tmpfs_truncate(inode_t *inode)
Definition tmpfs.c:109
static void tmpfs_superblock_cleanup(superblock_t *superblock)
Definition tmpfs.c:209
static uint64_t tmpfs_create(inode_t *dir, dentry_t *target, mode_t mode)
Definition tmpfs.c:92
static void tmpfs_dentry_add(dentry_t *dentry)
Definition tmpfs.c:32
static uint64_t tmpfs_link(inode_t *dir, dentry_t *old, dentry_t *target)
Definition tmpfs.c:121
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 inode_t * tmpfs_inode_new(superblock_t *superblock, itype_t type, void *buffer, uint64_t size)
Definition tmpfs.c:338
static file_ops_t fileOps
Definition tmpfs.c:86
static bool initialized
Definition tmpfs.c:28