feat: lru eviction policy on page caches
[lunaix-os.git] / lunaix-os / kernel / fs / twifs / twifs.c
1 /**
2  * @file twifs.c
3  * @author Lunaixsky (zelong56@gmail.com)
4  * @brief TwiFS - A pseudo file system for kernel state exposure.
5  * @version 0.1
6  * @date 2022-07-21
7  *
8  * @copyright Copyright (c) 2022
9  *
10  */
11 #include <klibc/string.h>
12 #include <lunaix/clock.h>
13 #include <lunaix/fs.h>
14 #include <lunaix/fs/twifs.h>
15 #include <lunaix/mm/cake.h>
16 #include <lunaix/mm/valloc.h>
17
18 static struct twifs_node* fs_root;
19
20 static struct cake_pile* twi_pile;
21
22 int
23 __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode);
24
25 int
26 __twifs_openfile(struct v_inode* inode, struct v_file* file);
27
28 struct twifs_node*
29 __twifs_get_node(struct twifs_node* parent, struct hstr* name);
30
31 struct v_inode*
32 __twifs_create_inode(struct twifs_node* twi_node);
33
34 int
35 __twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx);
36
37 int
38 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point);
39
40 int
41 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode);
42
43 int
44 __twifs_rmstuff(struct v_inode* inode);
45
46 int
47 __twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
48
49 int
50 __twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
51
52 void
53 twifs_init()
54 {
55     twi_pile = cake_new_pile("twifs_node", sizeof(struct twifs_node), 1, 0);
56
57     struct filesystem* twifs = vzalloc(sizeof(struct filesystem));
58     twifs->fs_name = HSTR("twifs", 5);
59     twifs->mount = __twifs_mount;
60     twifs->types = FSTYPE_ROFS;
61
62     fsm_register(twifs);
63
64     fs_root = twifs_dir_node(NULL, NULL, 0, 0);
65 }
66
67 struct twifs_node*
68 __twifs_new_node(struct twifs_node* parent,
69                  const char* name,
70                  int name_len,
71                  uint32_t itype)
72 {
73     struct twifs_node* node = cake_grab(twi_pile);
74     memset(node, 0, sizeof(*node));
75
76     node->name = HSTR(name, name_len);
77     node->itype = itype;
78     hstr_rehash(&node->name, HSTR_FULL_HASH);
79     llist_init_head(&node->children);
80
81     if (parent) {
82         llist_append(&parent->children, &node->siblings);
83     }
84
85     return node;
86 }
87
88 int
89 twifs_rm_node(struct twifs_node* node)
90 {
91     if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) {
92         return ENOTEMPTY;
93     }
94     llist_delete(&node->siblings);
95     vfs_i_free(node->inode);
96     cake_release(twi_pile, node);
97     return 0;
98 }
99
100 struct twifs_node*
101 twifs_file_node(struct twifs_node* parent,
102                 const char* name,
103                 int name_len,
104                 uint32_t itype)
105 {
106     struct twifs_node* twi_node =
107       __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype);
108
109     struct v_inode* twi_inode = __twifs_create_inode(twi_node);
110     twi_node->inode = twi_inode;
111
112     return twi_node;
113 }
114
115 struct twifs_node*
116 twifs_dir_node(struct twifs_node* parent,
117                const char* name,
118                int name_len,
119                uint32_t itype)
120 {
121     struct hstr hname = HSTR(name, name_len);
122     hstr_rehash(&hname, HSTR_FULL_HASH);
123     struct twifs_node* node = __twifs_get_node(parent, &hname);
124     if (node) {
125         return node;
126     }
127
128     struct twifs_node* twi_node =
129       __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype);
130
131     struct v_inode* twi_inode = __twifs_create_inode(twi_node);
132     twi_node->inode = twi_inode;
133
134     return twi_node;
135 }
136
137 struct twifs_node*
138 twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
139 {
140     return twifs_dir_node(fs_root, name, name_len, itype);
141 }
142
143 int
144 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
145 {
146     struct twifs_node* parent_node = (struct twifs_node*)inode->data;
147     if (!(parent_node->itype & VFS_IFDIR)) {
148         return ENOTDIR;
149     }
150     struct twifs_node* new_node =
151       twifs_dir_node(parent_node, dnode->name.value, dnode->name.len, 0);
152     dnode->inode = new_node->inode;
153
154     return 0;
155 }
156
157 int
158 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
159 {
160     mount_point->inode = fs_root->inode;
161     return 0;
162 }
163
164 struct v_inode*
165 __twifs_create_inode(struct twifs_node* twi_node)
166 {
167     struct v_inode* inode = vfs_i_alloc();
168     *inode = (struct v_inode){ .ctime = 0,
169                                .itype = twi_node->itype,
170                                .lb_addr = 0,
171                                .lb_usage = 0,
172                                .data = twi_node,
173                                .mtime = 0,
174                                .open_count = 0 };
175     inode->ops.dir_lookup = __twifs_dirlookup;
176     inode->ops.mkdir = __twifs_mkdir;
177     inode->ops.unlink = __twifs_rmstuff;
178     inode->ops.rmdir = __twifs_rmstuff;
179     inode->ops.open = __twifs_openfile;
180
181     inode->default_fops = (struct v_file_ops){ .read = __twifs_fread,
182                                                .write = __twifs_fwrite,
183                                                .readdir = __twifs_iterate_dir };
184
185     return inode;
186 }
187
188 int
189 __twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
190 {
191     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
192     if (!twi_node || !twi_node->ops.write) {
193         return ENOTSUP;
194     }
195     return twi_node->ops.write(inode, buffer, len, fpos);
196 }
197
198 int
199 __twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
200 {
201     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
202     if (!twi_node || !twi_node->ops.read) {
203         return ENOTSUP;
204     }
205     return twi_node->ops.read(inode, buffer, len, fpos);
206 }
207
208 struct twifs_node*
209 __twifs_get_node(struct twifs_node* parent, struct hstr* name)
210 {
211     if (!parent)
212         return NULL;
213
214     struct twifs_node *pos, *n;
215     llist_for_each(pos, n, &parent->children, siblings)
216     {
217         if (HSTR_EQ(&pos->name, name)) {
218             return pos;
219         }
220     }
221     return NULL;
222 }
223
224 int
225 __twifs_rmstuff(struct v_inode* inode)
226 {
227     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
228     return twifs_rm_node(twi_node);
229 }
230
231 int
232 __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
233 {
234     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
235
236     if (!(twi_node->itype & VFS_IFDIR)) {
237         return ENOTDIR;
238     }
239
240     struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
241     if (child_node) {
242         dnode->inode = child_node->inode;
243         return 0;
244     }
245     return ENOENT;
246 }
247
248 int
249 __twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx)
250 {
251     struct twifs_node* twi_node = (struct twifs_node*)(inode->data);
252     int counter = 0;
253     struct twifs_node *pos, *n;
254
255     llist_for_each(pos, n, &twi_node->children, siblings)
256     {
257         if (counter++ >= dctx->index) {
258             dctx->index = counter;
259             dctx->read_complete_callback(
260               dctx, pos->name.value, pos->name.len, pos->itype);
261             return 0;
262         }
263     }
264
265     return 1;
266 }
267
268 int
269 __twifs_openfile(struct v_inode* inode, struct v_file* file)
270 {
271     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
272     if (twi_node) {
273         return 0;
274     }
275     return ENOTSUP;
276 }