feat: implement readlink(2) readlinkat(2)
[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
299     int errno = dnode->inode->ops.open(dnode->inode, vfile);
300     if (errno) {
301         cake_release(file_pile, vfile);
302     } else {
303         *file = vfile;
304     }
305     return errno;
306 }
307
308 int
309 vfs_close(struct v_file* file)
310 {
311     if (!file->ops.close) {
312         return ENOTSUP;
313     }
314
315     int errno = file->ops.close(file);
316     if (!errno) {
317         cake_release(file_pile, file);
318     }
319     return errno;
320 }
321
322 int
323 vfs_fsync(struct v_file* file)
324 {
325     int errno = ENOTSUP;
326     if (file->ops.sync) {
327         errno = file->ops.sync(file);
328     }
329     if (!errno && file->inode->ops.sync) {
330         return file->inode->ops.sync(file->inode);
331     }
332     return errno;
333 }
334
335 int
336 vfs_alloc_fdslot(int* fd)
337 {
338     for (size_t i = 0; i < VFS_MAX_FD; i++) {
339         if (!__current->fdtable->fds[i]) {
340             *fd = i;
341             return 0;
342         }
343     }
344     return EMFILE;
345 }
346
347 struct v_superblock*
348 vfs_sb_alloc()
349 {
350     struct v_superblock* sb = cake_grab(superblock_pile);
351     memset(sb, 0, sizeof(*sb));
352     llist_init_head(&sb->sb_list);
353     return sb;
354 }
355
356 void
357 vfs_sb_free(struct v_superblock* sb)
358 {
359     cake_release(superblock_pile, sb);
360 }
361
362 struct v_dnode*
363 vfs_d_alloc()
364 {
365     struct v_dnode* dnode = cake_grab(dnode_pile);
366     memset(dnode, 0, sizeof(*dnode));
367     llist_init_head(&dnode->children);
368     dnode->name = vfs_empty;
369     return dnode;
370 }
371
372 void
373 vfs_d_free(struct v_dnode* dnode)
374 {
375     if (dnode->ops.destruct) {
376         dnode->ops.destruct(dnode);
377     }
378     cake_release(dnode_pile, dnode);
379 }
380
381 struct v_inode*
382 vfs_i_alloc()
383 {
384     struct v_inode* inode = cake_grab(inode_pile);
385     memset(inode, 0, sizeof(*inode));
386
387     return inode;
388 }
389
390 void
391 vfs_i_free(struct v_inode* inode)
392 {
393     cake_release(inode_pile, inode);
394 }
395
396 int
397 __vfs_do_open(struct v_file** file_out, const char* path, int options)
398 {
399     char name_str[VFS_NAME_MAXLEN];
400     struct hstr name = HSTR(name_str, 0);
401     struct v_dnode *dentry, *file;
402     int errno;
403     if ((errno = vfs_walk(NULL, path, &dentry, &name, VFS_WALK_PARENT))) {
404         return ENOENT;
405     }
406
407     vfs_walk(dentry, name.value, &file, NULL, 0);
408
409     struct v_file* opened_file = 0;
410     if (!file) {
411         if ((options & FO_CREATE)) {
412             errno = dentry->inode->ops.create(dentry->inode, opened_file);
413         } else {
414             errno = ENOENT;
415         }
416     } else {
417         errno = vfs_open(file, &opened_file);
418     }
419
420     *file_out = opened_file;
421     return errno;
422 }
423
424 __DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
425 {
426     struct v_file* opened_file;
427     int errno = __vfs_do_open(&opened_file, path, options), fd;
428
429     if (!errno && !(errno = vfs_alloc_fdslot(&fd))) {
430         struct v_fd* fd_s = vzalloc(sizeof(*fd_s));
431         fd_s->file = opened_file;
432         fd_s->pos = opened_file->inode->fsize & -((options & FO_APPEND) != 0);
433         __current->fdtable->fds[fd] = fd_s;
434         return fd;
435     }
436
437     __current->k_status = errno;
438     return SYSCALL_ESTATUS(errno);
439 }
440
441 #define GET_FD(fd, fd_s)                                                       \
442     (fd >= 0 && fd < VFS_MAX_FD && (fd_s = __current->fdtable->fds[fd]))
443
444 __DEFINE_LXSYSCALL1(int, close, int, fd)
445 {
446     struct v_fd* fd_s;
447     int errno;
448     if (!GET_FD(fd, fd_s)) {
449         errno = EBADF;
450     } else if (!(errno = vfs_close(fd_s->file))) {
451         vfree(fd_s);
452         __current->fdtable->fds[fd] = 0;
453     }
454
455     __current->k_status = errno;
456
457     return SYSCALL_ESTATUS(errno);
458 }
459
460 void
461 __vfs_readdir_callback(struct dir_context* dctx,
462                        const char* name,
463                        const int len,
464                        const int dtype)
465 {
466     struct dirent* dent = (struct dirent*)dctx->cb_data;
467     strncpy(dent->d_name, name, DIRENT_NAME_MAX_LEN);
468     dent->d_nlen = len;
469     dent->d_type = dtype;
470 }
471
472 __DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
473 {
474     struct v_fd* fd_s;
475     int errno;
476     if (!GET_FD(fd, fd_s)) {
477         errno = EBADF;
478     } else if (!(fd_s->file->inode->itype & VFS_INODE_TYPE_DIR)) {
479         errno = ENOTDIR;
480     } else {
481         struct dir_context dctx =
482           (struct dir_context){ .cb_data = dent,
483                                 .index = dent->d_offset,
484                                 .read_complete_callback =
485                                   __vfs_readdir_callback };
486         if (dent->d_offset == 0) {
487             __vfs_readdir_callback(&dctx, vfs_dot.value, vfs_dot.len, 0);
488         } else if (dent->d_offset == 1) {
489             __vfs_readdir_callback(&dctx, vfs_ddot.value, vfs_ddot.len, 0);
490         } else {
491             dctx.index -= 2;
492             if ((errno = fd_s->file->ops.readdir(fd_s->file, &dctx))) {
493                 goto done;
494             }
495         }
496         errno = 0;
497         dent->d_offset++;
498     }
499
500 done:
501     __current->k_status = errno;
502     return SYSCALL_ESTATUS(errno);
503 }
504
505 __DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
506 {
507     struct v_dnode *parent, *dir;
508     struct hstr component = HSTR(valloc(VFS_NAME_MAXLEN), 0);
509     int errno = vfs_walk(NULL, path, &parent, &component, VFS_WALK_PARENT);
510     if (errno) {
511         goto done;
512     }
513
514     if ((parent->super_block->fs->types & FSTYPE_ROFS)) {
515         errno = ENOTSUP;
516     } else if (!parent->inode->ops.mkdir) {
517         errno = ENOTSUP;
518     } else if (!(parent->inode->itype & VFS_INODE_TYPE_DIR)) {
519         errno = ENOTDIR;
520     } else {
521         dir = vfs_d_alloc();
522         dir->name = component;
523         if (!(errno = parent->inode->ops.mkdir(parent->inode, dir))) {
524             llist_append(&parent->children, &dir->siblings);
525         } else {
526             vfs_d_free(dir);
527             vfree(component.value);
528         }
529     }
530
531 done:
532     __current->k_status = errno;
533     return SYSCALL_ESTATUS(errno);
534 }
535
536 __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
537 {
538     int errno = 0;
539     struct v_fd* fd_s;
540     if (!GET_FD(fd, fd_s)) {
541         errno = EBADF;
542     } else {
543         struct v_file* file = fd_s->file;
544         file->f_pos = fd_s->pos;
545         if ((errno = file->ops.read(file, buf, count)) >= 0) {
546             fd_s->pos += errno;
547         }
548     }
549
550     __current->k_status = errno;
551     return SYSCALL_ESTATUS(errno);
552 }
553
554 __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
555 {
556     int errno = 0;
557     struct v_fd* fd_s;
558     if (!GET_FD(fd, fd_s)) {
559         errno = EBADF;
560     } else {
561         struct v_file* file = fd_s->file;
562         file->f_pos = fd_s->pos;
563         if ((errno = file->ops.write(file, buf, count)) >= 0) {
564             fd_s->pos += errno;
565         }
566     }
567
568     __current->k_status = errno;
569     return SYSCALL_ESTATUS(errno);
570 }
571
572 __DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
573 {
574     int errno = 0;
575     struct v_fd* fd_s;
576     if (!GET_FD(fd, fd_s)) {
577         errno = EBADF;
578     } else {
579         size_t fpos = fd_s->file->f_pos;
580         switch (options) {
581             case FSEEK_CUR:
582                 fpos = (size_t)((int)fd_s->file->f_pos + offset);
583                 break;
584             case FSEEK_END:
585                 fpos = (size_t)((int)fd_s->file->inode->fsize + offset);
586                 break;
587             case FSEEK_SET:
588                 fpos = offset;
589                 break;
590
591             default:
592                 break;
593         }
594         fd_s->pos = fpos;
595     }
596
597     __current->k_status = errno;
598     return SYSCALL_ESTATUS(errno);
599 }
600
601 int
602 vfs_readlink(struct v_dnode* dnode, char* buf, size_t size, int depth)
603 {
604     if (!dnode) {
605         return 0;
606     }
607
608     if (depth > 64) {
609         return ELOOP;
610     }
611
612     size_t len = vfs_readlink(dnode->parent, buf, size, depth + 1);
613
614     if (len >= size) {
615         return len;
616     }
617
618     size_t cpy_size = MIN(dnode->name.len, size - len);
619     strncpy(buf + len, dnode->name.value, cpy_size);
620     len += cpy_size;
621
622     if (len < size) {
623         buf[len++] = PATH_DELIM;
624     }
625
626     return len;
627 }
628
629 __DEFINE_LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
630 {
631     int errno;
632     struct v_dnode* dnode;
633     if (!(errno = vfs_walk(NULL, path, &dnode, NULL, 0))) {
634         errno = vfs_readlink(dnode, buf, size, 0);
635     }
636
637     if (errno >= 0) {
638         return errno;
639     }
640
641     __current->k_status = errno;
642     return SYSCALL_ESTATUS(errno);
643 }
644
645 __DEFINE_LXSYSCALL4(int,
646                     readlinkat,
647                     int,
648                     dirfd,
649                     const char*,
650                     pathname,
651                     char*,
652                     buf,
653                     size_t,
654                     size)
655 {
656     int errno;
657     struct v_fd* fd_s;
658     if (!GET_FD(dirfd, fd_s)) {
659         errno = EBADF;
660     } else {
661         struct v_dnode* dnode;
662         if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) {
663             errno = vfs_readlink(fd_s->file->dnode, buf, size, 0);
664         }
665     }
666
667     if (errno >= 0) {
668         return errno;
669     }
670
671     __current->k_status = errno;
672     return SYSCALL_ESTATUS(errno);
673 }