feat: ability to evict dnode and inode cache
[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 static volatile int32_t inode_id = 0;
23
24 int
25 __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode);
26
27 int
28 __twifs_openfile(struct v_inode* inode, struct v_file* file);
29
30 struct twifs_node*
31 __twifs_get_node(struct twifs_node* parent, struct hstr* name);
32
33 struct v_inode*
34 __twifs_create_inode(struct twifs_node* twi_node);
35
36 int
37 __twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx);
38
39 int
40 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point);
41
42 int
43 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode);
44
45 int
46 __twifs_rmstuff(struct v_inode* inode, struct v_dnode* dir);
47
48 int
49 __twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
50
51 int
52 __twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
53
54 void
55 twifs_init()
56 {
57     twi_pile = cake_new_pile("twifs_node", sizeof(struct twifs_node), 1, 0);
58
59     struct filesystem* twifs = vzalloc(sizeof(struct filesystem));
60     twifs->fs_name = HSTR("twifs", 5);
61     twifs->mount = __twifs_mount;
62     twifs->types = FSTYPE_ROFS;
63     twifs->fs_id = 0;
64
65     fsm_register(twifs);
66
67     fs_root = twifs_dir_node(NULL, NULL, 0, 0);
68 }
69
70 struct twifs_node*
71 __twifs_new_node(struct twifs_node* parent,
72                  const char* name,
73                  int name_len,
74                  uint32_t itype)
75 {
76     struct twifs_node* node = cake_grab(twi_pile);
77     memset(node, 0, sizeof(*node));
78
79     node->name = HSTR(name, name_len);
80     node->itype = itype;
81     hstr_rehash(&node->name, HSTR_FULL_HASH);
82     llist_init_head(&node->children);
83
84     if (parent) {
85         llist_append(&parent->children, &node->siblings);
86     }
87
88     return node;
89 }
90
91 int
92 twifs_rm_node(struct twifs_node* node)
93 {
94     if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) {
95         return ENOTEMPTY;
96     }
97     llist_delete(&node->siblings);
98     cake_release(twi_pile, node);
99     return 0;
100 }
101
102 struct twifs_node*
103 twifs_file_node(struct twifs_node* parent,
104                 const char* name,
105                 int name_len,
106                 uint32_t itype)
107 {
108     struct twifs_node* twi_node =
109       __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype);
110
111     struct v_inode* twi_inode = __twifs_create_inode(twi_node);
112     twi_node->inode = twi_inode;
113
114     return twi_node;
115 }
116
117 struct twifs_node*
118 twifs_dir_node(struct twifs_node* parent,
119                const char* name,
120                int name_len,
121                uint32_t itype)
122 {
123     struct hstr hname = HSTR(name, name_len);
124     hstr_rehash(&hname, HSTR_FULL_HASH);
125     struct twifs_node* node = __twifs_get_node(parent, &hname);
126     if (node) {
127         return node;
128     }
129
130     struct twifs_node* twi_node =
131       __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype);
132
133     struct v_inode* twi_inode = __twifs_create_inode(twi_node);
134     twi_node->inode = twi_inode;
135
136     return twi_node;
137 }
138
139 struct twifs_node*
140 twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
141 {
142     return twifs_dir_node(fs_root, name, name_len, itype);
143 }
144
145 int
146 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
147 {
148     return ENOTSUP;
149 }
150
151 int
152 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
153 {
154     vfs_assign_inode(mount_point, fs_root->inode);
155     return 0;
156 }
157
158 struct v_inode*
159 __twifs_create_inode(struct twifs_node* twi_node)
160 {
161     struct v_inode* inode = vfs_i_alloc(1, inode_id++);
162     inode->itype = twi_node->itype;
163     inode->data = twi_node;
164
165     inode->ctime = clock_unixtime();
166     inode->atime = inode->ctime;
167     inode->mtime = inode->ctime;
168
169     inode->ops.dir_lookup = __twifs_dirlookup;
170     inode->ops.mkdir = __twifs_mkdir;
171     inode->ops.rmdir = __twifs_rmstuff;
172     inode->ops.open = __twifs_openfile;
173
174     inode->default_fops = (struct v_file_ops){ .read = __twifs_fread,
175                                                .write = __twifs_fwrite,
176                                                .readdir = __twifs_iterate_dir };
177
178     return inode;
179 }
180
181 int
182 __twifs_fwrite(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
183 {
184     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
185     if (!twi_node || !twi_node->ops.write) {
186         return ENOTSUP;
187     }
188     return twi_node->ops.write(inode, buffer, len, fpos);
189 }
190
191 int
192 __twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
193 {
194     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
195     if (!twi_node || !twi_node->ops.read) {
196         return ENOTSUP;
197     }
198     return twi_node->ops.read(inode, buffer, len, fpos);
199 }
200
201 struct twifs_node*
202 __twifs_get_node(struct twifs_node* parent, struct hstr* name)
203 {
204     if (!parent)
205         return NULL;
206
207     struct twifs_node *pos, *n;
208     llist_for_each(pos, n, &parent->children, siblings)
209     {
210         if (HSTR_EQ(&pos->name, name)) {
211             return pos;
212         }
213     }
214     return NULL;
215 }
216
217 int
218 __twifs_rmstuff(struct v_inode* inode, struct v_dnode* dir)
219 {
220     return ENOTSUP;
221 }
222
223 int
224 __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
225 {
226     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
227
228     if (!(twi_node->itype & VFS_IFDIR)) {
229         return ENOTDIR;
230     }
231
232     struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
233     if (child_node) {
234         vfs_assign_inode(dnode, child_node->inode);
235         return 0;
236     }
237     return ENOENT;
238 }
239
240 int
241 __twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx)
242 {
243     struct twifs_node* twi_node = (struct twifs_node*)(inode->data);
244     int counter = 0;
245     struct twifs_node *pos, *n;
246
247     llist_for_each(pos, n, &twi_node->children, siblings)
248     {
249         if (counter++ >= dctx->index) {
250             dctx->index = counter;
251             dctx->read_complete_callback(
252               dctx, pos->name.value, pos->name.len, pos->itype);
253             return 0;
254         }
255     }
256
257     return 1;
258 }
259
260 int
261 __twifs_openfile(struct v_inode* inode, struct v_file* file)
262 {
263     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
264     if (twi_node) {
265         return 0;
266     }
267     return ENOTSUP;
268 }