feat: rename(2), mount(2) and unmount(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 #include <lunaix/fs/twifs.h>
24
25 #define PATH_DELIM '/'
26 #define DNODE_HASHTABLE_BITS 10
27 #define DNODE_HASHTABLE_SIZE (1 << DNODE_HASHTABLE_BITS)
28 #define DNODE_HASH_MASK (DNODE_HASHTABLE_SIZE - 1)
29 #define DNODE_HASHBITS (32 - DNODE_HASHTABLE_BITS)
30
31 #define lock_inode(inode) mutex_lock(&inode->lock)
32 #define unlock_inode(inode) mutex_unlock(&inode->lock)
33
34 #define lock_dnode(dnode) mutex_lock(&dnode->lock)
35 #define unlock_dnode(dnode) mutex_unlock(&dnode->lock)
36
37 static struct cake_pile* dnode_pile;
38 static struct cake_pile* inode_pile;
39 static struct cake_pile* file_pile;
40 static struct cake_pile* superblock_pile;
41 static struct cake_pile* fd_pile;
42
43 static struct v_superblock* root_sb;
44 static struct hbucket* dnode_cache;
45
46 static int fs_id = 0;
47
48 struct hstr vfs_ddot = HSTR("..", 2);
49 struct hstr vfs_dot = HSTR(".", 1);
50 struct hstr vfs_empty = HSTR("", 0);
51
52 struct v_dnode*
53 vfs_d_alloc();
54
55 void
56 vfs_d_free(struct v_dnode* dnode);
57
58 struct v_superblock*
59 vfs_sb_alloc();
60
61 void
62 vfs_sb_free(struct v_superblock* sb);
63
64 void
65 vfs_init()
66 {
67     // 为他们专门创建一个蛋糕堆,而不使用valloc,这样我们可以最小化内碎片的产生
68     dnode_pile = cake_new_pile("dnode_cache", sizeof(struct v_dnode), 1, 0);
69     inode_pile = cake_new_pile("inode_cache", sizeof(struct v_inode), 1, 0);
70     file_pile = cake_new_pile("file_cache", sizeof(struct v_file), 1, 0);
71     fd_pile = cake_new_pile("fd_cache", sizeof(struct v_fd), 1, 0);
72     superblock_pile =
73       cake_new_pile("sb_cache", sizeof(struct v_superblock), 1, 0);
74
75     dnode_cache = vzalloc(DNODE_HASHTABLE_SIZE * sizeof(struct hbucket));
76
77     hstr_rehash(&vfs_ddot, HSTR_FULL_HASH);
78     hstr_rehash(&vfs_dot, HSTR_FULL_HASH);
79
80     // 创建一个根superblock,用来蕴含我们的根目录。
81     root_sb = vfs_sb_alloc();
82     root_sb->root = vfs_d_alloc();
83     root_sb->root->inode = vfs_i_alloc();
84 }
85
86 inline struct hbucket*
87 __dcache_hash(struct v_dnode* parent, uint32_t* hash)
88 {
89     uint32_t _hash = *hash;
90     // 与parent的指针值做加法,来减小碰撞的可能性。
91     _hash += (uint32_t)parent;
92     // 确保低位更加随机
93     _hash = _hash ^ (_hash >> DNODE_HASHBITS);
94     *hash = _hash;
95     return &dnode_cache[_hash & DNODE_HASH_MASK];
96 }
97
98 struct v_dnode*
99 vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str)
100 {
101     if (!str->len || HSTR_EQ(str, &vfs_dot))
102         return parent;
103
104     if (HSTR_EQ(str, &vfs_ddot)) {
105         return parent->parent ? parent->parent : parent;
106     }
107
108     uint32_t hash = str->hash;
109     struct hbucket* slot = __dcache_hash(parent, &hash);
110
111     struct v_dnode *pos, *n;
112     hashtable_bucket_foreach(slot, pos, n, hash_list)
113     {
114         if (pos->name.hash == hash) {
115             return pos;
116         }
117     }
118     return NULL;
119 }
120
121 void
122 vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode)
123 {
124     struct hbucket* bucket = __dcache_hash(parent, &dnode->name.hash);
125     hlist_add(&bucket->head, &dnode->hash_list);
126 }
127
128 void
129 vfs_dcache_rehash(struct v_dnode* parent, struct v_dnode* dnode)
130 {
131     hlist_delete(&dnode->hash_list);
132     hstr_rehash(&dnode->name, HSTR_FULL_HASH);
133     vfs_dcache_add(parent, dnode);
134 }
135
136 int
137 __vfs_walk(struct v_dnode* start,
138            const char* path,
139            struct v_dnode** dentry,
140            struct hstr* component,
141            int walk_options)
142 {
143     int errno = 0;
144     int i = 0, j = 0;
145
146     if (path[0] == PATH_DELIM || !start) {
147         if ((walk_options & VFS_WALK_FSRELATIVE) && start) {
148             start = start->super_block->root;
149         } else {
150             start = root_sb->root;
151         }
152         i++;
153     }
154
155     struct v_dnode* dnode;
156     struct v_dnode* current_level = start;
157
158     char name_content[VFS_NAME_MAXLEN];
159     struct hstr name = HSTR(name_content, 0);
160
161     char current = path[i++], lookahead;
162     while (current) {
163         lookahead = path[i++];
164         if (current != PATH_DELIM) {
165             if (j >= VFS_NAME_MAXLEN - 1) {
166                 return ENAMETOOLONG;
167             }
168             if (!VFS_VALID_CHAR(current)) {
169                 return EINVAL;
170             }
171             name_content[j++] = current;
172             if (lookahead) {
173                 goto cont;
174             }
175         }
176
177         // handling cases like /^.*(\/+).*$/
178         if (lookahead == PATH_DELIM) {
179             goto cont;
180         }
181
182         lock_dnode(current_level);
183
184         name_content[j] = 0;
185         name.len = j;
186         hstr_rehash(&name, HSTR_FULL_HASH);
187
188         if (!lookahead && (walk_options & VFS_WALK_PARENT)) {
189             if (component) {
190                 component->hash = name.hash;
191                 component->len = j;
192                 strcpy(component->value, name_content);
193             }
194             unlock_dnode(current_level);
195             break;
196         }
197
198         dnode = vfs_dcache_lookup(current_level, &name);
199
200         if (!dnode) {
201             dnode = vfs_d_alloc();
202
203             hstrcpy(&dnode->name, &name);
204
205             lock_inode(current_level->inode);
206
207             errno =
208               current_level->inode->ops.dir_lookup(current_level->inode, dnode);
209
210             if (errno == ENOENT && (walk_options & VFS_WALK_MKPARENT)) {
211                 if (!current_level->inode->ops.mkdir) {
212                     errno = ENOTSUP;
213                 } else {
214                     errno = current_level->inode->ops.mkdir(
215                       current_level->inode, dnode);
216                 }
217             }
218
219             unlock_inode(current_level->inode);
220
221             if (errno) {
222                 unlock_dnode(current_level);
223                 vfree(dnode->name.value);
224                 goto error;
225             }
226
227             vfs_dcache_add(current_level, dnode);
228
229             dnode->parent = current_level;
230             llist_append(&current_level->children, &dnode->siblings);
231         }
232
233         unlock_dnode(current_level);
234
235         j = 0;
236         current_level = dnode;
237     cont:
238         current = lookahead;
239     };
240
241     *dentry = current_level;
242     return 0;
243
244 error:
245     vfs_d_free(dnode);
246     *dentry = NULL;
247     return errno;
248 }
249
250 #define VFS_MAX_SYMLINK 16
251
252 int
253 vfs_walk(struct v_dnode* start,
254          const char* path,
255          struct v_dnode** dentry,
256          struct hstr* component,
257          int options)
258 {
259     struct v_dnode* interim;
260     const char* pathname = path;
261     int errno = __vfs_walk(start, path, &interim, component, options);
262     int counter = 0;
263
264     while (!errno) {
265         if (counter >= VFS_MAX_SYMLINK) {
266             errno = ELOOP;
267             continue;
268         }
269         if ((interim->inode->itype & VFS_IFSYMLINK) &&
270             !(options & VFS_WALK_NOFOLLOW) &&
271             interim->inode->ops.read_symlink) {
272             errno = interim->inode->ops.read_symlink(interim->inode, &pathname);
273             if (errno) {
274                 break;
275             }
276         } else {
277             break;
278         }
279         errno = __vfs_walk(start, pathname, &interim, component, options);
280         counter++;
281     }
282
283     *dentry = errno ? 0 : interim;
284
285     return errno;
286 }
287
288 int
289 vfs_mount(const char* target, const char* fs_name, struct device* device)
290 {
291     int errno;
292     struct v_dnode* mnt;
293
294     if (!(errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
295         errno = vfs_mount_at(fs_name, device, mnt);
296     }
297
298     return errno;
299 }
300
301 int
302 vfs_unmount(const char* target)
303 {
304     int errno;
305     struct v_dnode* mnt;
306
307     if (!(errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
308         errno = vfs_unmount_at(mnt);
309     }
310
311     return errno;
312 }
313
314 int
315 vfs_mount_at(const char* fs_name,
316              struct device* device,
317              struct v_dnode* mnt_point)
318 {
319     if (!(mnt_point->inode->itype & VFS_IFDIR)) {
320         return ENOTDIR;
321     }
322
323     struct filesystem* fs = fsm_get(fs_name);
324     if (!fs) {
325         return ENODEV;
326     }
327
328     struct v_superblock* sb = vfs_sb_alloc();
329     sb->dev = device;
330     sb->fs_id = fs_id++;
331
332     int errno = 0;
333     if (!(errno = fs->mount(sb, mnt_point))) {
334         sb->fs = fs;
335         sb->root = mnt_point;
336         mnt_point->super_block = sb;
337         llist_append(&root_sb->sb_list, &sb->sb_list);
338     }
339
340     return errno;
341 }
342
343 int
344 vfs_unmount_at(struct v_dnode* mnt_point)
345 {
346     // FIXME mnt point check & deal with the detached dcache subtree
347     int errno = 0;
348     struct v_superblock* sb = mnt_point->super_block;
349     if (!sb) {
350         return EINVAL;
351     }
352     if (!(errno = sb->fs->unmount(sb))) {
353         struct v_dnode* fs_root = sb->root;
354         llist_delete(&fs_root->siblings);
355         llist_delete(&sb->sb_list);
356         hlist_delete(&fs_root->hash_list);
357         vfs_sb_free(sb);
358         vfs_d_free(fs_root);
359     }
360     return errno;
361 }
362
363 int
364 vfs_open(struct v_dnode* dnode, struct v_file** file)
365 {
366     if (!dnode->inode || !dnode->inode->ops.open) {
367         return ENOTSUP;
368     }
369
370     struct v_inode* inode = dnode->inode;
371     struct v_file* vfile = cake_grab(file_pile);
372     memset(vfile, 0, sizeof(*vfile));
373
374     vfile->dnode = dnode;
375     vfile->inode = inode;
376     vfile->ref_count = ATOMIC_VAR_INIT(1);
377     vfile->ops = inode->default_fops;
378
379     if ((inode->itype & VFS_IFFILE) && !inode->pg_cache) {
380         struct pcache* pcache = vzalloc(sizeof(struct pcache));
381         pcache_init(pcache);
382         pcache->master = inode;
383         inode->pg_cache = pcache;
384     }
385
386     int errno = inode->ops.open(inode, vfile);
387     if (errno) {
388         cake_release(file_pile, vfile);
389     } else {
390         atomic_fetch_add(&dnode->ref_count, 1);
391         inode->open_count++;
392
393         *file = vfile;
394     }
395
396     return errno;
397 }
398
399 int
400 vfs_link(struct v_dnode* to_link, struct v_dnode* name)
401 {
402     int errno;
403
404     lock_inode(to_link->inode);
405     if (to_link->super_block->root != name->super_block->root) {
406         errno = EXDEV;
407     } else if (!to_link->inode->ops.link) {
408         errno = ENOTSUP;
409     } else if (!(errno = to_link->inode->ops.link(to_link->inode, name))) {
410         name->inode = to_link->inode;
411         atomic_fetch_add(&to_link->inode->link_count, 1);
412     }
413     unlock_inode(to_link->inode);
414
415     return errno;
416 }
417
418 int
419 vfs_close(struct v_file* file)
420 {
421     int errno = 0;
422     if (!file->ops.close || !(errno = file->ops.close(file))) {
423         atomic_fetch_sub(&file->dnode->ref_count, 1);
424         file->inode->open_count--;
425
426         pcache_commit_all(file->inode);
427         cake_release(file_pile, file);
428     }
429     return errno;
430 }
431
432 int
433 vfs_fsync(struct v_file* file)
434 {
435     lock_inode(file->inode);
436
437     int errno = ENOTSUP;
438     pcache_commit_all(file->inode);
439     if (file->ops.sync) {
440         errno = file->ops.sync(file->inode);
441     }
442
443     unlock_inode(file->inode);
444
445     return errno;
446 }
447
448 int
449 vfs_alloc_fdslot(int* fd)
450 {
451     for (size_t i = 0; i < VFS_MAX_FD; i++) {
452         if (!__current->fdtable->fds[i]) {
453             *fd = i;
454             return 0;
455         }
456     }
457     return EMFILE;
458 }
459
460 struct v_superblock*
461 vfs_sb_alloc()
462 {
463     struct v_superblock* sb = cake_grab(superblock_pile);
464     memset(sb, 0, sizeof(*sb));
465     llist_init_head(&sb->sb_list);
466     return sb;
467 }
468
469 void
470 vfs_sb_free(struct v_superblock* sb)
471 {
472     cake_release(superblock_pile, sb);
473 }
474
475 struct v_dnode*
476 vfs_d_alloc()
477 {
478     struct v_dnode* dnode = cake_grab(dnode_pile);
479     memset(dnode, 0, sizeof(*dnode));
480     llist_init_head(&dnode->children);
481     llist_init_head(&dnode->siblings);
482     mutex_init(&dnode->lock);
483
484     dnode->ref_count = ATOMIC_VAR_INIT(0);
485     dnode->name = HHSTR(vzalloc(VFS_NAME_MAXLEN), 0, 0);
486
487     return dnode;
488 }
489
490 void
491 vfs_d_free(struct v_dnode* dnode)
492 {
493     if (dnode->inode && dnode->inode->link_count) {
494         dnode->inode->link_count--;
495     }
496     vfree(dnode->name.value);
497     cake_release(dnode_pile, dnode);
498 }
499
500 struct v_inode*
501 vfs_i_alloc()
502 {
503     struct v_inode* inode = cake_grab(inode_pile);
504     memset(inode, 0, sizeof(*inode));
505     inode->link_count = 1;
506     mutex_init(&inode->lock);
507
508     return inode;
509 }
510
511 void
512 vfs_i_free(struct v_inode* inode)
513 {
514     cake_release(inode_pile, inode);
515 }
516
517 /* ---- System call definition and support ---- */
518
519 #define FLOCATE_CREATE_EMPTY 1
520
521 #define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
522 #define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; })
523
524 #define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
525
526 int
527 __vfs_getfd(int fd, struct v_fd** fd_s)
528 {
529     if (TEST_FD(fd) && (*fd_s = __current->fdtable->fds[fd])) {
530         return 0;
531     }
532     return EBADF;
533 }
534
535 int
536 __vfs_try_locate_file(const char* path,
537                       struct v_dnode** fdir,
538                       struct v_dnode** file,
539                       int options)
540 {
541     char name_str[VFS_NAME_MAXLEN];
542     struct hstr name = HSTR(name_str, 0);
543     int errno;
544     if ((errno =
545            vfs_walk(__current->cwd, path, fdir, &name, VFS_WALK_PARENT))) {
546         return errno;
547     }
548
549     errno = vfs_walk(*fdir, name.value, file, NULL, 0);
550     if (errno != ENOENT || !(options & FLOCATE_CREATE_EMPTY)) {
551         return errno;
552     }
553
554     struct v_dnode* parent = *fdir;
555     struct v_dnode* file_new = vfs_d_alloc();
556     hstrcpy(&file_new->name, &name);
557
558     if (!(errno = parent->inode->ops.create(parent->inode, file_new))) {
559         *file = file_new;
560
561         vfs_dcache_add(parent, file_new);
562         llist_append(&parent->children, &file_new->siblings);
563     } else {
564         vfs_d_free(file_new);
565     }
566
567     return errno;
568 }
569
570 int
571 vfs_do_open(const char* path, int options)
572 {
573     int errno, fd;
574     struct v_dnode *dentry, *file;
575     struct v_file* ofile = 0;
576
577     errno = __vfs_try_locate_file(
578       path, &dentry, &file, (options & FO_CREATE) ? FLOCATE_CREATE_EMPTY : 0);
579
580     if (errno || (errno = vfs_open(file, &ofile))) {
581         return errno;
582     }
583
584     struct v_inode* o_inode = ofile->inode;
585     if (!(o_inode->itype & VFS_IFSEQDEV) && !(options & FO_DIRECT)) {
586         // XXX Change here accordingly when signature of pcache_r/w changed.
587         ofile->ops.read = pcache_read;
588         ofile->ops.write = pcache_write;
589     }
590
591     if (!errno && !(errno = vfs_alloc_fdslot(&fd))) {
592         struct v_fd* fd_s = vzalloc(sizeof(*fd_s));
593         ofile->f_pos = ofile->inode->fsize & -((options & FO_APPEND) != 0);
594         fd_s->file = ofile;
595         fd_s->flags = options;
596         __current->fdtable->fds[fd] = fd_s;
597         return fd;
598     }
599
600     return errno;
601 }
602
603 __DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
604 {
605     int errno = vfs_do_open(path, options);
606     return DO_STATUS_OR_RETURN(errno);
607 }
608
609 __DEFINE_LXSYSCALL1(int, close, int, fd)
610 {
611     struct v_fd* fd_s;
612     int errno = 0;
613     if ((errno = __vfs_getfd(fd, &fd_s))) {
614         goto done_err;
615     }
616
617     if (fd_s->file->ref_count > 1) {
618         fd_s->file->ref_count--;
619     } else if ((errno = vfs_close(fd_s->file))) {
620         goto done_err;
621     }
622
623     vfree(fd_s);
624     __current->fdtable->fds[fd] = 0;
625
626 done_err:
627     return DO_STATUS(errno);
628 }
629
630 void
631 __vfs_readdir_callback(struct dir_context* dctx,
632                        const char* name,
633                        const int len,
634                        const int dtype)
635 {
636     struct dirent* dent = (struct dirent*)dctx->cb_data;
637     strncpy(dent->d_name, name, DIRENT_NAME_MAX_LEN);
638     dent->d_nlen = len;
639     dent->d_type = dtype;
640 }
641
642 __DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
643 {
644     struct v_fd* fd_s;
645     int errno;
646
647     if ((errno = __vfs_getfd(fd, &fd_s))) {
648         goto done;
649     }
650
651     struct v_inode* inode = fd_s->file->inode;
652
653     lock_inode(inode);
654
655     if (!(fd_s->file->inode->itype & VFS_IFDIR)) {
656         errno = ENOTDIR;
657     } else {
658         struct dir_context dctx =
659           (struct dir_context){ .cb_data = dent,
660                                 .index = dent->d_offset,
661                                 .read_complete_callback =
662                                   __vfs_readdir_callback };
663         if (dent->d_offset == 0) {
664             __vfs_readdir_callback(&dctx, vfs_dot.value, vfs_dot.len, 0);
665         } else if (dent->d_offset == 1) {
666             __vfs_readdir_callback(&dctx, vfs_ddot.value, vfs_ddot.len, 0);
667         } else {
668             dctx.index -= 2;
669             if ((errno = fd_s->file->ops.readdir(inode, &dctx))) {
670                 unlock_inode(inode);
671                 goto done;
672             }
673         }
674         errno = 0;
675         dent->d_offset++;
676     }
677
678     unlock_inode(inode);
679
680 done:
681     return DO_STATUS(errno);
682 }
683
684 __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
685 {
686     int errno = 0;
687     struct v_fd* fd_s;
688     if ((errno = __vfs_getfd(fd, &fd_s))) {
689         goto done;
690     }
691
692     struct v_file* file = fd_s->file;
693     if ((file->inode->itype & VFS_IFDIR)) {
694         errno = EISDIR;
695         goto done;
696     }
697
698     lock_inode(file->inode);
699
700     file->inode->atime = clock_unixtime();
701
702     __SYSCALL_INTERRUPTIBLE(
703       { errno = file->ops.read(file->inode, buf, count, file->f_pos); })
704
705     unlock_inode(file->inode);
706
707     if (errno > 0) {
708         file->f_pos += errno;
709         return errno;
710     }
711
712 done:
713     return DO_STATUS(errno);
714 }
715
716 __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
717 {
718     int errno = 0;
719     struct v_fd* fd_s;
720     if ((errno = __vfs_getfd(fd, &fd_s))) {
721         goto done;
722     }
723
724     struct v_file* file = fd_s->file;
725     if ((file->inode->itype & VFS_IFDIR)) {
726         errno = EISDIR;
727         goto done;
728     }
729
730     lock_inode(file->inode);
731
732     file->inode->mtime = clock_unixtime();
733
734     __SYSCALL_INTERRUPTIBLE(
735       { errno = file->ops.write(file->inode, buf, count, file->f_pos); })
736
737     unlock_inode(file->inode);
738
739     if (errno > 0) {
740         file->f_pos += errno;
741         return errno;
742     }
743
744 done:
745     return DO_STATUS(errno);
746 }
747
748 __DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
749 {
750     int errno = 0;
751     struct v_fd* fd_s;
752     if ((errno = __vfs_getfd(fd, &fd_s))) {
753         goto done;
754     }
755
756     struct v_file* file = fd_s->file;
757
758     lock_inode(file->inode);
759
760     size_t fpos = file->f_pos;
761     switch (options) {
762         case FSEEK_CUR:
763             fpos = (size_t)((int)file->f_pos + offset);
764             break;
765         case FSEEK_END:
766             fpos = (size_t)((int)file->inode->fsize + offset);
767             break;
768         case FSEEK_SET:
769             fpos = offset;
770             break;
771     }
772     if (!file->ops.seek || !(errno = file->ops.seek(file->inode, fpos))) {
773         file->f_pos = fpos;
774     }
775
776     unlock_inode(file->inode);
777
778 done:
779     return DO_STATUS(errno);
780 }
781
782 int
783 vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
784 {
785     if (!dnode) {
786         return 0;
787     }
788
789     if (depth > 64) {
790         return ELOOP;
791     }
792
793     size_t len = vfs_get_path(dnode->parent, buf, size, depth + 1);
794
795     if (len >= size) {
796         return len;
797     }
798
799     size_t cpy_size = MIN(dnode->name.len, size - len);
800     strncpy(buf + len, dnode->name.value, cpy_size);
801     len += cpy_size;
802
803     if (len < size) {
804         buf[len++] = PATH_DELIM;
805     }
806
807     return len;
808 }
809
810 int
811 vfs_readlink(struct v_dnode* dnode, char* buf, size_t size)
812 {
813     const char* link;
814     struct v_inode* inode = dnode->inode;
815     if (inode->ops.read_symlink) {
816         lock_inode(inode);
817
818         int errno = inode->ops.read_symlink(inode, &link);
819         strncpy(buf, link, size);
820
821         unlock_inode(inode);
822         return errno;
823     }
824     return 0;
825 }
826
827 __DEFINE_LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
828 {
829     int errno;
830     struct v_fd* fd_s;
831     if ((errno = __vfs_getfd(fd, &fd_s))) {
832         goto done;
833     }
834
835     struct v_dnode* dnode;
836     errno = vfs_get_path(fd_s->file->dnode, buf, size, 0);
837
838     if (errno >= 0) {
839         return errno;
840     }
841
842 done:
843     return DO_STATUS(errno);
844 }
845
846 __DEFINE_LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
847 {
848     int errno;
849     struct v_dnode* dnode;
850     if (!(errno =
851             vfs_walk(__current->cwd, path, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
852         errno = vfs_readlink(dnode, buf, size);
853     }
854
855     if (errno >= 0) {
856         return errno;
857     }
858
859     return DO_STATUS(errno);
860 }
861
862 __DEFINE_LXSYSCALL4(int,
863                     readlinkat,
864                     int,
865                     dirfd,
866                     const char*,
867                     pathname,
868                     char*,
869                     buf,
870                     size_t,
871                     size)
872 {
873     int errno;
874     struct v_fd* fd_s;
875     if ((errno = __vfs_getfd(dirfd, &fd_s))) {
876         goto done;
877     }
878
879     struct v_dnode* dnode;
880     if (!(errno = vfs_walk(
881             fd_s->file->dnode, pathname, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
882         errno = vfs_readlink(fd_s->file->dnode, buf, size);
883     }
884
885     if (errno >= 0) {
886         return errno;
887     }
888
889 done:
890     return DO_STATUS(errno);
891 }
892
893 /*
894     NOTE
895     When we perform operation that could affect the layout of
896     directory (i.e., rename, mkdir, rmdir). We must lock the parent dir
897     whenever possible. This will blocking any ongoing path walking to reach
898     it hence avoid any partial state.
899 */
900
901 __DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname)
902 {
903     int errno;
904     struct v_dnode* dnode;
905     if ((errno = vfs_walk(__current->cwd, pathname, &dnode, NULL, 0))) {
906         return DO_STATUS(errno);
907     }
908
909     lock_dnode(dnode);
910
911     if (dnode->parent)
912         lock_dnode(dnode->parent);
913
914     if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
915         errno = EROFS;
916         goto done;
917     }
918
919     if (dnode->ref_count || dnode->inode->open_count) {
920         errno = EBUSY;
921         goto done;
922     }
923
924     if (!llist_empty(&dnode->children)) {
925         errno = ENOTEMPTY;
926         goto done;
927     }
928
929     lock_inode(dnode->inode);
930
931     if ((dnode->inode->itype & VFS_IFDIR)) {
932         errno = dnode->inode->ops.rmdir(dnode->inode);
933         if (!errno) {
934             llist_delete(&dnode->siblings);
935             hlist_delete(&dnode->hash_list);
936             unlock_inode(dnode->inode);
937             vfs_d_free(dnode);
938
939             goto done;
940         }
941     } else {
942         errno = ENOTDIR;
943     }
944
945     unlock_inode(dnode->inode);
946
947 done:
948     unlock_dnode(dnode);
949     if (dnode->parent)
950         unlock_dnode(dnode->parent);
951     return DO_STATUS(errno);
952 }
953
954 __DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
955 {
956     struct v_dnode *parent, *dir = vfs_d_alloc();
957     int errno =
958       vfs_walk(__current->cwd, path, &parent, &dir->name, VFS_WALK_PARENT);
959     if (errno) {
960         goto done;
961     }
962
963     lock_dnode(parent);
964     lock_inode(parent->inode);
965
966     if ((parent->super_block->fs->types & FSTYPE_ROFS)) {
967         errno = ENOTSUP;
968     } else if (!parent->inode->ops.mkdir) {
969         errno = ENOTSUP;
970     } else if (!(parent->inode->itype & VFS_IFDIR)) {
971         errno = ENOTDIR;
972     } else if (!(errno = parent->inode->ops.mkdir(parent->inode, dir))) {
973         llist_append(&parent->children, &dir->siblings);
974         goto cleanup;
975     }
976
977     vfs_d_free(dir);
978
979 cleanup:
980     unlock_inode(parent->inode);
981     unlock_dnode(parent);
982 done:
983     return DO_STATUS(errno);
984 }
985
986 int
987 __vfs_do_unlink(struct v_dnode* dnode)
988 {
989     struct v_inode* inode = dnode->inode;
990
991     if (dnode->ref_count) {
992         return EBUSY;
993     }
994
995     lock_inode(inode);
996
997     int errno;
998     if (inode->open_count) {
999         errno = EBUSY;
1000     } else if (!(inode->itype & VFS_IFDIR)) {
1001         // The underlying unlink implementation should handle
1002         //  symlink case
1003         errno = inode->ops.unlink(inode);
1004         if (!errno) {
1005             inode->link_count--;
1006             llist_delete(&dnode->siblings);
1007             hlist_delete(&dnode->hash_list);
1008             vfs_d_free(dnode);
1009         }
1010     } else {
1011         errno = EISDIR;
1012     }
1013
1014     unlock_inode(inode);
1015
1016     return errno;
1017 }
1018
1019 __DEFINE_LXSYSCALL1(int, unlink, const char*, pathname)
1020 {
1021     int errno;
1022     struct v_dnode* dnode;
1023     if ((errno = vfs_walk(__current->cwd, pathname, &dnode, NULL, 0))) {
1024         goto done;
1025     }
1026     if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
1027         errno = EROFS;
1028         goto done;
1029     }
1030
1031     errno = __vfs_do_unlink(dnode);
1032
1033 done:
1034     return DO_STATUS(errno);
1035 }
1036
1037 __DEFINE_LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
1038 {
1039     int errno;
1040     struct v_fd* fd_s;
1041     if ((errno = __vfs_getfd(fd, &fd_s))) {
1042         goto done;
1043     }
1044
1045     struct v_dnode* dnode;
1046     if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) {
1047         errno = __vfs_do_unlink(dnode);
1048     }
1049
1050 done:
1051     return DO_STATUS(errno);
1052 }
1053
1054 __DEFINE_LXSYSCALL2(int, link, const char*, oldpath, const char*, newpath)
1055 {
1056     int errno;
1057     struct v_dnode *dentry, *to_link, *name_dentry, *name_file;
1058
1059     errno = __vfs_try_locate_file(oldpath, &dentry, &to_link, 0);
1060     if (!errno) {
1061         errno = __vfs_try_locate_file(
1062           newpath, &name_dentry, &name_file, FLOCATE_CREATE_EMPTY);
1063         if (!errno) {
1064             errno = EEXIST;
1065         } else if (name_file) {
1066             errno = vfs_link(to_link, name_file);
1067         }
1068     }
1069     return DO_STATUS(errno);
1070 }
1071
1072 __DEFINE_LXSYSCALL1(int, fsync, int, fildes)
1073 {
1074     int errno;
1075     struct v_fd* fd_s;
1076     if (!(errno = __vfs_getfd(fildes, &fd_s))) {
1077         errno = vfs_fsync(fd_s->file);
1078     }
1079
1080     return DO_STATUS(errno);
1081 }
1082
1083 int
1084 vfs_dup_fd(struct v_fd* old, struct v_fd** new)
1085 {
1086     int errno = 0;
1087     struct v_fd* copied = cake_grab(fd_pile);
1088
1089     memcpy(copied, old, sizeof(struct v_fd));
1090
1091     atomic_fetch_add(&old->file->ref_count, 1);
1092
1093     *new = copied;
1094
1095     return errno;
1096 }
1097
1098 int
1099 vfs_dup2(int oldfd, int newfd)
1100 {
1101     if (newfd == oldfd) {
1102         return newfd;
1103     }
1104
1105     int errno;
1106     struct v_fd *oldfd_s, *newfd_s;
1107     if ((errno = __vfs_getfd(oldfd, &oldfd_s))) {
1108         goto done;
1109     }
1110
1111     if (!TEST_FD(newfd)) {
1112         errno = EBADF;
1113         goto done;
1114     }
1115
1116     newfd_s = __current->fdtable->fds[newfd];
1117     if (newfd_s && (errno = vfs_close(newfd_s->file))) {
1118         goto done;
1119     }
1120
1121     if (!(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
1122         __current->fdtable->fds[newfd] = newfd_s;
1123         return newfd;
1124     }
1125
1126 done:
1127     return DO_STATUS(errno);
1128 }
1129
1130 __DEFINE_LXSYSCALL2(int, dup2, int, oldfd, int, newfd)
1131 {
1132     return vfs_dup2(oldfd, newfd);
1133 }
1134
1135 __DEFINE_LXSYSCALL1(int, dup, int, oldfd)
1136 {
1137     int errno, newfd;
1138     struct v_fd *oldfd_s, *newfd_s;
1139     if ((errno = __vfs_getfd(oldfd, &oldfd_s))) {
1140         goto done;
1141     }
1142
1143     if (!(errno = vfs_alloc_fdslot(&newfd)) &&
1144         !(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
1145         __current->fdtable->fds[newfd] = newfd_s;
1146         return newfd;
1147     }
1148
1149 done:
1150     return DO_STATUS(errno);
1151 }
1152
1153 __DEFINE_LXSYSCALL2(int,
1154                     symlink,
1155                     const char*,
1156                     pathname,
1157                     const char*,
1158                     link_target)
1159 {
1160     int errno;
1161     struct v_dnode* dnode;
1162     if ((errno = vfs_walk(__current->cwd, pathname, &dnode, NULL, 0))) {
1163         goto done;
1164     }
1165     if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
1166         errno = EROFS;
1167         goto done;
1168     }
1169     if (!dnode->inode->ops.symlink) {
1170         errno = ENOTSUP;
1171         goto done;
1172     }
1173
1174     lock_inode(dnode->inode);
1175
1176     errno = dnode->inode->ops.symlink(dnode->inode, link_target);
1177
1178     unlock_inode(dnode->inode);
1179
1180 done:
1181     return DO_STATUS(errno);
1182 }
1183
1184 int
1185 __vfs_do_chdir(struct v_dnode* dnode)
1186 {
1187     int errno = 0;
1188
1189     lock_dnode(dnode);
1190
1191     if (!(dnode->inode->itype & VFS_IFDIR)) {
1192         errno = ENOTDIR;
1193         goto done;
1194     }
1195
1196     if (__current->cwd) {
1197         __current->cwd->ref_count--;
1198     }
1199
1200     dnode->ref_count--;
1201     __current->cwd = dnode;
1202
1203     unlock_dnode(dnode);
1204
1205 done:
1206     return errno;
1207 }
1208
1209 __DEFINE_LXSYSCALL1(int, chdir, const char*, path)
1210 {
1211     struct v_dnode* dnode;
1212     int errno = 0;
1213
1214     if ((errno = vfs_walk(__current->cwd, path, &dnode, NULL, 0))) {
1215         goto done;
1216     }
1217
1218     errno = __vfs_do_chdir(dnode);
1219
1220 done:
1221     return DO_STATUS(errno);
1222 }
1223
1224 __DEFINE_LXSYSCALL1(int, fchdir, int, fd)
1225 {
1226     struct v_fd* fd_s;
1227     int errno = 0;
1228
1229     if ((errno = __vfs_getfd(fd, &fd_s))) {
1230         goto done;
1231     }
1232
1233     errno = __vfs_do_chdir(fd_s->file->dnode);
1234
1235 done:
1236     return DO_STATUS(errno);
1237 }
1238
1239 __DEFINE_LXSYSCALL2(char*, getcwd, char*, buf, size_t, size)
1240 {
1241     int errno = 0;
1242     char* ret_ptr = 0;
1243     if (size < 2) {
1244         errno = ERANGE;
1245         goto done;
1246     }
1247
1248     size_t len = 0;
1249
1250     if (!__current->cwd) {
1251         *buf = PATH_DELIM;
1252         len = 1;
1253     } else {
1254         len = vfs_get_path(__current->cwd, buf, size, 0);
1255         if (len == size) {
1256             errno = ERANGE;
1257             goto done;
1258         }
1259     }
1260
1261     buf[len + 1] = '\0';
1262
1263     ret_ptr = buf;
1264
1265 done:
1266     __current->k_status = errno;
1267     return ret_ptr;
1268 }
1269
1270 int
1271 vfs_do_rename(struct v_dnode* current, struct v_dnode* target)
1272 {
1273     if (current->inode->id == target->inode->id) {
1274         // hard link
1275         return 0;
1276     }
1277
1278     if (current->ref_count || target->ref_count) {
1279         return EBUSY;
1280     }
1281
1282     if (current->super_block != target->super_block) {
1283         return EXDEV;
1284     }
1285
1286     int errno = 0;
1287
1288     struct v_dnode* oldparent = current->parent;
1289     struct v_dnode* newparent = target->parent;
1290
1291     lock_dnode(current);
1292     lock_dnode(target);
1293     if (oldparent)
1294         lock_dnode(oldparent);
1295     if (newparent)
1296         lock_dnode(newparent);
1297
1298     if (!llist_empty(&target->children)) {
1299         errno = ENOTEMPTY;
1300         unlock_dnode(target);
1301         goto cleanup;
1302     }
1303
1304     if ((errno = current->inode->ops.rename(current->inode, current, target))) {
1305         unlock_dnode(target);
1306         goto cleanup;
1307     }
1308
1309     // re-position current
1310     current->parent = newparent;
1311     hstrcpy(&current->name, &target->name);
1312     llist_delete(&current->siblings);
1313     llist_append(&newparent->children, &current->siblings);
1314     vfs_dcache_rehash(newparent, current);
1315
1316     // detach target
1317     llist_delete(&target->siblings);
1318     hlist_delete(&target->hash_list);
1319
1320     unlock_dnode(target);
1321
1322 cleanup:
1323     unlock_dnode(current);
1324     if (oldparent)
1325         unlock_dnode(oldparent);
1326     if (newparent)
1327         unlock_dnode(newparent);
1328
1329     return errno;
1330 }
1331
1332 __DEFINE_LXSYSCALL2(int, rename, const char*, oldpath, const char*, newpath)
1333 {
1334     struct v_dnode *cur, *target_parent, *target;
1335     struct hstr name = HSTR(valloc(VFS_NAME_MAXLEN), 0);
1336     int errno = 0;
1337
1338     if ((errno = vfs_walk(__current->cwd, oldpath, &cur, NULL, 0))) {
1339         goto done;
1340     }
1341
1342     if ((errno = vfs_walk(
1343            __current->cwd, newpath, &target_parent, &name, VFS_WALK_PARENT))) {
1344         goto done;
1345     }
1346
1347     errno = vfs_walk(target_parent, name.value, &target, NULL, 0);
1348     if (errno == ENOENT) {
1349         target = vfs_d_alloc();
1350         hstrcpy(&target->name, &name);
1351     } else if (errno) {
1352         goto done;
1353     }
1354
1355     if (!(errno = vfs_do_rename(cur, target))) {
1356         vfs_d_free(target);
1357     }
1358
1359 done:
1360     vfree(name.value);
1361     return DO_STATUS(errno);
1362 }
1363
1364 __DEFINE_LXSYSCALL3(int,
1365                     mount,
1366                     const char*,
1367                     source,
1368                     const char*,
1369                     target,
1370                     const char*,
1371                     fstype)
1372 {
1373     struct v_dnode *dev, *mnt;
1374     int errno = 0;
1375
1376     if ((errno = vfs_walk(__current->cwd, source, &dev, NULL, 0))) {
1377         goto done;
1378     }
1379
1380     if ((errno = vfs_walk(__current->cwd, target, &mnt, NULL, 0))) {
1381         goto done;
1382     }
1383
1384     if (!(dev->inode->itype & VFS_IFVOLDEV)) {
1385         errno = ENOTDEV;
1386         goto done;
1387     }
1388
1389     // FIXME should not touch the underlying fs!
1390     struct device* device =
1391       (struct device*)((struct twifs_node*)dev->inode->data)->data;
1392
1393     errno = vfs_mount_at(fstype, device, mnt);
1394
1395 done:
1396     return DO_STATUS(errno);
1397 }
1398
1399 __DEFINE_LXSYSCALL1(int, unmount, const char*, target)
1400 {
1401     return vfs_unmount(target);
1402 }