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