Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
vfs.c
Go to the documentation of this file.
1#include "console/console.h"
2#include "init/init.h"
4#include "libk/debug/debug.h"
5#include "libk/fs/iso9660.h"
6#include "libk/serial.h"
7#include "llist.h"
8#include "memory/slab.h"
9#include "notify.h"
10#include "str.h"
11#include "vfs/vnode.h"
12#include <string.h>
13#include <type.h>
14#include <vector.h>
15#include <vfs/dentry.h>
16#include <vfs/dev.h>
17#include <vfs/enum.h>
18#include <vfs/filesystem.h>
19#include <vfs/mount.h>
20#include <vfs/vfs.h>
21#include <vfs/vnode.h>
22
23#define RBT_TYPE vnode_t
24#define RBT_ID_NAME id
25#include <libk/tree/rbt.h>
26
27// definition
28#define VFS_DEBUG 1
29#define PATH_MAX 4096
30#define NAME_MAX 255
31#define VFS_MAX_FS 512
32#define VFS_MAX_PATH_CACHE 512
33#define CALC_PATH_HASH_LEN(path, curr_depth) \
34 4096 + 1024 * pow(strlen(path), curr_depth)
35
36// internal use
37static rbt_node* NIL;
40static void vfs_event_handler(uint32_t event, void* data, void* ctx);
41
43 vnode_t* vnode = create_vnode();
44
46 memset(node, 0, sizeof(rbt_node));
48
49 return vnode;
50}
51
52INIT(Vfs) {
53 vxCreateSlabCache(&rbt_node_cache, "rbt_node", sizeof(rbt_node), 64, 0);
54
56 memset(NIL, 0, sizeof(rbt_node));
57 NIL->data = create_vnode();
58 NIL->left = NIL->right = NIL->parent = NIL;
59 vfs_tree = NIL;
60
61 // create root inode
62 auto root_inode = create_and_attach_vnode();
63 root_inode->permission = 660;
64 root_inode->type = VNODE_TYPE_DIR;
65
66 // create root dentry
67 {
68 auto entry = create_dentry(str("/"), root_inode, 0);
69 vxSetDentryAsRoot(entry);
70 }
71
72 // register fs
73 {
74 auto iso_fs = (struct fs_data){
75 .magic =
76 {
77 .magic = {'C', 'D', '0', '0', '1'},
78 .count = 5,
79 },
80 .ops = iso9660_fs_operations(),
81 };
82 create_filesystem("ISO9660", &iso_fs);
83 }
84
85 // create notify
86 notify_dev_create(str("/vfs/block"));
87 notify_dev_create(str("/vfs/root"));
88
89 // handle block notify
90 {
91 auto n = (struct notifier*)kalloc(sizeof(struct notifier));
92 memset(n, 0, sizeof(struct notifier));
93 n->callback = vfs_event_handler;
94 n->context = 0;
95 n->priority = NOTIFY_HIGHT;
96 n->flags = 0;
97
98 notify_register("/vfs/block", n);
99 }
100
101 LOG_INFO("vfs", "vfs has been installed");
102}
103
104// TODO: auto detect filesystem
105KERNEL_API int vfs_mount(dentry_ptr dev_dentry, char* fs, dentry_ptr dentry,
106 int flags) {
107 if (!fs || !dev_dentry || !dentry)
108 return VFS_ERR;
109
110 UNUSED(flags);
111
112 auto fs_ = retrieve_filesystem(fs);
113 if (!fs_) {
114 LOG2_WARN("VFS", "vfs_mount: fs %s not found", fs);
115 return VFS_ERR;
116 }
117
118 if (!fs_->data.ops) {
119 LOG2_WARN("VFS", "vfs_mount: fs %s ops not found", fs);
120 return VFS_ERR;
121 }
122
123 auto dev_vnode = dev_dentry->vnode;
124 if (!dev_vnode) {
125 LOG2_WARN("VFS", "vfs_mount_dev: dev vnode not found");
126 return VFS_ERR;
127 }
128
129 if (dev_vnode->type != VNODE_TYPE_BLK) {
130 LOG2_WARN("VFS", "vfs_mount: dev not a block device");
131 return VFS_ERR;
132 }
133
134 auto cdev =
135 retrieve_dev(dev_vnode->device.major, dev_vnode->device.minor);
136
137 if (!cdev) {
138 LOG2_WARN("VFS", "vfs_mount_dev: cdev not found");
139 return VFS_ERR;
140 }
141 LOG_DEBUG("VFS", "vfs_mount_dev: cdev minor %d major %d", cdev->minor,
142 cdev->major);
143
144 vnode_ptr_t dentry_node = dentry->vnode;
145 if (!dentry_node) {
146 LOG2_INFO("VFS",
147 "vfs_mount: created vnode for mount point dentry");
148 dentry_node = create_vnode();
149 dentry->vnode = dentry_node;
150 }
151
152 // TODO: validate filesystem magic
153 dentry_node->type = VNODE_TYPE_DIR;
154 dentry_node->mountedhere = cdev;
155 dev_vnode->mount = cdev;
156
157 struct fs_instance* fs_ins =
158 (struct fs_instance*)kalloc(sizeof(struct fs_instance));
159 fs_ins->fs = fs_;
160 fs_ins->block_dentry = dev_dentry;
161 fs_ins->cdev = cdev;
162
163 dentry_node->fs_instance = fs_ins;
164
165 // first lookup on filesystem
166 fs_->data.ops->lookup(fs_ins, 0, 0, &dentry);
167
168 dentry_get(dev_dentry);
169
170 KDEBUG(DEBUG_LEVEL_OK, "mounted %d:%d on %s with filesystem %s\n",
171 cdev->major, cdev->minor, dentry->name->c_str, fs_->name);
172 return VFS_OK;
173}
174
176 if (!dentry)
177 return VFS_OK;
178
179 auto ch = dentry->child_list.next;
180 while (ch != &dentry->child_list) {
181 auto next = ch->next; // simpan next sebelum child dilepas
182 dentry_t* child = container_of(ch, dentry_t, siblings);
183
184 int ret = vfs_umount_recursive(child);
185 if (ret != VFS_OK)
186 return ret;
187
188 ch = next;
189 }
190
191 if (get_reffcount(dentry) > 1) {
192 LOG2_WARN("VFS", "umount: dentry '%s' (%d) still in use",
193 dentry->name ? dentry->name->c_str : "?",
195 return VFS_ERR_BUSY;
196 }
197
198 // TODO: handle later
199 // auto vnode = dentry->vnode;
200 // if (vnode) {
201 // auto fs_instance = vnode->fs_instance;
202 // if (fs_instance && fs_instance->fs &&
203 // fs_instance->fs->data.ops->umount) {
204 // fs_instance->fs->data.ops->umount(fs_instance);
205 // }
206 // }
207
208 llist_del(&dentry->siblings);
209
210 auto root_cache = get_root_cache();
211 cache_remove(root_cache, dentry);
212
214 return VFS_OK;
215}
216
218 if (!dentry)
219 return VFS_ERR;
220
221 auto vnode = dentry->vnode;
222 if (!vnode)
223 return VFS_ERR;
224
225 if (vnode->type == VNODE_TYPE_DIR) {
226 LOG2_DEBUG("Umount", "%s is directory", dentry->name->c_str);
227 auto cdev = vnode->mountedhere;
228 if (!cdev) {
229 LOG2_WARN("Unmount", "no mounted here");
230 return VFS_ERR;
231 }
232 LOG2_DEBUG("Umount", "mounted here %d:%d", cdev->major,
233 cdev->minor);
236
237 } else if (vnode->type == VNODE_TYPE_BLK) {
238 LOG2_DEBUG("Umount", "%s is block", dentry->name->c_str);
239 vnode->mount = 0;
240
241 } else {
242 LOG2_WARN("Umount", "%s is unknown", dentry->name->c_str);
243 return VFS_ERR;
244 }
245
246 KDEBUG(DEBUG_LEVEL_OK, "mounted %s\n", dentry->name->c_str);
247
249 auto ok = vfs_umount_recursive(dentry);
250 if (ok != VFS_OK)
252 return ok;
253}
254
255__attribute__((unused)) static void
256detect_cd_filesystem(dentry_ptr dentry, void* data, void* ctx) {
257 UNUSED(data);
258 UNUSED(ctx);
259
260 auto vnode = dentry->vnode;
261 if (!vnode)
262 return;
263
264 auto ops = (vops_blk_t*)vnode->ops;
265 if (!ops || !ops->read)
266 return;
267
268 auto request_size = sizeof(struct iso9660_pvd);
269 uint8_t* d_ = (uint8_t*)kalloc(request_size);
270 if (!d_)
271 return;
272
273 memset(d_, 0, request_size);
274
276
277 if (!cdev) {
278 serial2_printf("cdev not found\n");
279 kfree2(d_);
280 return;
281 }
282
283 // ISO9660 PVD is always at byte sector 16
284 int ret = ops->read(vnode, 16, d_, request_size);
285
286 if (ret < 0) {
287 serial2_printf("read failed: %d\n", ret);
288 kfree2(d_);
289 return;
290 }
291
292 struct iso9660_pvd* pvd = (struct iso9660_pvd*)(void*)d_;
293 if (strncmp(pvd->id, "CD001", 5) == 0) {
294 LOG2_INFO("VFS NOTIFY", "terdeteksi ISO9660 CD-ROM");
295
296 // trying to mount
297 boolean_t is_contain_root = false;
298 {
299 dentry_ptr mount_entry;
300 vxnamei("/tmp/root", &mount_entry);
301 vfs_mount(dentry, "ISO9660", mount_entry, 0);
302
303 dentry_ptr out;
304 if (resolve_dentry("/kernel.elf", mount_entry, &out,
305 0) == VFS_OK) {
306
307 auto full_path =
309 LOG2_INFO("VFS NOTIFY",
310 "found root filesystem at %s",
311 full_path->c_str);
312 str_release(full_path);
313
314 is_contain_root = true;
315 }
316
317 dentry_put(out);
318 vfs_umount(mount_entry);
319
320 // TODO: delete temp directory
321 }
322
323 // remount again on /root
324 if (is_contain_root) {
325 dentry_ptr mount_entry;
326 vxnamei("/", &mount_entry);
327 vfs_mount(dentry, "ISO9660", mount_entry, 0);
329 }
330 }
331 kfree2(d_);
332}
333
334__attribute__((unused)) static void vfs_notify_probe_handler(void* data,
335 void* ctx) {
336
337 UNUSED(ctx);
338
339 if (!data)
340 return;
341
343
344 if (!dentry->vnode)
345 return;
346
347 auto ops = (vops_blk_t*)dentry->vnode->ops;
348
349 if (ops == 0)
350 return;
351
352 auto dev_major = dentry->vnode->device.major;
353
354 serial2_printf("vnode major %d %x vdata %x\n", dev_major, ops,
355 ops->v_data);
356
357 if (dev_major == DEV_MAJOR_CDROM) {
358 detect_cd_filesystem(dentry, data, ctx);
359 }
360}
361
362static void vfs_event_handler(uint32_t event, void* data, void* ctx) {
363 UNUSED(data);
364 UNUSED(ctx);
365 UNUSED(event);
366
367 switch (event) {
368 case VFS_NOTIFY_PROBE:
369 vfs_notify_probe_handler(data, ctx);
370 break;
371
372 default:
373 break;
374 }
375
376 LOG2_DEBUG("VFS NOTIFY", "new event detected (%d)", event);
377 KDEBUG(DEBUG_LEVEL_OK, "vfs notify received\n");
378}
379
380#undef RBT_ID_NAME
381#undef RBT_TYPE
struct vfs_cache * get_root_cache()
void cache_remove(struct vfs_cache *cache, struct dentry *dentry)
Definition cache.c:116
@ DEBUG_LEVEL_OK
Definition debug.h:11
#define KDEBUG(...)
Definition debug.h:16
int get_reffcount(dentry_ptr dentry)
Definition dentry.c:352
void dentry_get(dentry_ptr dentry)
Definition dentry.c:68
struct dentry * dentry_ptr
Definition dentry.h:20
void dentry_put(dentry_ptr dentry)
Definition dentry.c:72
void vxSetDentryAsRoot(dentry_ptr dentry)
Definition dentry.c:84
int resolve_dentry(char *path, dentry_ptr parent, dentry_ptr *out, uint8_t flag)
Resolves a path to a directory entry (dentry) with configurable start point and strictness.
kstring get_full_path_from_dentry(dentry_ptr dentry)
Definition dentry.c:356
struct vnode * vnode_ptr_t
Definition dentry.h:115
int vxnamei(const char *path, dentry_ptr *out)
Resolves a file path to a directory entry (dentry).
struct dentry dentry_t
Definition dentry.h:19
#define DEV_MAJOR_CDROM
Definition dev.h:40
struct cdev * next
Definition dev.h:4
cdev_ptr_t retrieve_dev(uint32_t major, uint32_t minor)
void * ops
Definition dev.h:2
volatile uint32_t ch
Definition ehci.hpp:1
@ VFS_ERR
Definition enum.h:8
@ VFS_OK
Definition enum.h:5
@ VFS_ERR_BUSY
Definition enum.h:6
int create_filesystem(char name[16], struct fs_data *fs_data)
Definition filesystem.c:7
struct vnode vnode_t
Definition filesystem.h:10
filesystem_ptr_t retrieve_filesystem(const char name[16])
struct fs_data data
Definition filesystem.h:1
uint16_t flags
Definition thread.h:5
typedef __attribute__
Definition msi.c:47
#define INIT(fn)
Definition init.h:26
void serial2_printf(const char *fmt,...)
fs_operations_t * iso9660_fs_operations(void)
Definition iso9660.c:437
void * kalloc(size_t size)
void kfree2(void *ptr)
static void llist_del(struct llist_head *entry)
Definition llist.h:42
void notify_dev_create(kstring name)
Definition notify.c:41
int notify_call(char *name, uint32_t event, void *data)
Definition notify.c:110
#define NOTIFY_HIGHT
Definition notify.h:22
int notify_register(char *name, struct notifier *n)
Definition notify.c:78
static int rbt_insert_node(rbt_node **root, rbt_node *z, struct __rbt_type *data, rbt_node *NIL)
Definition rbt.h:123
#define LOG2_WARN(mod, fmt,...)
Definition serial.h:40
#define LOG2_DEBUG(mod, fmt,...)
Definition serial.h:35
#define LOG_INFO(mod, fmt,...)
Definition serial.h:20
#define LOG2_INFO(mod, fmt,...)
Definition serial.h:33
#define LOG_DEBUG(mod, fmt,...)
Definition serial.h:22
void * vxSlabAlloc(struct slab_cache *cache)
Definition slab.c:93
void vxCreateSlabCache(struct slab_cache **cache, const char *name, const size_t obj_size, size_t alignment, const uintptr_t virt_addr)
Definition slab.c:44
int strncmp(const char *s1, const char *s2, size_t n)
void memset(void *ptr, int value, size_t num)
void str_release(kstring str)
kstring str(const char *str)
int counter
Definition type.h:80
Definition dev.h:63
uint32_t major
Definition dev.h:64
uint32_t minor
Definition dev.h:65
kstring name
Definition dentry.h:32
struct vnode * vnode
Definition dentry.h:33
atomic_t refcount
Definition dentry.h:29
struct llist_head child_list
Definition dentry.h:27
uint32_t major
Definition vnode.h:55
uint32_t minor
Definition vnode.h:56
dentry_ptr block_dentry
Definition filesystem.h:39
cdev_ptr_t cdev
Definition filesystem.h:40
filesystem_ptr_t fs
Definition filesystem.h:41
char id[5]
Definition iso9660.h:21
char * c_str
Definition string.h:12
struct llist_head * next
Definition llist.h:11
Definition rbt.h:26
Definition vnode.h:59
struct device_id device
Definition vnode.h:73
void * ops
Definition vnode.h:64
uint8_t type
Definition vnode.h:62
struct fs_instance * fs_instance
Definition vnode.h:67
cdev_ptr_t mount
Definition vnode.h:69
cdev_ptr_t mountedhere
Definition vnode.h:68
unsigned int uint32_t
Definition type.h:19
#define KERNEL_API
Definition type.h:93
uint8_t boolean_t
Definition type.h:89
#define UNUSED(x)
Definition type.h:100
unsigned char uint8_t
Definition type.h:7
#define container_of(ptr, type, member)
Definition type.h:108
static rbt_node * vfs_tree
Definition vfs.c:38
int vfs_umount(dentry_ptr dentry)
Definition vfs.c:217
static int vfs_umount_recursive(dentry_t *dentry)
Definition vfs.c:175
static void vfs_event_handler(uint32_t event, void *data, void *ctx)
Definition vfs.c:362
static rbt_node * NIL
Definition vfs.c:37
vnode_t * create_and_attach_vnode()
@ VFS_NOTIFY_PROBE
Definition vfs.h:13
@ VFS_NOTIFY_ROOT_FOUND
Definition vfs.h:17
int vfs_mount(dentry_ptr dev_dentry, char *fs, dentry_ptr dentry, int flags)
static struct slab_cache * rbt_node_cache
Definition vm_manager.c:25
@ VNODE_TYPE_DIR
Definition vnode.h:13
@ VNODE_TYPE_BLK
Definition vnode.h:16
struct vops_blk vops_blk_t