0fbf6529df93295f851e13b690f827479daa5d69
[lunaix-os.git] / lunaix-os / kernel / fs / vfs.c
1 /**
2  * @file vfs.c
3  * @author Lunaixsky (zelong56@gmail.com)
4  * @brief Lunaix virtual file system - an abstraction layer for all file system.
5  * @version 0.1
6  * @date 2022-07-24
7  *
8  * @copyright Copyright (c) 2022
9  *
10  */
11
12 #include <klibc/string.h>
13 #include <lunaix/dirent.h>
14 #include <lunaix/foptions.h>
15 #include <lunaix/fs.h>
16 #include <lunaix/mm/cake.h>
17 #include <lunaix/mm/page.h>
18 #include <lunaix/mm/valloc.h>
19 #include <lunaix/process.h>
20 #include <lunaix/spike.h>
21 #include <lunaix/syscall.h>
22
23 #define PATH_DELIM '/'
24 #define DNODE_HASHTABLE_BITS 10
25 #define DNODE_HASHTABLE_SIZE (1 << DNODE_HASHTABLE_BITS)
26 #define DNODE_HASH_MASK (DNODE_HASHTABLE_SIZE - 1)
27 #define DNODE_HASHBITS (32 - DNODE_HASHTABLE_BITS)
28
29 static struct cake_pile* dnode_pile;
30 static struct cake_pile* inode_pile;
31 static struct cake_pile* file_pile;
32 static struct cake_pile* superblock_pile;
33 static struct cake_pile* fd_pile;
34
35 static struct v_superblock* root_sb;
36 static struct hbucket* dnode_cache;
37
38 static int fs_id = 0;
39
40 struct hstr vfs_ddot = HSTR("..", 2);
41 struct hstr vfs_dot = HSTR(".", 1);
42 struct hstr vfs_empty = HSTR("", 0);
43
44 struct v_dnode*
45 vfs_d_alloc();
46
47 void
48 vfs_d_free(struct v_dnode* dnode);
49
50 struct v_superblock*
51 vfs_sb_alloc();
52
53 void
54 vfs_sb_free(struct v_superblock* sb);
55
56 void
57 vfs_init()
58 {
59     // 为他们专门创建一个蛋糕堆,而不使用valloc,这样我们可以最小化内碎片的产生
60     dnode_pile = cake_new_pile("dnode_cache", sizeof(struct v_dnode), 1, 0);
61     inode_pile = cake_new_pile("inode_cache", sizeof(struct v_inode), 1, 0);
62     file_pile = cake_new_pile("file_cache", sizeof(struct v_file), 1, 0);
63     fd_pile = cake_new_pile("fd_cache", sizeof(struct v_fd), 1, 0);
64     superblock_pile =
65       cake_new_pile("sb_cache", sizeof(struct v_superblock), 1, 0);
66
67     dnode_cache = vzalloc(DNODE_HASHTABLE_SIZE * sizeof(struct hbucket));
68
69     hstr_rehash(&vfs_ddot, HSTR_FULL_HASH);
70     hstr_rehash(&vfs_dot, HSTR_FULL_HASH);
71
72     // 创建一个根superblock,用来蕴含我们的根目录。
73     root_sb = vfs_sb_alloc();
74     root_sb->root = vfs_d_alloc();
75 }
76
77 inline struct hbucket*
78 __dcache_get_bucket(struct v_dnode* parent, unsigned int hash)
79 {
80     // 与parent的指针值做加法,来减小碰撞的可能性。
81     hash += (uint32_t)parent;
82     // 确保低位更加随机
83     hash = hash ^ (hash >> DNODE_HASHBITS);
84     return &dnode_cache[hash & DNODE_HASH_MASK];
85 }
86
87 struct v_dnode*
88 vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str)
89 {
90     if (!str->len || HSTR_EQ(str, &vfs_dot))
91         return parent;
92
93     if (HSTR_EQ(str, &vfs_ddot)) {
94         return parent->parent ? parent->parent : parent;
95     }
96
97     struct hbucket* slot = __dcache_get_bucket(parent, str->hash);
98
99     struct v_dnode *pos, *n;
100     hashtable_bucket_foreach(slot, pos, n, hash_list)
101     {
102         if (pos->name.hash == str->hash) {
103             return pos;
104         }
105     }
106     return NULL;
107 }
108
109 void
110 vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode)
111 {
112     struct hbucket* bucket = __dcache_get_bucket(parent, dnode->name.hash);
113     hlist_add(&bucket->head, &dnode->hash_list);
114 }
115
116 int
117 vfs_walk(struct v_dnode* start,
118          const char* path,
119          struct v_dnode** dentry,
120          struct hstr* component,
121          int walk_options)
122 {
123     int errno = 0;
124     int i = 0, j = 0;
125
126     if (path[0] == PATH_DELIM || !start) {
127         if ((walk_options & VFS_WALK_FSRELATIVE) && start) {
128             start = start->super_block->root;
129         } else {
130             start = root_sb->root;
131         }
132         i++;
133     }
134
135     struct v_dnode* dnode;
136     struct v_dnode* current_level = start;
137
138     char name_content[VFS_NAME_MAXLEN];
139     struct hstr name = HSTR(name_content, 0);
140
141     char current = path[i++], lookahead;
142     while (current) {
143         lookahead = path[i++];
144         if (current != PATH_DELIM) {
145             if (j >= VFS_NAME_MAXLEN - 1) {
146                 return ENAMETOOLONG;
147             }
148             if (!VFS_VALID_CHAR(current)) {
149                 return VFS_EINVLD;
150             }
151             name_content[j++] = current;
152             if (lookahead) {
153                 goto cont;
154             }
155         }
156
157         // handling cases like /^.*(\/+).*$/
158         if (lookahead == PATH_DELIM) {
159             goto cont;
160         }
161
162         name_content[j] = 0;
163         name.len = j;
164         hstr_rehash(&name, HSTR_FULL_HASH);
165
166         if (!lookahead && (walk_options & VFS_WALK_PARENT)) {
167             if (component) {
168                 component->hash = name.hash;
169                 component->len = j;
170                 strcpy(component->value, name_content);
171             }
172             break;
173         }
174
175         dnode = vfs_dcache_lookup(current_level, &name);
176
177         if (!dnode) {
178             dnode = vfs_d_alloc();
179             dnode->name = HSTR(valloc(VFS_NAME_MAXLEN), j);
180             dnode->name.hash = name.hash;
181
182             strcpy(dnode->name.value, name_content);
183
184             errno =
185               current_level->inode->ops.dir_lookup(current_level->inode, dnode);
186
187             if (errno == ENOENT && (walk_options & VFS_WALK_MKPARENT)) {
188                 if (!current_level->inode->ops.mkdir) {
189                     errno = ENOTSUP;
190                 } else {
191                     errno = current_level->inode->ops.mkdir(
192                       current_level->inode, dnode);
193                 }
194             }
195
196             if (errno) {
197                 goto error;
198             }
199
200             vfs_dcache_add(current_level, dnode);
201
202             dnode->parent = current_level;
203             llist_append(&current_level->children, &dnode->siblings);
204         }
205
206         j = 0;
207         current_level = dnode;
208     cont:
209         current = lookahead;
210     };
211
212     *dentry = current_level;
213     return 0;
214
215 error:
216     vfree(dnode->name.value);
217     vfs_d_free(dnode);
218     *dentry = NULL;
219     return errno;
220 }
221
222 int
223 vfs_mount(const char* target, const char* fs_name, bdev_t device)
224 {
225     int errno;
226     struct v_dnode* mnt;
227
228     if (!(errno = vfs_walk(NULL, target, &mnt, NULL, 0))) {
229         errno = vfs_mount_at(fs_name, device, mnt);
230     }
231
232     return errno;
233 }
234
235 int
236 vfs_unmount(const char* target)
237 {
238     int errno;
239     struct v_dnode* mnt;
240
241     if (!(errno = vfs_walk(NULL, target, &mnt, NULL, 0))) {
242         errno = vfs_unmount_at(mnt);
243     }
244
245     return errno;
246 }
247
248 int
249 vfs_mount_at(const char* fs_name, bdev_t device, struct v_dnode* mnt_point)
250 {
251     struct filesystem* fs = fsm_get(fs_name);
252     if (!fs)
253         return VFS_ENOFS;
254     struct v_superblock* sb = vfs_sb_alloc();
255     sb->dev = device;
256     sb->fs_id = fs_id++;
257
258     int errno = 0;
259     if (!(errno = fs->mount(sb, mnt_point))) {
260         sb->fs = fs;
261         sb->root = mnt_point;
262         mnt_point->super_block = sb;
263         llist_append(&root_sb->sb_list, &sb->sb_list);
264     }
265
266     return errno;
267 }
268
269 int
270 vfs_unmount_at(struct v_dnode* mnt_point)
271 {
272     int errno = 0;
273     struct v_superblock* sb = mnt_point->super_block;
274     if (!sb) {
275         return VFS_EBADMNT;
276     }
277     if (!(errno = sb->fs->unmount(sb))) {
278         struct v_dnode* fs_root = sb->root;
279         llist_delete(&fs_root->siblings);
280         llist_delete(&sb->sb_list);
281         vfs_sb_free(sb);
282     }
283     return errno;
284 }
285
286 int
287 vfs_open(struct v_dnode* dnode, struct v_file** file)
288 {
289     if (!dnode->inode || !dnode->inode->ops.open) {
290         return ENOTSUP;
291     }
292
293     struct v_file* vfile = cake_grab(file_pile);
294     memset(vfile, 0, sizeof(*vfile));
295
296     vfile->dnode = dnode;
297     vfile->inode = dnode->inode;
298     dnode->inode->open_count++;
299
300     int errno = dnode->inode->ops.open(dnode->inode, vfile);
301     if (errno) {
302         cake_release(file_pile, vfile);
303     } else {
304         *file = vfile;
305     }
306     return errno;
307 }
308
309 int
310 vfs_close(struct v_file* file)
311 {
312     if (!file->ops.close) {
313         return ENOTSUP;
314     }
315
316     int errno = file->ops.close(file);
317     if (!errno) {
318         if (file->inode->open_count) {
319             file->inode->open_count--;
320         }
321         cake_release(file_pile, file);
322     }
323     return errno;
324 }
325
326 int
327 vfs_fsync(struct v_file* file)
328 {
329     int errno = ENOTSUP;
330     if (file->ops.sync) {
331         errno = file->ops.sync(file);
332     }
333     if (!errno && file->inode->ops.sync) {
334         return file->inode->ops.sync(file->inode);
335     }
336     return errno;
337 }
338
339 int
340 vfs_alloc_fdslot(int* fd)
341 {
342     for (size_t i = 0; i < VFS_MAX_FD; i++) {
343         if (!__current->fdtable->fds[i]) {
344             *fd = i;
345             return 0;
346         }
347     }
348     return EMFILE;
349 }
350
351 struct v_superblock*
352 vfs_sb_alloc()
353 {
354     struct v_superblock* sb = cake_grab(superblock_pile);
355     memset(sb, 0, sizeof(*sb));
356     llist_init_head(&sb->sb_list);
357     return sb;
358 }
359
360 void
361 vfs_sb_free(struct v_superblock* sb)
362 {
363     cake_release(superblock_pile, sb);
364 }
365
366 struct v_dnode*
367 vfs_d_alloc()
368 {
369     struct v_dnode* dnode = cake_grab(dnode_pile);
370     memset(dnode, 0, sizeof(*dnode));
371     llist_init_head(&dnode->children);
372     dnode->name = vfs_empty;
373     return dnode;
374 }
375
376 void
377 vfs_d_free(struct v_dnode* dnode)
378 {
379     if (dnode->ops.destruct) {
380         dnode->ops.destruct(dnode);
381     }
382     cake_release(dnode_pile, dnode);
383 }
384
385 struct v_inode*
386 vfs_i_alloc()
387 {
388     struct v_inode* inode = cake_grab(inode_pile);
389     memset(inode, 0, sizeof(*inode));
390
391     return inode;
392 }
393
394 void
395 vfs_i_free(struct v_inode* inode)
396 {
397     cake_release(inode_pile, inode);
398 }
399
400 /* ---- System call definition and support ---- */
401
402 int
403 __vfs_do_open(struct v_file** file_out, const char* path, int options)
404 {
405     char name_str[VFS_NAME_MAXLEN];
406     struct hstr name = HSTR(name_str, 0);
407     struct v_dnode *dentry, *file;
408     int errno;
409     if ((errno = vfs_walk(NULL, path, &dentry, &name, VFS_WALK_PARENT))) {
410         return ENOENT;
411     }
412
413     vfs_walk(dentry, name.value, &file, NULL, 0);
414
415     struct v_file* opened_file = 0;
416     if (!file) {
417         if ((options & FO_CREATE)) {
418             errno = dentry->inode->ops.create(dentry->inode, opened_file);
419         } else {
420             errno = ENOENT;
421         }
422     } else {
423         errno = vfs_open(file, &opened_file);
424     }
425
426     *file_out = opened_file;
427     return errno;
428 }
429
430 __DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
431 {
432     struct v_file* opened_file;
433     int errno = __vfs_do_open(&opened_file, path, options), fd;
434
435     if (!errno && !(errno = vfs_alloc_fdslot(&fd))) {
436         struct v_fd* fd_s = vzalloc(sizeof(*fd_s));
437         fd_s->file = opened_file;
438         fd_s->pos = opened_file->inode->fsize & -((options & FO_APPEND) != 0);
439         __current->fdtable->fds[fd] = fd_s;
440         return fd;
441     }
442
443     __current->k_status = errno;
444     return SYSCALL_ESTATUS(errno);
445 }
446
447 #define GET_FD(fd, fd_s)                                                       \
448     (fd >= 0 && fd < VFS_MAX_FD && (fd_s = __current->fdtable->fds[fd]))
449
450 __DEFINE_LXSYSCALL1(int, close, int, fd)
451 {
452     struct v_fd* fd_s;
453     int errno;
454     if (!GET_FD(fd, fd_s)) {
455         errno = EBADF;
456     } else if (!(errno = vfs_close(fd_s->file))) {
457         vfree(fd_s);
458         __current->fdtable->fds[fd] = 0;
459     }
460
461     __current->k_status = errno;
462
463     return SYSCALL_ESTATUS(errno);
464 }
465
466 void
467 __vfs_readdir_callback(struct dir_context* dctx,
468                        const char* name,
469                        const int len,
470                        const int dtype)
471 {
472     struct dirent* dent = (struct dirent*)dctx->cb_data;
473     strncpy(dent->d_name, name, DIRENT_NAME_MAX_LEN);
474     dent->d_nlen = len;
475     dent->d_type = dtype;
476 }
477
478 __DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
479 {
480     struct v_fd* fd_s;
481     int errno;
482     if (!GET_FD(fd, fd_s)) {
483         errno = EBADF;
484     } else if (!(fd_s->file->inode->itype & VFS_INODE_TYPE_DIR)) {
485         errno = ENOTDIR;
486     } else {
487         struct dir_context dctx =
488           (struct dir_context){ .cb_data = dent,
489                                 .index = dent->d_offset,
490                                 .read_complete_callback =
491                                   __vfs_readdir_callback };
492         if (dent->d_offset == 0) {
493             __vfs_readdir_callback(&dctx, vfs_dot.value, vfs_dot.len, 0);
494         } else if (dent->d_offset == 1) {
495             __vfs_readdir_callback(&dctx, vfs_ddot.value, vfs_ddot.len, 0);
496         } else {
497             dctx.index -= 2;
498             if ((errno = fd_s->file->ops.readdir(fd_s->file, &dctx))) {
499                 goto done;
500             }
501         }
502         errno = 0;
503         dent->d_offset++;
504     }
505
506 done:
507     __current->k_status = errno;
508     return SYSCALL_ESTATUS(errno);
509 }
510
511 __DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
512 {
513     struct v_dnode *parent, *dir;
514     struct hstr component = HSTR(valloc(VFS_NAME_MAXLEN), 0);
515     int errno = vfs_walk(NULL, path, &parent, &component, VFS_WALK_PARENT);
516     if (errno) {
517         goto done;
518     }
519
520     if ((parent->super_block->fs->types & FSTYPE_ROFS)) {
521         errno = ENOTSUP;
522     } else if (!parent->inode->ops.mkdir) {
523         errno = ENOTSUP;
524     } else if (!(parent->inode->itype & VFS_INODE_TYPE_DIR)) {
525         errno = ENOTDIR;
526     } else {
527         dir = vfs_d_alloc();
528         dir->name = component;
529         if (!(errno = parent->inode->ops.mkdir(parent->inode, dir))) {
530             llist_append(&parent->children, &dir->siblings);
531         } else {
532             vfs_d_free(dir);
533             vfree(component.value);
534         }
535     }
536
537 done:
538     __current->k_status = errno;
539     return SYSCALL_ESTATUS(errno);
540 }
541
542 __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
543 {
544     int errno = 0;
545     struct v_fd* fd_s;
546     if (!GET_FD(fd, fd_s)) {
547         errno = EBADF;
548     } else {
549         struct v_file* file = fd_s->file;
550         file->f_pos = fd_s->pos;
551         if ((errno = file->ops.read(file, buf, count)) >= 0) {
552             fd_s->pos += errno;
553         }
554     }
555
556     __current->k_status = errno;
557     return SYSCALL_ESTATUS(errno);
558 }
559
560 __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
561 {
562     int errno = 0;
563     struct v_fd* fd_s;
564     if (!GET_FD(fd, fd_s)) {
565         errno = EBADF;
566     } else {
567         struct v_file* file = fd_s->file;
568         file->f_pos = fd_s->pos;
569         if ((errno = file->ops.write(file, buf, count)) >= 0) {
570             fd_s->pos += errno;
571         }
572     }
573
574     __current->k_status = errno;
575     return SYSCALL_ESTATUS(errno);
576 }
577
578 __DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
579 {
580     int errno = 0;
581     struct v_fd* fd_s;
582     if (!GET_FD(fd, fd_s)) {
583         errno = EBADF;
584     } else {
585         size_t fpos = fd_s->file->f_pos;
586         switch (options) {
587             case FSEEK_CUR:
588                 fpos = (size_t)((int)fd_s->file->f_pos + offset);
589                 break;
590             case FSEEK_END:
591                 fpos = (size_t)((int)fd_s->file->inode->fsize + offset);
592                 break;
593             case FSEEK_SET:
594                 fpos = offset;
595                 break;
596
597             default:
598                 break;
599         }
600         fd_s->pos = fpos;
601     }
602
603     __current->k_status = errno;
604     return SYSCALL_ESTATUS(errno);
605 }
606
607 int
608 vfs_readlink(struct v_dnode* dnode, char* buf, size_t size, int depth)
609 {
610     if (!dnode) {
611         return 0;
612     }
613
614     if (depth > 64) {
615         return ELOOP;
616     }
617
618     size_t len = vfs_readlink(dnode->parent, buf, size, depth + 1);
619
620     if (len >= size) {
621         return len;
622     }
623
624     size_t cpy_size = MIN(dnode->name.len, size - len);
625     strncpy(buf + len, dnode->name.value, cpy_size);
626     len += cpy_size;
627
628     if (len < size) {
629         buf[len++] = PATH_DELIM;
630     }
631
632     return len;
633 }
634
635 __DEFINE_LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
636 {
637     int errno;
638     struct v_dnode* dnode;
639     if (!(errno = vfs_walk(NULL, path, &dnode, NULL, 0))) {
640         errno = vfs_readlink(dnode, buf, size, 0);
641     }
642
643     if (errno >= 0) {
644         return errno;
645     }
646
647     __current->k_status = errno;
648     return SYSCALL_ESTATUS(errno);
649 }
650
651 __DEFINE_LXSYSCALL4(int,
652                     readlinkat,
653                     int,
654                     dirfd,
655                     const char*,
656                     pathname,
657                     char*,
658                     buf,
659                     size_t,
660                     size)
661 {
662     int errno;
663     struct v_fd* fd_s;
664     if (!GET_FD(dirfd, fd_s)) {
665         errno = EBADF;
666     } else {
667         struct v_dnode* dnode;
668         if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) {
669             errno = vfs_readlink(fd_s->file->dnode, buf, size, 0);
670         }
671     }
672
673     if (errno >= 0) {
674         return errno;
675     }
676
677     __current->k_status = errno;
678     return SYSCALL_ESTATUS(errno);
679 }
680
681 __DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname)
682 {
683     int errno;
684     struct v_dnode* dnode;
685     if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
686         goto done;
687     }
688     if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
689         errno = EROFS;
690         goto done;
691     }
692
693     if (dnode->inode->open_count) {
694         errno = EBUSY;
695         goto done;
696     }
697
698     if (dnode->inode->itype == VFS_INODE_TYPE_DIR) {
699         errno = dnode->inode->ops.rmdir(dnode->inode);
700     } else {
701         errno = ENOTDIR;
702     }
703
704 done:
705     __current->k_status = errno;
706     return SYSCALL_ESTATUS(errno);
707 }
708
709 int
710 __vfs_do_unlink(struct v_inode* inode)
711 {
712     int errno;
713     if (inode->open_count) {
714         errno = EBUSY;
715     } else if (inode->itype != VFS_INODE_TYPE_DIR) {
716         // TODO handle symbolic link and type other than regular file
717         errno = inode->ops.unlink(inode);
718     } else {
719         errno = EISDIR;
720     }
721
722     return errno;
723 }
724
725 __DEFINE_LXSYSCALL1(int, unlink, const char*, pathname)
726 {
727     int errno;
728     struct v_dnode* dnode;
729     if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
730         goto done;
731     }
732     if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
733         errno = EROFS;
734         goto done;
735     }
736
737     errno = __vfs_do_unlink(dnode->inode);
738
739 done:
740     __current->k_status = errno;
741     return SYSCALL_ESTATUS(errno);
742 }
743
744 __DEFINE_LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
745 {
746     int errno;
747     struct v_fd* fd_s;
748     if (!GET_FD(fd, fd_s)) {
749         errno = EBADF;
750     } else {
751         struct v_dnode* dnode;
752         if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) {
753             errno = __vfs_do_unlink(dnode->inode);
754         }
755     }
756
757 done:
758     __current->k_status = errno;
759     return SYSCALL_ESTATUS(errno);
760 }