3 * @author Lunaixsky (zelong56@gmail.com)
4 * @brief Lunaix virtual file system - an abstraction layer for all file system.
8 * @copyright Copyright (c) 2022
12 // Welcome to The Mountain O'Shit! :)
15 TODO vfs & device todos checklist
17 It is overseen by Twilight Sparkle ;)
19 1. Get inodes hooked into lru (CHECKED)
20 2. Get dnodes hooked into lru (CHECKED)
21 3. Get inodes properly hashed so they can be reused by underling fs (CHECKED)
22 4. (lru) Add a callback function (or destructor) for eviction. (CHECKED)
23 [good idea] or a constructor/destructor pattern in cake allocator ?
24 5. (mount) Figure out a way to identify a busy mount point before unmount
25 maybe a unified mount_point structure that maintain a referencing
26 counter on any dnodes within the subtree? Such a counter will only
27 increament if a file is opened or a dnode is being used as working
28 directory and decreamenting conversely. (CHECKED)
29 6. (mount) Ability to track all mount points (including sub-mounts)
30 so we can be confident to clean up everything when we
32 7. (mount) Figure out a way to acquire the device represented by a dnode.
33 so it can be used to mount. (e.g. we wish to get `struct device*`
34 out of the dnode at /dev/sda)
35 [tip] we should pay attention at twifs and add a private_data field
36 under struct v_dnode? (CHECKED)
37 8. (mount) Then, we should refactor on mount/unmount mechanism. (CHECKED)
38 9. (mount) (future) Ability to mount any thing? e.g. Linux can mount a disk
39 image file using a so called "loopback" pseudo device. Maybe
40 we can do similar thing in Lunaix? A block device emulation
41 above the regular file when we mount it on.
42 10. (device) device number (dev_t) allocation
43 [good idea] <class>:<subclass>:<uniq_id> composition (CHECKED)
46 #include <klibc/string.h>
47 #include <lunaix/foptions.h>
48 #include <lunaix/fs.h>
49 #include <lunaix/mm/cake.h>
50 #include <lunaix/mm/valloc.h>
51 #include <lunaix/process.h>
52 #include <lunaix/spike.h>
53 #include <lunaix/syscall.h>
54 #include <lunaix/syscall_utils.h>
56 #include <lunaix/fs/twifs.h>
58 #include <usr/lunaix/dirent_defs.h>
60 static struct cake_pile* dnode_pile;
61 static struct cake_pile* inode_pile;
62 static struct cake_pile* file_pile;
63 static struct cake_pile* superblock_pile;
64 static struct cake_pile* fd_pile;
66 struct v_dnode* vfs_sysroot;
68 struct lru_zone *dnode_lru, *inode_lru;
70 struct hstr vfs_ddot = HSTR("..", 2);
71 struct hstr vfs_dot = HSTR(".", 1);
72 struct hstr vfs_empty = HSTR("", 0);
75 __vfs_try_evict_dnode(struct lru_node* obj);
78 __vfs_try_evict_inode(struct lru_node* obj);
83 // 为他们专门创建一个蛋糕堆,而不使用valloc,这样我们可以最小化内碎片的产生
84 dnode_pile = cake_new_pile("dnode_cache", sizeof(struct v_dnode), 1, 0);
85 inode_pile = cake_new_pile("inode_cache", sizeof(struct v_inode), 1, 0);
86 file_pile = cake_new_pile("file_cache", sizeof(struct v_file), 1, 0);
87 fd_pile = cake_new_pile("fd_cache", sizeof(struct v_fd), 1, 0);
89 cake_new_pile("sb_cache", sizeof(struct v_superblock), 1, 0);
91 dnode_lru = lru_new_zone("vfs_dnode", __vfs_try_evict_dnode);
92 inode_lru = lru_new_zone("vfs_inode", __vfs_try_evict_inode);
94 hstr_rehash(&vfs_ddot, HSTR_FULL_HASH);
95 hstr_rehash(&vfs_dot, HSTR_FULL_HASH);
98 vfs_sysroot = vfs_d_alloc(NULL, &vfs_empty);
99 vfs_sysroot->parent = vfs_sysroot;
101 vfs_ref_dnode(vfs_sysroot);
104 static inline struct hbucket*
105 __dcache_hash(struct v_dnode* parent, u32_t* hash)
107 struct hbucket* d_cache;
110 d_cache = parent->super_block->d_cache;
112 _hash = _hash ^ (_hash >> VFS_HASHBITS);
113 _hash += (u32_t)__ptr(parent);
116 return &d_cache[_hash & VFS_HASH_MASK];
120 __sync_inode_nolock(struct v_inode* inode)
122 pcache_commit_all(inode);
125 if (inode->ops->sync) {
126 errno = inode->ops->sync(inode);
133 vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str)
135 if (!str->len || HSTR_EQ(str, &vfs_dot))
138 if (HSTR_EQ(str, &vfs_ddot)) {
139 return parent->parent;
142 u32_t hash = str->hash;
143 struct hbucket* slot = __dcache_hash(parent, &hash);
145 struct v_dnode *pos, *n;
146 hashtable_bucket_foreach(slot, pos, n, hash_list)
148 if (pos->name.hash == hash && pos->parent == parent) {
156 vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode)
160 dnode->ref_count = 1;
161 dnode->parent = parent;
162 llist_append(&parent->children, &dnode->siblings);
164 struct hbucket* bucket = __dcache_hash(parent, &dnode->name.hash);
165 hlist_add(&bucket->head, &dnode->hash_list);
169 vfs_dcache_remove(struct v_dnode* dnode)
172 assert(dnode->ref_count == 1);
174 llist_delete(&dnode->siblings);
175 llist_delete(&dnode->aka_list);
176 hlist_delete(&dnode->hash_list);
178 dnode->parent = NULL;
179 dnode->ref_count = 0;
183 vfs_dcache_rehash(struct v_dnode* new_parent, struct v_dnode* dnode)
187 hstr_rehash(&dnode->name, HSTR_FULL_HASH);
188 vfs_dcache_remove(dnode);
189 vfs_dcache_add(new_parent, dnode);
193 vfs_open(struct v_dnode* dnode, struct v_file** file)
195 struct v_inode* inode = dnode->inode;
197 if (!inode || !inode->ops->open) {
203 struct v_file* vfile = cake_grab(file_pile);
204 memset(vfile, 0, sizeof(*vfile));
206 vfile->dnode = dnode;
207 vfile->inode = inode;
208 vfile->ref_count = 1;
209 vfile->ops = inode->default_fops;
211 if (check_regfile_node(inode) && !inode->pg_cache) {
212 struct pcache* pcache = vzalloc(sizeof(struct pcache));
214 pcache->master = inode;
215 inode->pg_cache = pcache;
218 int errno = inode->ops->open(inode, vfile);
220 cake_release(file_pile, vfile);
222 vfs_ref_dnode(dnode);
234 vfs_assign_inode(struct v_dnode* assign_to, struct v_inode* inode)
236 if (assign_to->inode) {
237 llist_delete(&assign_to->aka_list);
238 assign_to->inode->link_count--;
241 llist_append(&inode->aka_dnodes, &assign_to->aka_list);
242 assign_to->inode = inode;
247 vfs_link(struct v_dnode* to_link, struct v_dnode* name)
251 if ((errno = vfs_check_writable(to_link))) {
255 lock_inode(to_link->inode);
256 if (to_link->super_block->root != name->super_block->root) {
258 } else if (!to_link->inode->ops->link) {
260 } else if (!(errno = to_link->inode->ops->link(to_link->inode, name))) {
261 vfs_assign_inode(name, to_link->inode);
263 unlock_inode(to_link->inode);
269 vfs_pclose(struct v_file* file, pid_t pid)
271 struct v_inode* inode;
278 * This happened when process is terminated while blocking on read.
279 * In that case, the process is still holding the inode lock and it
280 will never get released.
281 * The unlocking should also include ownership check.
283 * To see why, consider two process both open the same file both with
285 * Process A: busy on reading x
286 * Process B: do nothing with x
287 * Assuming that, after a very short time, process B get terminated
288 * while process A is still busy in it's reading business. By this
289 * design, the inode lock of this file x is get released by B rather
290 * than A. And this will cause a probable race condition on A if other
291 * process is writing to this file later after B exit.
294 mutex_unlock_for(&inode->lock, pid);
296 if (vfs_check_duped_file(file)) {
297 vfs_unref_file(file);
301 if ((errno = file->ops->close(file))) {
305 vfs_unref_dnode(file->dnode);
306 cake_release(file_pile, file);
309 if the current inode is not being locked by other
310 threads that does not share same open context,
311 then we can try to do sync opportunistically
313 if (mutex_on_hold(&inode->lock)) {
319 pcache_commit_all(inode);
322 if (!inode->open_count) {
323 __sync_inode_nolock(inode);
333 vfs_close(struct v_file* file)
335 return vfs_pclose(file, __current->pid);
339 vfs_free_fd(struct v_fd* fd)
341 cake_release(fd_pile, fd);
345 vfs_isync(struct v_inode* inode)
349 int errno = __sync_inode_nolock(inode);
357 vfs_fsync(struct v_file* file)
360 if ((errno = vfs_check_writable(file->dnode))) {
364 return vfs_isync(file->inode);
368 vfs_alloc_fdslot(int* fd)
370 for (size_t i = 0; i < VFS_MAX_FD; i++) {
371 if (!__current->fdtable->fds[i]) {
382 struct v_superblock* sb = cake_grab(superblock_pile);
383 memset(sb, 0, sizeof(*sb));
384 llist_init_head(&sb->sb_list);
386 sb->i_cache = vzalloc(VFS_HASHTABLE_SIZE * sizeof(struct hbucket));
387 sb->d_cache = vzalloc(VFS_HASHTABLE_SIZE * sizeof(struct hbucket));
394 vfs_sb_ref(struct v_superblock* sb)
400 vfs_sb_unref(struct v_superblock* sb)
402 assert(sb->ref_count);
405 if (likely(sb->ref_count)) {
409 if (sb->ops.release) {
416 cake_release(superblock_pile, sb);
420 __vfs_try_evict_dnode(struct lru_node* obj)
422 struct v_dnode* dnode = container_of(obj, struct v_dnode, lru);
424 if (!dnode->ref_count) {
432 __vfs_try_evict_inode(struct lru_node* obj)
434 struct v_inode* inode = container_of(obj, struct v_inode, lru);
436 if (!inode->link_count && !inode->open_count) {
444 vfs_d_alloc(struct v_dnode* parent, struct hstr* name)
446 struct v_dnode* dnode = cake_grab(dnode_pile);
448 lru_evict_half(dnode_lru);
450 if (!(dnode = cake_grab(dnode_pile))) {
455 memset(dnode, 0, sizeof(*dnode));
456 llist_init_head(&dnode->children);
457 llist_init_head(&dnode->siblings);
458 llist_init_head(&dnode->aka_list);
459 mutex_init(&dnode->lock);
461 dnode->name = HHSTR(vzalloc(VFS_NAME_MAXLEN), 0, 0);
463 hstrcpy(&dnode->name, name);
466 vfs_d_assign_sb(dnode, parent->super_block);
467 dnode->mnt = parent->mnt;
470 lru_use_one(dnode_lru, &dnode->lru);
476 vfs_d_free(struct v_dnode* dnode)
478 assert(dnode->ref_count == 1);
481 assert(dnode->inode->link_count > 0);
482 dnode->inode->link_count--;
485 vfs_dcache_remove(dnode);
486 // Make sure the children de-referencing their parent.
487 // With lru presented, the eviction will be propagated over the entire
488 // detached subtree eventually
489 struct v_dnode *pos, *n;
490 llist_for_each(pos, n, &dnode->children, siblings)
492 vfs_dcache_remove(pos);
495 if (dnode->destruct) {
496 dnode->destruct(dnode);
499 vfs_sb_unref(dnode->super_block);
500 vfree((void*)dnode->name.value);
501 cake_release(dnode_pile, dnode);
505 vfs_i_find(struct v_superblock* sb, u32_t i_id)
507 struct hbucket* slot = &sb->i_cache[i_id & VFS_HASH_MASK];
508 struct v_inode *pos, *n;
509 hashtable_bucket_foreach(slot, pos, n, hash_list)
511 if (pos->id == i_id) {
512 lru_use_one(inode_lru, &pos->lru);
521 vfs_i_addhash(struct v_inode* inode)
523 struct hbucket* slot = &inode->sb->i_cache[inode->id & VFS_HASH_MASK];
525 hlist_delete(&inode->hash_list);
526 hlist_add(&slot->head, &inode->hash_list);
530 vfs_i_alloc(struct v_superblock* sb)
532 assert(sb->ops.init_inode);
534 struct v_inode* inode;
535 if (!(inode = cake_grab(inode_pile))) {
536 lru_evict_half(inode_lru);
537 if (!(inode = cake_grab(inode_pile))) {
542 memset(inode, 0, sizeof(*inode));
543 mutex_init(&inode->lock);
544 llist_init_head(&inode->xattrs);
545 llist_init_head(&inode->aka_dnodes);
547 sb->ops.init_inode(sb, inode);
549 inode->ctime = clock_unixtime();
550 inode->atime = inode->ctime;
551 inode->mtime = inode->ctime;
553 vfs_i_assign_sb(inode, sb);
554 lru_use_one(inode_lru, &inode->lru);
559 vfs_i_free(struct v_inode* inode)
561 if (inode->pg_cache) {
562 pcache_release(inode->pg_cache);
563 vfree(inode->pg_cache);
565 // we don't need to sync inode.
566 // If an inode can be free, then it must be properly closed.
567 // Hence it must be synced already!
568 if (inode->destruct) {
569 inode->destruct(inode);
572 vfs_sb_unref(inode->sb);
573 hlist_delete(&inode->hash_list);
574 cake_release(inode_pile, inode);
577 /* ---- System call definition and support ---- */
579 // make a new name when not exists
580 #define FLOC_MAYBE_MKNAME 1
582 // name must be non-exist and made.
583 #define FLOC_MKNAME 2
586 #define FLOC_NOFOLLOW 4
589 vfs_getfd(int fd, struct v_fd** fd_s)
591 if (TEST_FD(fd) && (*fd_s = __current->fdtable->fds[fd])) {
598 __vfs_mknod(struct v_inode* parent, struct v_dnode* dnode,
599 unsigned int itype, dev_t* dev)
603 errno = parent->ops->create(parent, dnode, itype);
611 struct file_locator {
613 struct v_dnode* file;
618 * @brief unlock the file locator (floc) if possible.
619 * If the file to be located if not exists, and
620 * any FLOC_*MKNAME flag is set, then the parent
621 * dnode will be locked until the file has been properly
622 * finalised by subsequent logic.
627 __floc_try_unlock(struct file_locator* floc)
631 unlock_dnode(floc->dir);
636 __vfs_try_locate_file(const char* path,
637 struct file_locator* floc,
640 char name_str[VFS_NAME_MAXLEN];
641 struct v_dnode *fdir, *file;
642 struct hstr name = HSTR(name_str, 0);
643 int errno, woption = 0;
645 if ((options & FLOC_NOFOLLOW)) {
646 woption |= VFS_WALK_NOFOLLOW;
647 options &= ~FLOC_NOFOLLOW;
652 errno = vfs_walk_proc(path, &fdir, &name, woption | VFS_WALK_PARENT);
657 errno = vfs_walk(fdir, name.value, &file, NULL, woption);
659 if (errno && errno != ENOENT) {
664 if ((options & FLOC_MKNAME)) {
675 errno = vfs_check_writable(fdir);
682 file = vfs_d_alloc(fdir, &name);
690 vfs_dcache_add(fdir, file);
700 vfs_do_open(const char* path, int options)
702 int errno, fd, loptions = 0;
703 struct v_dnode *dentry, *file;
704 struct v_file* ofile = NULL;
705 struct file_locator floc;
706 struct v_inode* inode;
708 if ((options & FO_CREATE)) {
709 loptions |= FLOC_MAYBE_MKNAME;
710 } else if ((options & FO_NOFOLLOW)) {
711 loptions |= FLOC_NOFOLLOW;
714 errno = __vfs_try_locate_file(path, &floc, loptions);
716 if (errno || (errno = vfs_alloc_fdslot(&fd))) {
724 errno = __vfs_mknod(dentry->inode, file, VFS_IFFILE, NULL);
727 __floc_try_unlock(&floc);
731 __floc_try_unlock(&floc);
735 if ((errno = vfs_open(file, &ofile))) {
739 inode = ofile->inode;
742 struct v_fd* fd_s = cake_grab(fd_pile);
743 memset(fd_s, 0, sizeof(*fd_s));
745 if ((options & O_TRUNC)) {
746 file->inode->fsize = 0;
749 if (vfs_get_dtype(inode->itype) == DT_DIR) {
754 fd_s->flags = options;
755 __current->fdtable->fds[fd] = fd_s;
762 __DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
764 int errno = vfs_do_open(path, options);
765 return DO_STATUS_OR_RETURN(errno);
768 __DEFINE_LXSYSCALL1(int, close, int, fd)
772 if ((errno = vfs_getfd(fd, &fd_s))) {
776 if ((errno = vfs_close(fd_s->file))) {
780 cake_release(fd_pile, fd_s);
781 __current->fdtable->fds[fd] = 0;
784 return DO_STATUS(errno);
788 __vfs_readdir_callback(struct dir_context* dctx,
793 struct lx_dirent* dent = (struct lx_dirent*)dctx->cb_data;
794 strncpy(dent->d_name, name, MIN(len, DIRENT_NAME_MAX_LEN));
796 dent->d_type = dtype;
799 __DEFINE_LXSYSCALL2(int, sys_readdir, int, fd, struct lx_dirent*, dent)
804 if ((errno = vfs_getfd(fd, &fd_s))) {
808 struct v_inode* inode = fd_s->file->inode;
812 if (!check_directory_node(inode)) {
817 struct dir_context dctx = (struct dir_context) {
819 .read_complete_callback = __vfs_readdir_callback
822 if ((errno = fd_s->file->ops->readdir(fd_s->file, &dctx)) != 1) {
832 return DO_STATUS_OR_RETURN(errno);
835 __DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
839 if ((errno = vfs_getfd(fd, &fd_s))) {
843 struct v_file* file = fd_s->file;
844 if (check_directory_node(file->inode)) {
849 if (!check_allow_read(file->inode)) {
854 lock_inode(file->inode);
856 file->inode->atime = clock_unixtime();
858 if (check_seqdev_node(file->inode) || (fd_s->flags & FO_DIRECT)) {
859 errno = file->ops->read(file->inode, buf, count, file->f_pos);
861 errno = pcache_read(file->inode, buf, count, file->f_pos);
865 file->f_pos += errno;
866 unlock_inode(file->inode);
870 unlock_inode(file->inode);
873 return DO_STATUS(errno);
876 __DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
880 if ((errno = vfs_getfd(fd, &fd_s))) {
884 struct v_inode* inode;
885 struct v_file* file = fd_s->file;
887 if ((errno = vfs_check_writable(file->dnode))) {
891 if (check_directory_node(file->inode)) {
899 inode->mtime = clock_unixtime();
900 if ((fd_s->flags & O_APPEND)) {
901 file->f_pos = inode->fsize;
904 if (check_seqdev_node(inode) || (fd_s->flags & FO_DIRECT)) {
905 errno = file->ops->write(inode, buf, count, file->f_pos);
907 errno = pcache_write(inode, buf, count, file->f_pos);
911 file->f_pos += errno;
912 inode->fsize = MAX(inode->fsize, file->f_pos);
921 return DO_STATUS(errno);
924 __DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
928 if ((errno = vfs_getfd(fd, &fd_s))) {
932 struct v_file* file = fd_s->file;
933 struct v_inode* inode = file->inode;
935 if (!file->ops->seek) {
940 if (!check_allow_read(inode)) {
948 int fpos = file->f_pos;
950 if (vfs_get_dtype(inode->itype) == DT_DIR) {
951 options = (options != FSEEK_END) ? options : FSEEK_SET;
956 overflow = sadd_of((int)file->f_pos, offset, &fpos);
959 overflow = sadd_of((int)inode->fsize, offset, &fpos);
970 errno = file->ops->seek(file, fpos);
976 return DO_STATUS(errno);
980 vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
992 if (dnode->parent != dnode) {
993 len = vfs_get_path(dnode->parent, buf, size, depth + 1);
1000 if (!len || buf[len - 1] != VFS_PATH_DELIM) {
1001 buf[len++] = VFS_PATH_DELIM;
1004 size_t cpy_size = MIN(dnode->name.len, size - len);
1005 strncpy(buf + len, dnode->name.value, cpy_size);
1012 vfs_readlink(struct v_dnode* dnode, char* buf, size_t size)
1015 struct v_inode* inode = dnode->inode;
1017 if (!check_symlink_node(inode)) {
1021 if (!inode->ops->read_symlink) {
1025 if (!check_allow_read(inode)) {
1031 int errno = inode->ops->read_symlink(inode, &link);
1033 strncpy(buf, link, MIN(size, (size_t)errno));
1036 unlock_inode(inode);
1041 vfs_get_dtype(int itype)
1043 int dtype = DT_FILE;
1044 if (check_itype(itype, VFS_IFSYMLINK)) {
1045 dtype |= DT_SYMLINK;
1048 if (check_itype(itype, VFS_IFDIR)) {
1058 __DEFINE_LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
1062 if ((errno = vfs_getfd(fd, &fd_s))) {
1066 struct v_dnode* dnode;
1067 errno = vfs_get_path(fd_s->file->dnode, buf, size, 0);
1074 return DO_STATUS(errno);
1077 __DEFINE_LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
1080 struct v_dnode* dnode;
1081 if (!(errno = vfs_walk_proc(path, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
1082 errno = vfs_readlink(dnode, buf, size);
1089 return DO_STATUS(errno);
1092 __DEFINE_LXSYSCALL4(
1093 int, readlinkat, int, dirfd, const char*, pathname, char*, buf, size_t, size)
1097 if ((errno = vfs_getfd(dirfd, &fd_s))) {
1101 pathname = pathname ? pathname : "";
1103 struct v_dnode* dnode;
1104 if (!(errno = vfs_walk(
1105 fd_s->file->dnode, pathname, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
1106 errno = vfs_readlink(fd_s->file->dnode, buf, size);
1114 return DO_STATUS(errno);
1119 When we perform operation that could affect the layout of
1120 directory (i.e., rename, mkdir, rmdir). We must lock the parent dir
1121 whenever possible. This will blocking any ongoing path walking to reach
1122 it hence avoid any partial state.
1125 __DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname)
1128 struct v_dnode* dnode;
1129 if ((errno = vfs_walk_proc(pathname, &dnode, NULL, 0))) {
1130 return DO_STATUS(errno);
1135 if ((errno = vfs_check_writable(dnode))) {
1139 if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
1144 if (dnode->ref_count > 1 || dnode->inode->open_count) {
1149 if (!llist_empty(&dnode->children)) {
1154 struct v_dnode* parent = dnode->parent;
1162 lock_inode(parent->inode);
1164 if (check_directory_node(dnode->inode)) {
1165 errno = parent->inode->ops->rmdir(parent->inode, dnode);
1167 vfs_dcache_remove(dnode);
1173 unlock_inode(parent->inode);
1174 unlock_dnode(parent);
1177 unlock_dnode(dnode);
1178 return DO_STATUS(errno);
1181 __DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
1184 struct v_dnode *parent, *dir;
1185 char name_value[VFS_NAME_MAXLEN];
1186 struct hstr name = HHSTR(name_value, 0, 0);
1188 if ((errno = vfs_walk_proc(path, &parent, &name, VFS_WALK_PARENT))) {
1192 if (!(errno = vfs_walk(parent, name_value, &dir, NULL, 0))) {
1197 if ((errno = vfs_check_writable(parent))) {
1201 if (!(dir = vfs_d_alloc(parent, &name))) {
1206 struct v_inode* inode = parent->inode;
1211 if ((parent->super_block->fs->types & FSTYPE_ROFS)) {
1213 } else if (!inode->ops->mkdir) {
1215 } else if (!check_directory_node(inode)) {
1217 } else if (!(errno = inode->ops->mkdir(inode, dir))) {
1218 vfs_dcache_add(parent, dir);
1225 unlock_inode(inode);
1226 unlock_dnode(parent);
1228 return DO_STATUS(errno);
1232 __vfs_do_unlink(struct v_dnode* dnode)
1235 struct v_inode* inode = dnode->inode;
1237 if (dnode->ref_count > 1) {
1241 if ((errno = vfs_check_writable(dnode))) {
1247 if (inode->open_count) {
1249 } else if (!check_directory_node(inode)) {
1250 errno = inode->ops->unlink(inode, dnode);
1258 unlock_inode(inode);
1263 __DEFINE_LXSYSCALL1(int, unlink, const char*, pathname)
1266 struct v_dnode* dnode;
1267 if ((errno = vfs_walk_proc(pathname, &dnode, NULL, 0))) {
1271 errno = __vfs_do_unlink(dnode);
1274 return DO_STATUS(errno);
1277 __DEFINE_LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
1281 if ((errno = vfs_getfd(fd, &fd_s))) {
1285 struct v_dnode* dnode;
1286 if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) {
1287 errno = __vfs_do_unlink(dnode);
1291 return DO_STATUS(errno);
1294 __DEFINE_LXSYSCALL2(int, link, const char*, oldpath, const char*, newpath)
1297 struct file_locator floc;
1298 struct v_dnode *to_link, *name_file;
1300 errno = __vfs_try_locate_file(oldpath, &floc, 0);
1305 __floc_try_unlock(&floc);
1307 to_link = floc.file;
1308 errno = __vfs_try_locate_file(newpath, &floc, FLOC_MKNAME);
1313 name_file = floc.file;
1314 errno = vfs_link(to_link, name_file);
1316 vfs_d_free(name_file);
1320 __floc_try_unlock(&floc);
1321 return DO_STATUS(errno);
1324 __DEFINE_LXSYSCALL1(int, fsync, int, fildes)
1329 if (!(errno = vfs_getfd(fildes, &fd_s))) {
1330 errno = vfs_fsync(fd_s->file);
1333 return DO_STATUS(errno);
1337 vfs_dup_fd(struct v_fd* old, struct v_fd** new)
1340 struct v_fd* copied = cake_grab(fd_pile);
1342 memcpy(copied, old, sizeof(struct v_fd));
1344 vfs_ref_file(old->file);
1352 vfs_dup2(int oldfd, int newfd)
1354 if (newfd == oldfd) {
1359 struct v_fd *oldfd_s, *newfd_s;
1360 if ((errno = vfs_getfd(oldfd, &oldfd_s))) {
1364 if (!TEST_FD(newfd)) {
1369 newfd_s = __current->fdtable->fds[newfd];
1370 if (newfd_s && (errno = vfs_close(newfd_s->file))) {
1374 if (!(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
1375 __current->fdtable->fds[newfd] = newfd_s;
1380 return DO_STATUS(errno);
1383 __DEFINE_LXSYSCALL2(int, dup2, int, oldfd, int, newfd)
1385 return vfs_dup2(oldfd, newfd);
1388 __DEFINE_LXSYSCALL1(int, dup, int, oldfd)
1391 struct v_fd *oldfd_s, *newfd_s;
1392 if ((errno = vfs_getfd(oldfd, &oldfd_s))) {
1396 if (!(errno = vfs_alloc_fdslot(&newfd)) &&
1397 !(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
1398 __current->fdtable->fds[newfd] = newfd_s;
1403 return DO_STATUS(errno);
1406 __DEFINE_LXSYSCALL2(
1407 int, symlink, const char*, pathname, const char*, link_target)
1410 struct file_locator floc;
1411 struct v_dnode *file;
1412 struct v_inode *f_ino;
1414 errno = __vfs_try_locate_file(pathname, &floc, FLOC_MKNAME);
1420 errno = __vfs_mknod(floc.dir->inode, file, VFS_IFSYMLINK, NULL);
1426 f_ino = file->inode;
1430 errno = vfs_check_writable(file);
1435 if (!f_ino->ops->set_symlink) {
1442 errno = f_ino->ops->set_symlink(f_ino, link_target);
1444 unlock_inode(f_ino);
1447 __floc_try_unlock(&floc);
1448 return DO_STATUS(errno);
1452 vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
1458 if (!check_directory_node(dnode->inode)) {
1464 vfs_unref_dnode(proc->cwd);
1467 vfs_ref_dnode(dnode);
1470 unlock_dnode(dnode);
1476 __DEFINE_LXSYSCALL1(int, chdir, const char*, path)
1478 struct v_dnode* dnode;
1481 if ((errno = vfs_walk_proc(path, &dnode, NULL, 0))) {
1485 errno = vfs_do_chdir((struct proc_info*)__current, dnode);
1488 return DO_STATUS(errno);
1491 __DEFINE_LXSYSCALL1(int, fchdir, int, fd)
1496 if ((errno = vfs_getfd(fd, &fd_s))) {
1500 errno = vfs_do_chdir((struct proc_info*)__current, fd_s->file->dnode);
1503 return DO_STATUS(errno);
1506 __DEFINE_LXSYSCALL2(char*, getcwd, char*, buf, size_t, size)
1517 if (!__current->cwd) {
1518 *buf = VFS_PATH_DELIM;
1521 len = vfs_get_path(__current->cwd, buf, size, 0);
1533 syscall_result(errno);
1538 vfs_do_rename(struct v_dnode* current, struct v_dnode* target)
1541 if (current->inode->id == target->inode->id) {
1546 if ((errno = vfs_check_writable(current))) {
1550 if (current->ref_count > 1 || target->ref_count > 1) {
1554 if (current->super_block != target->super_block) {
1558 struct v_dnode* oldparent = current->parent;
1559 struct v_dnode* newparent = target->parent;
1561 lock_dnode(current);
1564 lock_dnode(oldparent);
1566 lock_dnode(newparent);
1568 if (!llist_empty(&target->children)) {
1570 unlock_dnode(target);
1575 current->inode->ops->rename(current->inode, current, target))) {
1576 unlock_dnode(target);
1580 // re-position current
1581 hstrcpy(¤t->name, &target->name);
1582 vfs_dcache_rehash(newparent, current);
1587 unlock_dnode(target);
1590 unlock_dnode(current);
1592 unlock_dnode(oldparent);
1594 unlock_dnode(newparent);
1599 __DEFINE_LXSYSCALL2(int, rename, const char*, oldpath, const char*, newpath)
1601 struct v_dnode *cur, *target_parent, *target;
1602 struct hstr name = HSTR(valloc(VFS_NAME_MAXLEN), 0);
1605 if ((errno = vfs_walk_proc(oldpath, &cur, NULL, 0))) {
1609 if ((errno = vfs_walk(
1610 __current->cwd, newpath, &target_parent, &name, VFS_WALK_PARENT))) {
1614 errno = vfs_walk(target_parent, name.value, &target, NULL, 0);
1615 if (errno == ENOENT) {
1616 target = vfs_d_alloc(target_parent, &name);
1617 vfs_dcache_add(target_parent, target);
1627 errno = vfs_do_rename(cur, target);
1630 vfree((void*)name.value);
1631 return DO_STATUS(errno);
1634 __DEFINE_LXSYSCALL2(int, fstat, int, fd, struct file_stat*, stat)
1639 if ((errno = vfs_getfd(fd, &fds))) {
1643 struct v_inode* vino = fds->file->inode;
1644 struct device* fdev = vino->sb->dev;
1646 *stat = (struct file_stat){.st_ino = vino->id,
1647 .st_blocks = vino->lb_usage,
1648 .st_size = vino->fsize,
1649 .mode = vino->itype,
1650 .st_ioblksize = PAGE_SIZE,
1651 .st_blksize = vino->sb->blksize};
1653 if (check_device_node(vino)) {
1654 struct device* rdev = resolve_device(vino->data);
1660 stat->st_rdev = (dev_t){.meta = rdev->ident.fn_grp,
1661 .unique = rdev->ident.unique,
1662 .index = dev_uid(rdev) };
1666 stat->st_dev = (dev_t){.meta = fdev->ident.fn_grp,
1667 .unique = fdev->ident.unique,
1668 .index = dev_uid(fdev) };
1672 return DO_STATUS(errno);