PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
filesystem.c
Go to the documentation of this file.
2
4#include <kernel/fs/cwd.h>
5#include <kernel/fs/dentry.h>
7#include <kernel/fs/key.h>
8#include <kernel/fs/mount.h>
9#include <kernel/fs/path.h>
10#include <kernel/fs/sysfs.h>
11#include <kernel/fs/vfs.h>
12#include <kernel/fs/vnode.h>
13#include <kernel/log/log.h>
14#include <kernel/log/panic.h>
15#include <kernel/mem/vmm.h>
16#include <kernel/proc/process.h>
17#include <kernel/sched/clock.h>
18#include <kernel/sched/sched.h>
19#include <kernel/sched/timer.h>
20#include <kernel/sched/wait.h>
21#include <kernel/sync/mutex.h>
22#include <kernel/sync/rwlock.h>
23#include <kernel/utils/ref.h>
24
25#include <kernel/cpu/regs.h>
26
27#include <errno.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <string.h>
31#include <sys/fs.h>
32#include <sys/list.h>
33
34static dentry_t* dir = NULL;
35
39
40static map_key_t filesystem_key(const char* name)
41{
42 return map_key_string(name);
43}
44
45static size_t superblock_read(file_t* file, void* buffer, size_t count, size_t* offset)
46{
47 superblock_t* sb = file->vnode->data;
48 assert(sb != NULL);
49
50 char info[MAX_PATH];
51 int length = snprintf(info, sizeof(info), "id: %llu\nblock_size: %llu\nmax_file_size: %llu\n", sb->id,
52 sb->blockSize, sb->maxFileSize);
53 if (length < 0)
54 {
55 return 0;
56 }
57
58 return BUFFER_READ(buffer, count, offset, info, (size_t)length);
59}
60
61static void superblock_cleanup(vnode_t* vnode)
62{
63 superblock_t* sb = vnode->data;
64 if (sb == NULL)
65 {
66 return;
67 }
68
69 UNREF(sb);
70 vnode->data = NULL;
71}
72
76
80
82{
83 filesystem_t* fs = dir->data;
84 assert(fs != NULL);
85
86 sbid_t id;
87 if (sscanf(dentry->name, "%llu", &id) != 1)
88 {
89 return 0;
90 }
91
93
94 superblock_t* sb;
95 LIST_FOR_EACH(sb, &fs->superblocks, entry)
96 {
97 if (sb->id != id)
98 {
99 continue;
100 }
101
102 vnode_t* vnode = vnode_new(dentry->superblock, VREG, NULL, &sbFileOps);
103 if (vnode == NULL)
104 {
105 return ERR;
106 }
107 vnode->data = REF(sb);
108 dentry_make_positive(dentry, vnode);
109 return 0;
110 }
111
112 return 0;
113}
114
116{
117 if (!dentry_iterate_dots(dentry, ctx))
118 {
119 return 0;
120 }
121
122 filesystem_t* fs = dentry->vnode->data;
123 assert(fs != NULL);
124
126
127 superblock_t* sb;
128 LIST_FOR_EACH(sb, &fs->superblocks, entry)
129 {
130 if (ctx->index++ < ctx->pos)
131 {
132 continue;
133 }
134
135 char name[MAX_NAME];
136 snprintf(name, MAX_NAME, "%llu", sb->id);
137
138 if (!ctx->emit(ctx, name, VREG))
139 {
140 return 0;
141 }
142 }
143
144 return 0;
145}
146
150
154
156{
157 UNUSED(dir);
158
160
161 map_key_t key = filesystem_key(dentry->name);
162 filesystem_t* fs = CONTAINER_OF_SAFE(map_get(&fsMap, &key), filesystem_t, mapEntry);
163 if (fs == NULL)
164 {
165 return 0;
166 }
167
168 vnode_t* vnode = vnode_new(dentry->superblock, VDIR, &fsVnodeOps, NULL);
169 if (vnode == NULL)
170 {
171 return ERR;
172 }
173 UNREF_DEFER(vnode);
174 vnode->data = fs;
175
176 dentry->ops = &fsDentryOps;
177 dentry_make_positive(dentry, vnode);
178 return 0;
179}
180
182{
183 if (!dentry_iterate_dots(dentry, ctx))
184 {
185 return 0;
186 }
187
189
190 filesystem_t* fs;
191 LIST_FOR_EACH(fs, &filesystems, entry)
192 {
193 if (ctx->index++ < ctx->pos)
194 {
195 continue;
196 }
197
198 if (!ctx->emit(ctx, fs->name, VDIR))
199 {
200 return 0;
201 }
202 }
203
204 return 0;
205}
206
210
214
216{
218
219 if (dir != NULL)
220 {
221 LOG_ERR("filesystem already exposed\n");
222 return;
223 }
224
226 if (dir == NULL)
227 {
228 panic(NULL, "failed to expose filesystem sysfs directory");
229 }
230 dir->ops = &dirDentryOps;
231}
232
234{
235 if (fs == NULL || strnlen_s(fs->name, MAX_NAME) > MAX_NAME)
236 {
237 errno = EINVAL;
238 return ERR;
239 }
240
244 rwlock_init(&fs->lock);
245
246 map_key_t key = filesystem_key(fs->name);
247
249
250 if (map_insert(&fsMap, &key, &fs->mapEntry) == ERR)
251 {
252 return ERR;
253 }
255
256 return 0;
257}
258
260{
261 if (fs == NULL)
262 {
263 return;
264 }
265
267 map_remove(&fsMap, &fs->mapEntry);
268 list_remove(&fs->entry);
269
270 while (!list_is_empty(&fs->superblocks))
271 {
273 }
274}
275
277{
279
280 map_key_t key = filesystem_key(name);
281 return CONTAINER_OF_SAFE(map_get(&fsMap, &key), filesystem_t, mapEntry);
282}
283
285{
286 if (path == NULL || process == NULL)
287 {
288 return NULL;
289 }
290
291 pathname_t pathname;
292 if (pathname_init(&pathname, path) == ERR)
293 {
294 return NULL;
295 }
296
297 namespace_t* ns = process_get_ns(process);
298 if (ns == NULL)
299 {
300 return NULL;
301 }
302 UNREF_DEFER(ns);
303
304 path_t target = cwd_get(&process->cwd, ns);
305 PATH_DEFER(&target);
306
307 if (path_walk(&target, &pathname, ns) == ERR)
308 {
309 return NULL;
310 }
311
312 if (!DENTRY_IS_POSITIVE(target.dentry))
313 {
314 errno = ENOENT;
315 return NULL;
316 }
317
318 if (target.dentry->ops != &fsDentryOps)
319 {
320 errno = EINVAL;
321 return NULL;
322 }
323
324 return target.dentry->vnode->data;
325}
326
327bool options_next(const char** iter, char* buffer, size_t size, char** key, char** value)
328{
329 while (*iter != NULL && **iter != '\0')
330 {
331 const char* start = *iter;
332 const char* end = strchr(start, ',');
333 size_t len = end != NULL ? (size_t)(end - start) : strlen(start);
334
335 *iter = end != NULL ? end + 1 : NULL;
336
337 if (len == 0)
338 {
339 continue;
340 }
341 if (len >= size)
342 {
343 continue;
344 }
345
346 memcpy(buffer, start, len);
347 buffer[len] = '\0';
348
349 *key = buffer;
350 *value = strchr(*key, '=');
351
352 if (*value != NULL)
353 {
354 *(*value)++ = '\0';
355 return true;
356 }
357 }
358
359 return false;
360}
#define MAX_NAME
Maximum length of names.
Definition MAX_NAME.h:11
#define MAX_PATH
Maximum length of filepaths.
Definition MAX_PATH.h:11
#define assert(expression)
Definition assert.h:29
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
static void start()
Definition main.c:542
static char * id
Definition dwm.c:20
static list_t filesystems
Definition filesystem.c:37
static dentry_t * dir
Definition filesystem.c:34
static rwlock_t lock
Definition filesystem.c:38
static file_ops_t sbFileOps
Definition filesystem.c:73
static size_t superblock_read(file_t *file, void *buffer, size_t count, size_t *offset)
Definition filesystem.c:45
static uint64_t filesystem_iterate(dentry_t *dentry, dir_ctx_t *ctx)
Definition filesystem.c:115
static uint64_t filesystem_dir_lookup(vnode_t *dir, dentry_t *dentry)
Definition filesystem.c:155
static vnode_ops_t sbVnodeOps
Definition filesystem.c:77
static void superblock_cleanup(vnode_t *vnode)
Definition filesystem.c:61
static map_key_t filesystem_key(const char *name)
Definition filesystem.c:40
static dentry_ops_t dirDentryOps
Definition filesystem.c:211
static uint64_t filesystem_dir_iterate(dentry_t *dentry, dir_ctx_t *ctx)
Definition filesystem.c:181
static vnode_ops_t fsVnodeOps
Definition filesystem.c:147
static dentry_ops_t fsDentryOps
Definition filesystem.c:151
static vnode_ops_t dirVnodeOps
Definition filesystem.c:207
static map_t fsMap
Definition filesystem.c:36
static uint64_t filesystem_lookup(vnode_t *dir, dentry_t *dentry)
Definition filesystem.c:81
path_t cwd_get(cwd_t *cwd, namespace_t *ns)
Get the current working directory.
Definition cwd.c:19
void dentry_make_positive(dentry_t *dentry, vnode_t *vnode)
Make a dentry positive by associating it with an vnode.
Definition dentry.c:289
bool dentry_iterate_dots(dentry_t *dentry, dir_ctx_t *ctx)
Helper function to iterate over the special entries "." and "..".
Definition dentry.c:304
#define DENTRY_IS_POSITIVE(dentry)
Check if a dentry is positive.
Definition dentry.h:67
void filesystem_expose(void)
Exposes the sysfs fs directory.
Definition filesystem.c:215
filesystem_t * filesystem_get_by_path(const char *path, process_t *process)
Gets a filesystem by path.
Definition filesystem.c:284
uint64_t filesystem_register(filesystem_t *fs)
Registers a filesystem.
Definition filesystem.c:233
bool options_next(const char **iter, char *buffer, size_t size, char **key, char **value)
Helper function for iterating over options passed to a filesystem mount operation.
Definition filesystem.c:327
filesystem_t * filesystem_get_by_name(const char *name)
Gets a filesystem by name.
Definition filesystem.c:276
void filesystem_unregister(filesystem_t *fs)
Unregisters a filesystem.
Definition filesystem.c:259
#define PATH_DEFER(path)
Defer path put.
Definition path.h:106
uint64_t path_walk(path_t *path, const pathname_t *pathname, namespace_t *ns)
Walk a pathname to a path.
Definition path.c:593
uint64_t pathname_init(pathname_t *pathname, const char *string)
Initialize a pathname.
Definition path.c:116
dentry_t * sysfs_dir_new(dentry_t *parent, const char *name, const vnode_ops_t *vnodeOps, void *data)
Create a new directory inside a mounted sysfs instance.
Definition sysfs.c:114
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
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_ERR(format,...)
Definition log.h:93
namespace_t * process_get_ns(process_t *process)
Gets the namespace of a process.
Definition process.c:206
static void rwlock_init(rwlock_t *lock)
Initializes a rwlock.
Definition rwlock.h:79
#define RWLOCK_READ_SCOPE(lock)
Acquires a rwlock for reading for the reminder of the current scope.
Definition rwlock.h:34
#define RWLOCK_CREATE()
Create a rwlock initializer.
Definition rwlock.h:52
#define RWLOCK_WRITE_SCOPE(lock)
Acquires a rwlock for writing for the reminder of the current scope.
Definition rwlock.h:43
void map_entry_init(map_entry_t *entry)
Initialize a map entry.
Definition map.c:37
uint64_t map_insert(map_t *map, const map_key_t *key, map_entry_t *value)
Insert a key-value pair into the map.
Definition map.c:170
void map_remove(map_t *map, map_entry_t *entry)
Remove a entry from the map.
Definition map.c:319
map_entry_t * map_get(map_t *map, const map_key_t *key)
Get a value from the map by key.
Definition map.c:253
static map_key_t map_key_string(const char *str)
Create a map key from a string.
Definition map.h:144
#define MAP_CREATE()
Create a map initializer.
Definition map.h:161
#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_READ(buffer, count, offset, src, size)
Helper macros for implementing file operations dealing with simple buffers.
Definition vfs.h:209
#define ENOENT
No such file or directory.
Definition errno.h:42
#define EINVAL
Invalid argument.
Definition errno.h:142
#define errno
Error number variable.
Definition errno.h:27
#define UNUSED(x)
Mark a variable as unused.
Definition defs.h:96
uint64_t sbid_t
A suberblock identifier that uniquely identifies a superblock within the system.
Definition fs.h:353
@ 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
#define LIST_CREATE(name)
Creates a list initializer.
Definition list.h:163
static bool list_is_empty(list_t *list)
Checks if a list is empty.
Definition list.h:210
static void list_entry_init(list_entry_t *entry)
Initializes a list entry.
Definition list.h:173
static list_entry_t * list_pop_front(list_t *list)
Pops the first entry from the list.
Definition list.h:366
static void list_init(list_t *list)
Initializes a list.
Definition list.h:185
#define NULL
Pointer error value.
Definition NULL.h:25
#define ERR
Integer error value.
Definition ERR.h:17
#define CONTAINER_OF_SAFE(ptr, type, member)
Safe container of macro.
static uint64_t offset
Definition screen.c:19
static atomic_long count
Definition main.c:11
__SIZE_TYPE__ size_t
Definition size_t.h:4
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC int sscanf(const char *_RESTRICT s, const char *_RESTRICT format,...)
Definition sscanf.c:4
_PUBLIC int snprintf(char *_RESTRICT s, size_t n, const char *_RESTRICT format,...)
Definition snprintf.c:3
_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 char * strchr(const char *s, int c)
Definition strchr.c:3
size_t strnlen_s(const char *s, size_t maxsize)
Definition strnlen_s.c:4
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
char name[MAX_NAME]
The name of the dentry, immutable after creation.
Definition dentry.h:158
const dentry_ops_t * ops
Definition dentry.h:164
void * data
Definition dentry.h:165
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
Directory context used to iterate over directory entries.
Definition dentry.h:97
size_t index
An index that the filesystem can use for its own purposes.
Definition dentry.h:114
size_t pos
The current position in the directory, can be used to skip entries.
Definition dentry.h:112
bool(* emit)(dir_ctx_t *ctx, const char *name, vtype_t type)
Emit function.
Definition dentry.h:111
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
list_entry_t entry
Used internally.
Definition filesystem.h:54
const char * name
Definition filesystem.h:58
map_entry_t mapEntry
Used internally.
Definition filesystem.h:55
rwlock_t lock
Used internally.
Definition filesystem.h:57
list_t superblocks
Used internally.
Definition filesystem.h:56
A doubly linked list.
Definition list.h:46
Map key stucture.
Definition map.h:57
Hash map structure.
Definition map.h:90
Namespace structure.
Definition namespace.h:57
Path structure.
Definition path.h:127
dentry_t * dentry
Definition path.h:129
Pathname structure.
Definition path.h:139
Process structure.
Definition process.h:76
cwd_t cwd
Definition process.h:87
Read-Write Ticket Lock structure.
Definition rwlock.h:66
Superblock structure.
Definition superblock.h:33
uint64_t blockSize
Definition superblock.h:37
uint64_t maxFileSize
Definition superblock.h:38
vnode operations structure.
Definition vnode.h:69
void(* cleanup)(vnode_t *vnode)
Cleanup function called when the vnode is being freed.
Definition vnode.h:138
uint64_t(* lookup)(vnode_t *dir, dentry_t *target)
Look up a dentry in a directory vnode.
Definition vnode.h:80
vnode structure.
Definition vnode.h:48
void * data
Filesystem defined data.
Definition vnode.h:52