feat: twifs - pseudo file system for lunaix kernel state exposure
[lunaix-os.git] / lunaix-os / kernel / fs / vfs.c
1 #include <klibc/string.h>
2 #include <lunaix/fs.h>
3 #include <lunaix/mm/cake.h>
4 #include <lunaix/mm/page.h>
5 #include <lunaix/mm/valloc.h>
6 #include <lunaix/spike.h>
7
8 #define PATH_DELIM '/'
9 #define DNODE_HASHTABLE_BITS 10
10 #define DNODE_HASHTABLE_SIZE (1 << DNODE_HASHTABLE_BITS)
11 #define DNODE_HASH_MASK (DNODE_HASHTABLE_SIZE - 1)
12 #define DNODE_HASHBITS (32 - DNODE_HASHTABLE_BITS)
13
14 static struct cake_pile* dnode_pile;
15 static struct cake_pile* inode_pile;
16 static struct cake_pile* file_pile;
17 static struct cake_pile* superblock_pile;
18
19 static struct v_superblock* root_sb;
20 static struct hbucket* dnode_cache;
21
22 static int fs_id = 0;
23
24 struct v_dnode*
25 vfs_d_alloc();
26
27 void
28 vfs_d_free(struct v_dnode* dnode);
29
30 struct v_superblock*
31 vfs_sb_alloc();
32
33 void
34 vfs_sb_free(struct v_superblock* sb);
35
36 void
37 vfs_init()
38 {
39     // 为他们专门创建一个蛋糕堆,而不使用valloc,这样我们可以最小化内碎片的产生
40     dnode_pile = cake_new_pile("dnode_cache", sizeof(struct v_dnode), 1, 0);
41     inode_pile = cake_new_pile("inode_cache", sizeof(struct v_inode), 1, 0);
42     inode_pile = cake_new_pile("file_cache", sizeof(struct v_file), 1, 0);
43     superblock_pile =
44       cake_new_pile("sb_cache", sizeof(struct v_superblock), 1, 0);
45
46     dnode_cache = valloc(DNODE_HASHTABLE_SIZE * sizeof(struct hbucket));
47
48     // 挂载Lunaix的根文件系统,TwiFS!
49     struct filesystem* rootfs = fsm_get("twifs");
50     root_sb = vfs_sb_alloc();
51     rootfs->mount(root_sb, NULL);
52 }
53
54 inline struct hbucket*
55 __dcache_get_bucket(struct v_dnode* parent, unsigned int hash)
56 {
57     // 与parent的指针值做加法,来减小碰撞的可能性。
58     hash += (uint32_t)parent;
59     // 确保低位更加随机
60     hash = hash ^ (hash >> DNODE_HASHBITS);
61     return &dnode_cache[hash & DNODE_HASH_MASK];
62 }
63
64 struct v_dnode*
65 vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str)
66 {
67     struct hbucket* slot = __dcache_get_bucket(parent, str->hash);
68
69     struct v_dnode *pos, *n;
70     hashtable_bucket_foreach(slot, pos, n, hash_list)
71     {
72         if (pos->name.hash == str->hash) {
73             return pos;
74         }
75     }
76     return NULL;
77 }
78
79 void
80 vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode)
81 {
82     struct hbucket* bucket = __dcache_get_bucket(parent, dnode->name.hash);
83     hlist_add(&bucket->head, &dnode->hash_list);
84 }
85
86 int
87 vfs_walk(struct v_dnode* start,
88          const char* path,
89          struct v_dnode** dentry,
90          int walk_options)
91 {
92     int errno = 0;
93     int i = 0, j = 0;
94
95     if (path[0] == PATH_DELIM) {
96         if ((walk_options & VFS_WALK_FSRELATIVE)) {
97             start = start->super_block->root;
98         } else {
99             start = root_sb->root;
100         }
101         i++;
102     }
103
104     struct v_dnode* dnode;
105     struct v_dnode* current_level = start;
106
107     char name_content[VFS_NAME_MAXLEN];
108     struct hstr name = HSTR(name_content, 0);
109
110     char current = path[i++], lookahead;
111     while (current) {
112         lookahead = path[i++];
113         if (current != PATH_DELIM) {
114             if (j >= VFS_NAME_MAXLEN - 1) {
115                 return VFS_ETOOLONG;
116             }
117             if (!VFS_VALID_CHAR(current)) {
118                 return VFS_EINVLD;
119             }
120             name_content[j++] = current;
121             if (lookahead) {
122                 goto cont;
123             }
124         }
125
126         // handling cases like /^.*(\/+).*$/
127         if (lookahead == PATH_DELIM) {
128             goto cont;
129         }
130
131         name_content[j] = 0;
132         hstr_rehash(&name, HSTR_FULL_HASH);
133
134         dnode = vfs_dcache_lookup(current_level, &name);
135
136         if (!dnode) {
137             dnode = vfs_d_alloc();
138             dnode->name = HSTR(valloc(VFS_NAME_MAXLEN), j);
139             dnode->name.hash = name.hash;
140
141             strcpy(dnode->name.value, name_content);
142
143             errno =
144               current_level->inode->ops.dir_lookup(current_level->inode, dnode);
145
146             if (errno == VFS_ENOTFOUND &&
147                 ((walk_options & VFS_WALK_MKPARENT) ||
148                  ((walk_options & VFS_WALK_MKDIR) && !lookahead))) {
149                 /*
150                     两种创建文件夹的情况:
151                         1) VFS_WALK_MKPARENT:沿路创建所有不存在的文件夹
152                         2) VFS_WALK_MKDIR:仅创建路径最后一级的不存在文件夹
153                 */
154                 if (!current_level->inode->ops.mkdir) {
155                     errno = VFS_ENOOPS;
156                 } else {
157                     errno = current_level->inode->ops.mkdir(
158                       current_level->inode, dnode);
159                 }
160             }
161
162             if (errno) {
163                 goto error;
164             }
165
166             vfs_dcache_add(current_level, dnode);
167
168             dnode->parent = current_level;
169             llist_append(&current_level->children, &dnode->siblings);
170         }
171
172         j = 0;
173         current_level = dnode;
174     cont:
175         current = lookahead;
176     };
177
178     *dentry = current_level;
179     return 0;
180
181 error:
182     vfree(dnode->name.value);
183     vfs_d_free(dnode);
184     return errno;
185 }
186
187 int
188 vfs_mount(const char* fs_name, bdev_t device, struct v_dnode* mnt_point)
189 {
190     struct filesystem* fs = fsm_get(fs_name);
191     if (!fs)
192         return VFS_ENOFS;
193     struct v_superblock* sb = vfs_sb_alloc();
194     sb->dev = device;
195     sb->fs_id = fs_id++;
196
197     int errno = 0;
198     if (!(errno = fs->mount(sb, mnt_point))) {
199         sb->fs = fs;
200         sb->root = mnt_point;
201         mnt_point->super_block = sb;
202         llist_append(&root_sb->sb_list, &sb->sb_list);
203     }
204
205     return errno;
206 }
207
208 int
209 vfs_mkdir(const char* parent_path,
210           const char* component,
211           struct v_dnode** dentry)
212 {
213     return vfs_walk(root_sb->root, parent_path, dentry, VFS_WALK_MKDIR);
214 }
215
216 int
217 vfs_unmount(struct v_dnode* mnt_point)
218 {
219     int errno = 0;
220     struct v_superblock* sb = mnt_point->super_block;
221     if (!sb) {
222         return VFS_EBADMNT;
223     }
224     if (!(errno = sb->fs->unmount(sb))) {
225         struct v_dnode* fs_root = sb->root;
226         llist_delete(&fs_root->siblings);
227         llist_delete(&sb->sb_list);
228         vfs_sb_free(sb);
229     }
230     return errno;
231 }
232
233 int
234 vfs_open(struct v_dnode* dnode, struct v_file** file)
235 {
236     if (!dnode->inode || !dnode->inode->ops.open) {
237         return VFS_ENOOPS;
238     }
239
240     struct v_file* vfile = cake_grab(file_pile);
241     memset(vfile, 0, sizeof(*vfile));
242
243     int errno = dnode->inode->ops.open(dnode->inode, vfile);
244     if (errno) {
245         cake_release(file_pile, vfile);
246     } else {
247         *file = vfile;
248     }
249     return errno;
250 }
251
252 int
253 vfs_close(struct v_file* file)
254 {
255     if (!file->ops.close) {
256         return VFS_ENOOPS;
257     }
258
259     int errno = file->ops.close(file);
260     if (!errno) {
261         cake_release(file_pile, file);
262     }
263     return errno;
264 }
265
266 int
267 vfs_fsync(struct v_file* file)
268 {
269     int errno = VFS_ENOOPS;
270     if (file->ops.sync) {
271         errno = file->ops.sync(file);
272     }
273     if (!errno && file->inode->ops.sync) {
274         return file->inode->ops.sync(file->inode);
275     }
276     return errno;
277 }
278
279 struct v_superblock*
280 vfs_sb_alloc()
281 {
282     struct v_superblock* sb = cake_grab(superblock_pile);
283     memset(sb, 0, sizeof(*sb));
284     llist_init_head(&sb->sb_list);
285     return sb;
286 }
287
288 void
289 vfs_sb_free(struct v_superblock* sb)
290 {
291     cake_release(superblock_pile, sb);
292 }
293
294 struct v_dnode*
295 vfs_d_alloc()
296 {
297     struct v_dnode* dnode = cake_grab(dnode_pile);
298     llist_init_head(&dnode->children);
299 }
300
301 void
302 vfs_d_free(struct v_dnode* dnode)
303 {
304     if (dnode->ops.destruct) {
305         dnode->ops.destruct(dnode);
306     }
307     cake_release(dnode_pile, dnode);
308 }
309
310 struct v_inode*
311 vfs_i_alloc()
312 {
313     struct v_inode* inode = cake_grab(inode_pile);
314     memset(inode, 0, sizeof(*inode));
315
316     return inode;
317 }
318
319 void
320 vfs_i_free(struct v_inode* inode)
321 {
322     cake_release(inode_pile, inode);
323 }