refactor: inode hashing and reusing
[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);
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     vfs_i_free(node->inode);
99     cake_release(twi_pile, node);
100     return 0;
101 }
102
103 struct twifs_node*
104 twifs_file_node(struct twifs_node* parent,
105                 const char* name,
106                 int name_len,
107                 uint32_t itype)
108 {
109     struct twifs_node* twi_node =
110       __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype);
111
112     struct v_inode* twi_inode = __twifs_create_inode(twi_node);
113     twi_node->inode = twi_inode;
114
115     return twi_node;
116 }
117
118 struct twifs_node*
119 twifs_dir_node(struct twifs_node* parent,
120                const char* name,
121                int name_len,
122                uint32_t itype)
123 {
124     struct hstr hname = HSTR(name, name_len);
125     hstr_rehash(&hname, HSTR_FULL_HASH);
126     struct twifs_node* node = __twifs_get_node(parent, &hname);
127     if (node) {
128         return node;
129     }
130
131     struct twifs_node* twi_node =
132       __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype);
133
134     struct v_inode* twi_inode = __twifs_create_inode(twi_node);
135     twi_node->inode = twi_inode;
136
137     return twi_node;
138 }
139
140 struct twifs_node*
141 twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
142 {
143     return twifs_dir_node(fs_root, name, name_len, itype);
144 }
145
146 int
147 __twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
148 {
149     struct twifs_node* parent_node = (struct twifs_node*)inode->data;
150     if (!(parent_node->itype & VFS_IFDIR)) {
151         return ENOTDIR;
152     }
153     struct twifs_node* new_node =
154       twifs_dir_node(parent_node, dnode->name.value, dnode->name.len, 0);
155     dnode->inode = new_node->inode;
156
157     return 0;
158 }
159
160 int
161 __twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
162 {
163     mount_point->inode = fs_root->inode;
164     return 0;
165 }
166
167 struct v_inode*
168 __twifs_create_inode(struct twifs_node* twi_node)
169 {
170     struct v_inode* inode = vfs_i_alloc(1, inode_id++);
171     inode->itype = twi_node->itype;
172     inode->data = twi_node;
173
174     inode->ctime = clock_unixtime();
175     inode->atime = inode->ctime;
176     inode->mtime = inode->ctime;
177
178     inode->ops.dir_lookup = __twifs_dirlookup;
179     inode->ops.mkdir = __twifs_mkdir;
180     inode->ops.unlink = __twifs_rmstuff;
181     inode->ops.rmdir = __twifs_rmstuff;
182     inode->ops.open = __twifs_openfile;
183
184     inode->default_fops = (struct v_file_ops){ .read = __twifs_fread,
185                                                .write = __twifs_fwrite,
186                                                .readdir = __twifs_iterate_dir };
187
188     return inode;
189 }
190
191 int
192 __twifs_fwrite(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.write) {
196         return ENOTSUP;
197     }
198     return twi_node->ops.write(inode, buffer, len, fpos);
199 }
200
201 int
202 __twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
203 {
204     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
205     if (!twi_node || !twi_node->ops.read) {
206         return ENOTSUP;
207     }
208     return twi_node->ops.read(inode, buffer, len, fpos);
209 }
210
211 struct twifs_node*
212 __twifs_get_node(struct twifs_node* parent, struct hstr* name)
213 {
214     if (!parent)
215         return NULL;
216
217     struct twifs_node *pos, *n;
218     llist_for_each(pos, n, &parent->children, siblings)
219     {
220         if (HSTR_EQ(&pos->name, name)) {
221             return pos;
222         }
223     }
224     return NULL;
225 }
226
227 int
228 __twifs_rmstuff(struct v_inode* inode)
229 {
230     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
231     return twifs_rm_node(twi_node);
232 }
233
234 int
235 __twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
236 {
237     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
238
239     if (!(twi_node->itype & VFS_IFDIR)) {
240         return ENOTDIR;
241     }
242
243     struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
244     if (child_node) {
245         dnode->inode = child_node->inode;
246         return 0;
247     }
248     return ENOENT;
249 }
250
251 int
252 __twifs_iterate_dir(struct v_inode* inode, struct dir_context* dctx)
253 {
254     struct twifs_node* twi_node = (struct twifs_node*)(inode->data);
255     int counter = 0;
256     struct twifs_node *pos, *n;
257
258     llist_for_each(pos, n, &twi_node->children, siblings)
259     {
260         if (counter++ >= dctx->index) {
261             dctx->index = counter;
262             dctx->read_complete_callback(
263               dctx, pos->name.value, pos->name.len, pos->itype);
264             return 0;
265         }
266     }
267
268     return 1;
269 }
270
271 int
272 __twifs_openfile(struct v_inode* inode, struct v_file* file)
273 {
274     struct twifs_node* twi_node = (struct twifs_node*)inode->data;
275     if (twi_node) {
276         return 0;
277     }
278     return ENOTSUP;
279 }