1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "mos/filesystem/vfs_utils.h" |
4 | |
5 | #include "mos/filesystem/dentry.h" |
6 | #include "mos/filesystem/page_cache.h" |
7 | #include "mos/filesystem/vfs_types.h" |
8 | #include "mos/lib/sync/spinlock.h" |
9 | #include "mos/mm/physical/pmm.h" |
10 | #include "mos/mm/slab.h" |
11 | #include "mos/mm/slab_autoinit.h" |
12 | |
13 | #include <mos/lib/structures/hashmap_common.h> |
14 | #include <mos/types.h> |
15 | #include <mos_stdlib.h> |
16 | #include <mos_string.h> |
17 | |
18 | slab_t *dentry_cache; |
19 | SLAB_AUTOINIT("dentry" , dentry_cache, dentry_t); |
20 | |
21 | static dentry_t *dentry_create(superblock_t *sb, dentry_t *parent, const char *name) |
22 | { |
23 | dentry_t *dentry = kmalloc(dentry_cache); |
24 | dentry->superblock = sb; |
25 | tree_node_init(tree_node(dentry)); |
26 | |
27 | if (name) |
28 | dentry->name = strdup(src: name); |
29 | |
30 | if (parent) |
31 | { |
32 | MOS_ASSERT(spinlock_is_locked(&parent->lock)); |
33 | tree_add_child(tree_node(parent), tree_node(dentry)); |
34 | dentry->superblock = parent->superblock; |
35 | } |
36 | |
37 | return dentry; |
38 | } |
39 | |
40 | dentry_t *dentry_get_from_parent(superblock_t *sb, dentry_t *parent, const char *name) |
41 | { |
42 | if (!parent) |
43 | return dentry_create(sb, NULL, name); |
44 | |
45 | dentry_t *dentry = NULL; |
46 | |
47 | spinlock_acquire(&parent->lock); |
48 | tree_foreach_child(dentry_t, child, parent) |
49 | { |
50 | if (strcmp(str1: child->name, str2: name) == 0) |
51 | { |
52 | dentry = child; |
53 | break; |
54 | } |
55 | } |
56 | |
57 | // if not found, create a new one |
58 | if (!dentry) |
59 | dentry = dentry_create(sb, parent, name); |
60 | |
61 | spinlock_release(&parent->lock); |
62 | return dentry; |
63 | } |
64 | |
65 | bool simple_page_write_begin(inode_cache_t *icache, off_t offset, size_t size, phyframe_t **page, void **private) |
66 | { |
67 | MOS_UNUSED(size); |
68 | *page = pagecache_get_page_for_write(cache: icache, pgoff: offset / MOS_PAGE_SIZE); |
69 | if (!*page) |
70 | return false; |
71 | |
72 | *private = NULL; |
73 | return true; |
74 | } |
75 | |
76 | void simple_page_write_end(inode_cache_t *icache, off_t offset, size_t size, phyframe_t *page, void *private) |
77 | { |
78 | MOS_UNUSED(page); |
79 | MOS_UNUSED(private); |
80 | |
81 | // also update the inode's size |
82 | if (offset + size > icache->owner->size) |
83 | icache->owner->size = offset + size; |
84 | } |
85 | |
86 | long simple_flush_page_discard_data(inode_cache_t *icache, off_t pgoff, phyframe_t *page) |
87 | { |
88 | MOS_UNUSED(icache); |
89 | MOS_UNUSED(pgoff); |
90 | MOS_UNUSED(page); |
91 | return 0; |
92 | } |
93 | |
94 | // read from the page cache, the size and offset are already validated to be in the file's bounds |
95 | ssize_t vfs_generic_read(const file_t *file, void *buf, size_t size, off_t offset) |
96 | { |
97 | // cap the read size to the file's size |
98 | size = MIN(size, file->dentry->inode->size - offset); |
99 | inode_cache_t *icache = &file->dentry->inode->cache; |
100 | const ssize_t read = vfs_read_pagecache(icache, buf, size, offset); |
101 | return read; |
102 | } |
103 | |
104 | // write to the page cache, the size and offset are already validated to be in the file's bounds |
105 | ssize_t vfs_generic_write(const file_t *file, const void *buf, size_t size, off_t offset) |
106 | { |
107 | inode_cache_t *icache = &file->dentry->inode->cache; |
108 | const ssize_t written = vfs_write_pagecache(icache, buf, total_size: size, offset); |
109 | return written; |
110 | } |
111 | |
112 | bool vfs_simple_write_begin(inode_cache_t *icache, off_t offset, size_t size) |
113 | { |
114 | MOS_UNUSED(icache); |
115 | MOS_UNUSED(offset); |
116 | MOS_UNUSED(size); |
117 | return true; |
118 | } |
119 | |
120 | void vfs_generic_iterate_dir(const dentry_t *dir, vfs_listdir_state_t *state, dentry_iterator_op add_record) |
121 | { |
122 | dentry_t *d_parent = dentry_parent(dentry: dir); |
123 | if (d_parent == NULL) |
124 | d_parent = root_dentry; |
125 | |
126 | MOS_ASSERT(d_parent->inode != NULL); |
127 | MOS_ASSERT(dir->inode); |
128 | |
129 | add_record(state, dir->inode->ino, "." , 1, FILE_TYPE_DIRECTORY); |
130 | add_record(state, d_parent->inode->ino, ".." , 2, FILE_TYPE_DIRECTORY); |
131 | |
132 | tree_foreach_child(dentry_t, child, dir) |
133 | { |
134 | if (child->inode) |
135 | add_record(state, child->inode->ino, child->name, strlen(str: child->name), child->inode->type); |
136 | } |
137 | } |
138 | |