2 ** Copyright 2001-2004, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
5 #include <kernel/kernel.h>
6 #include <boot/stage2.h>
7 #include <kernel/vfs.h>
9 #include <kernel/vm_cache.h>
10 #include <kernel/debug.h>
11 #include <kernel/console.h>
12 #include <kernel/khash.h>
13 #include <kernel/lock.h>
14 #include <kernel/thread.h>
15 #include <kernel/heap.h>
16 #include <kernel/arch/cpu.h>
17 #include <kernel/elf.h>
18 #include <kernel/fs/rootfs.h>
19 #include <kernel/fs/bootfs.h>
20 #include <kernel/fs/devfs.h>
21 #include <kernel/fs/pipefs.h>
22 #include <newos/errors.h>
24 #include <kernel/fs/rootfs.h>
30 #include <sys/resource.h>
36 struct vnode
*mount_prev
;
37 struct vnode
*mount_next
;
38 struct vm_cache
*cache
;
42 struct fs_mount
*mount
;
43 struct vnode
*covered_by
;
48 struct vnode_hash_key
{
53 struct file_descriptor
{
66 struct file_descriptor
**fds
;
70 struct fs_container
*next
;
71 struct fs_calls
*calls
;
74 static struct fs_container
*fs_list
;
77 struct fs_mount
*next
;
78 struct fs_container
*fs
;
83 struct vnode
*root_vnode
;
84 struct vnode
*covers_vnode
;
85 struct vnode
*vnodes_head
;
86 struct vnode
*vnodes_tail
;
90 static mutex vfs_mutex
;
91 static mutex vfs_mount_mutex
;
92 static mutex vfs_mount_op_mutex
;
93 static mutex vfs_vnode_mutex
;
95 #define VNODE_HASH_TABLE_SIZE 1024
96 static void *vnode_table
;
97 static struct vnode
*root_vnode
;
99 #define MOUNTS_HASH_TABLE_SIZE 16
100 static void *mounts_table
;
101 static fs_id next_fsid
= 0;
103 static int mount_compare(void *_m
, const void *_key
)
105 struct fs_mount
*mount
= _m
;
106 const fs_id
*id
= _key
;
114 static unsigned int mount_hash(void *_m
, const void *_key
, unsigned int range
)
116 struct fs_mount
*mount
= _m
;
117 const fs_id
*id
= _key
;
120 return mount
->id
% range
;
125 static struct fs_mount
*fsid_to_mount(fs_id id
)
127 struct fs_mount
*mount
;
129 mutex_lock(&vfs_mount_mutex
);
131 mount
= hash_lookup(mounts_table
, &id
);
133 mutex_unlock(&vfs_mount_mutex
);
138 static int vnode_compare(void *_v
, const void *_key
)
140 struct vnode
*v
= _v
;
141 const struct vnode_hash_key
*key
= _key
;
143 if(v
->fsid
== key
->fsid
&& v
->vnid
== key
->vnid
)
149 static unsigned int vnode_hash(void *_v
, const void *_key
, unsigned int range
)
151 struct vnode
*v
= _v
;
152 const struct vnode_hash_key
*key
= _key
;
154 #define VHASH(fsid, vnid) (((uint32)((vnid)>>32) + (uint32)(vnid)) ^ (uint32)(fsid))
157 return (VHASH(v
->fsid
, v
->vnid
) % range
);
159 return (VHASH(key
->fsid
, key
->vnid
) % range
);
164 static int init_vnode(struct vnode
*v
)
167 dprintf("init_vnode: v %p\n", v
);
170 v
->mount_prev
= NULL
;
171 v
->mount_next
= NULL
;
172 v
->priv_vnode
= NULL
;
177 v
->delete_me
= false;
179 v
->covered_by
= NULL
;
185 static void add_vnode_to_mount_list(struct vnode
*v
, struct fs_mount
*mount
)
187 recursive_lock_lock(&mount
->rlock
);
189 v
->mount_next
= mount
->vnodes_head
;
190 v
->mount_prev
= NULL
;
192 v
->mount_next
->mount_prev
= v
;
194 mount
->vnodes_head
= v
;
196 if(!mount
->vnodes_tail
)
197 mount
->vnodes_tail
= v
;
199 // do a little bit of error checking
200 if(v
->mount_prev
== NULL
)
201 ASSERT(mount
->vnodes_head
== v
);
202 if(v
->mount_next
== NULL
)
203 ASSERT(mount
->vnodes_tail
== v
);
205 recursive_lock_unlock(&mount
->rlock
);
208 static void remove_vnode_from_mount_list(struct vnode
*v
, struct fs_mount
*mount
)
210 recursive_lock_lock(&mount
->rlock
);
212 // do a little bit of error checking
213 if(v
->mount_prev
== NULL
)
214 ASSERT(mount
->vnodes_head
== v
);
215 if(v
->mount_next
== NULL
)
216 ASSERT(mount
->vnodes_tail
== v
);
219 v
->mount_next
->mount_prev
= v
->mount_prev
;
221 mount
->vnodes_tail
= v
->mount_prev
;
223 v
->mount_prev
->mount_next
= v
->mount_next
;
225 mount
->vnodes_head
= v
->mount_next
;
227 v
->mount_prev
= v
->mount_next
= NULL
;
229 recursive_lock_unlock(&mount
->rlock
);
232 static struct vnode
*create_new_vnode(void)
236 v
= (struct vnode
*)kmalloc(sizeof(struct vnode
));
244 static int dec_vnode_ref_count(struct vnode
*v
, bool free_mem
, bool r
)
249 mutex_lock(&vfs_vnode_mutex
);
252 panic("dec_vnode_ref_count called on vnode that was busy! vnode %p\n", v
);
254 old_ref
= atomic_add(&v
->ref_count
, -1);
256 dprintf("dec_vnode_ref_count: vnode %p, ref now %d, old_ref %d\n", v
, v
->ref_count
, old_ref
);
262 mutex_unlock(&vfs_vnode_mutex
);
264 /* if we have a vm_cache attached, remove it */
266 vm_cache_release_ref((vm_cache_ref
*)v
->cache
);
270 v
->mount
->fs
->calls
->fs_removevnode(v
->mount
->fscookie
, v
->priv_vnode
, r
);
272 v
->mount
->fs
->calls
->fs_putvnode(v
->mount
->fscookie
, v
->priv_vnode
, r
);
274 remove_vnode_from_mount_list(v
, v
->mount
);
276 mutex_lock(&vfs_vnode_mutex
);
277 hash_remove(vnode_table
, v
);
278 mutex_unlock(&vfs_vnode_mutex
);
282 dprintf("dec_vnode_ref_count: freeing vnode %p\n", v
);
288 mutex_unlock(&vfs_vnode_mutex
);
294 static int inc_vnode_ref_count(struct vnode
*v
)
296 int old_ref
= atomic_add(&v
->ref_count
, 1);
298 dprintf("inc_vnode_ref_count: vnode %p, ref now %d, old_ref %d\n", v
, v
->ref_count
, old_ref
);
303 static struct vnode
*lookup_vnode(fs_id fsid
, vnode_id vnid
)
305 struct vnode_hash_key key
;
310 return hash_lookup(vnode_table
, &key
);
313 static int get_vnode(fs_id fsid
, vnode_id vnid
, struct vnode
**outv
, int r
)
319 dprintf("get_vnode: fsid %d vnid 0x%Lx\n", fsid
, vnid
);
322 mutex_lock(&vfs_vnode_mutex
);
325 v
= lookup_vnode(fsid
, vnid
);
328 mutex_unlock(&vfs_vnode_mutex
);
329 thread_snooze(10000); // 10 ms
330 mutex_lock(&vfs_vnode_mutex
);
338 dprintf("get_vnode: tried to lookup vnode, got %p\n", v
);
341 inc_vnode_ref_count(v
);
343 // we need to create a new vnode and read it in
344 v
= create_new_vnode();
351 v
->mount
= fsid_to_mount(fsid
);
353 err
= ERR_INVALID_HANDLE
;
357 hash_insert(vnode_table
, v
);
358 mutex_unlock(&vfs_vnode_mutex
);
360 add_vnode_to_mount_list(v
, v
->mount
);
362 err
= v
->mount
->fs
->calls
->fs_getvnode(v
->mount
->fscookie
, vnid
, &v
->priv_vnode
, r
);
365 remove_vnode_from_mount_list(v
, v
->mount
);
367 mutex_lock(&vfs_vnode_mutex
);
375 mutex_unlock(&vfs_vnode_mutex
);
377 dprintf("get_vnode: returning %p\n", v
);
383 hash_remove(vnode_table
, v
);
385 mutex_unlock(&vfs_vnode_mutex
);
392 static void put_vnode(struct vnode
*v
)
394 dec_vnode_ref_count(v
, true, false);
397 int vfs_get_vnode(fs_id fsid
, vnode_id vnid
, fs_vnode
*fsv
)
403 dprintf("vfs_get_vnode: fsid %d vnid 0x%Lx\n", fsid
, vnid
);
406 err
= get_vnode(fsid
, vnid
, &v
, true);
410 *fsv
= v
->priv_vnode
;
414 int vfs_put_vnode(fs_id fsid
, vnode_id vnid
)
419 dprintf("vfs_put_vnode: fsid %d vnid 0x%Lx\n", fsid
, vnid
);
422 mutex_lock(&vfs_vnode_mutex
);
424 v
= lookup_vnode(fsid
, vnid
);
426 mutex_unlock(&vfs_vnode_mutex
);
428 dec_vnode_ref_count(v
, true, true);
433 void vfs_vnode_acquire_ref(void *v
)
436 dprintf("vfs_vnode_acquire_ref: vnode %p\n", v
);
438 inc_vnode_ref_count((struct vnode
*)v
);
441 void vfs_vnode_release_ref(void *v
)
444 dprintf("vfs_vnode_release_ref: vnode %p\n", v
);
446 dec_vnode_ref_count((struct vnode
*)v
, true, false);
449 int vfs_remove_vnode(fs_id fsid
, vnode_id vnid
)
453 mutex_lock(&vfs_vnode_mutex
);
455 v
= lookup_vnode(fsid
, vnid
);
459 mutex_unlock(&vfs_vnode_mutex
);
463 void *vfs_get_cache_ptr(void *vnode
)
465 return ((struct vnode
*)vnode
)->cache
;
468 int vfs_set_cache_ptr(void *vnode
, void *cache
)
470 if(test_and_set((int *)&(((struct vnode
*)vnode
)->cache
), (int)cache
, 0) == 0)
476 static struct file_descriptor
*alloc_fd(void)
478 struct file_descriptor
*f
;
480 f
= kmalloc(sizeof(struct file_descriptor
));
491 static struct file_descriptor
*get_fd(struct ioctx
*ioctx
, int fd
)
493 struct file_descriptor
*f
;
495 mutex_lock(&ioctx
->io_mutex
);
497 if(fd
>= 0 && fd
< ioctx
->table_size
&& ioctx
->fds
[fd
]) {
500 atomic_add(&f
->ref_count
, 1);
505 mutex_unlock(&ioctx
->io_mutex
);
509 static void free_fd(struct file_descriptor
*f
)
512 f
->vnode
->mount
->fs
->calls
->fs_close(f
->vnode
->mount
->fscookie
, f
->vnode
->priv_vnode
, f
->cookie
);
513 f
->vnode
->mount
->fs
->calls
->fs_freecookie(f
->vnode
->mount
->fscookie
, f
->vnode
->priv_vnode
, f
->cookie
);
515 f
->vnode
->mount
->fs
->calls
->fs_closedir(f
->vnode
->mount
->fscookie
, f
->vnode
->priv_vnode
, f
->cookie
);
517 dec_vnode_ref_count(f
->vnode
, true, false);
521 static void put_fd(struct file_descriptor
*f
)
523 if(atomic_add(&f
->ref_count
, -1) == 1) {
528 static void remove_fd(struct ioctx
*ioctx
, int fd
)
530 struct file_descriptor
*f
;
532 mutex_lock(&ioctx
->io_mutex
);
534 if(fd
>= 0 && fd
< ioctx
->table_size
&& ioctx
->fds
[fd
]) {
537 ioctx
->fds
[fd
] = NULL
;
538 ioctx
->num_used_fds
--;
543 mutex_unlock(&ioctx
->io_mutex
);
549 static int new_fd(struct ioctx
*ioctx
, struct file_descriptor
*f
)
554 mutex_lock(&ioctx
->io_mutex
);
557 for(i
=0; i
<ioctx
->table_size
; i
++) {
564 fd
= ERR_NO_MORE_HANDLES
;
569 ioctx
->num_used_fds
++;
572 mutex_unlock(&ioctx
->io_mutex
);
577 static struct vnode
*get_vnode_from_fd(struct ioctx
*ioctx
, int fd
)
579 struct file_descriptor
*f
;
582 f
= get_fd(ioctx
, fd
);
590 inc_vnode_ref_count(v
);
598 static struct fs_container
*find_fs(const char *fs_name
)
600 struct fs_container
*fs
= fs_list
;
602 if(strcmp(fs_name
, fs
->name
) == 0) {
610 static struct ioctx
*get_current_ioctx(bool kernel
)
615 ioctx
= proc_get_kernel_proc()->ioctx
;
617 ioctx
= thread_get_current_thread()->proc
->ioctx
;
622 static int path_to_vnode(char *path
, struct vnode
**v
, bool kernel
)
626 struct vnode
*curr_v
;
627 struct vnode
*next_v
;
632 return ERR_INVALID_ARGS
;
634 // figure out if we need to start at root or at cwd
639 inc_vnode_ref_count(curr_v
);
641 struct ioctx
*ioctx
= get_current_ioctx(kernel
);
643 mutex_lock(&ioctx
->io_mutex
);
645 inc_vnode_ref_count(curr_v
);
646 mutex_unlock(&ioctx
->io_mutex
);
650 // dprintf("path_to_vnode: top of loop. p %p, *p = %c, p = '%s'\n", p, *p, p);
658 // walk to find the next component
659 for(next_p
= p
+1; *next_p
!= '\0' && *next_p
!= '/'; next_p
++);
665 while(*next_p
== '/');
668 // see if the .. is at the root of a mount
669 if(strcmp("..", p
) == 0 && curr_v
->mount
->root_vnode
== curr_v
) {
670 // move to the covered vnode so we pass the '..' parse to the underlying filesystem
671 if(curr_v
->mount
->covers_vnode
) {
672 next_v
= curr_v
->mount
->covers_vnode
;
673 inc_vnode_ref_count(next_v
);
674 dec_vnode_ref_count(curr_v
, true, false);
679 // tell the filesystem to parse this path
680 err
= curr_v
->mount
->fs
->calls
->fs_lookup(curr_v
->mount
->fscookie
, curr_v
->priv_vnode
, p
, &vnid
);
682 dec_vnode_ref_count(curr_v
, true, false);
686 // lookup the vnode, the call to fs_lookup should have caused a get_vnode to be called
687 // from inside the filesystem, thus the vnode would have to be in the list and it's
688 // ref count incremented at this point
689 mutex_lock(&vfs_vnode_mutex
);
690 next_v
= lookup_vnode(curr_v
->fsid
, vnid
);
691 mutex_unlock(&vfs_vnode_mutex
);
694 // pretty screwed up here
695 panic("path_to_vnode: could not lookup vnode (fsid 0x%x vnid 0x%Lx)\n", curr_v
->fsid
, vnid
);
696 err
= ERR_VFS_PATH_NOT_FOUND
;
697 dec_vnode_ref_count(curr_v
, true, false);
701 // decrease the ref count on the old dir we just looked up into
702 dec_vnode_ref_count(curr_v
, true, false);
707 // see if we hit a mount point
708 if(curr_v
->covered_by
) {
709 next_v
= curr_v
->covered_by
;
710 inc_vnode_ref_count(next_v
);
711 dec_vnode_ref_count(curr_v
, true, false);
722 // returns the vnode in the next to last segment of the path, returns the last
723 // portion in filename
724 static int path_to_dir_vnode(char *path
, struct vnode
**v
, char *filename
, bool kernel
)
728 p
= strrchr(path
, '/');
730 // this path is single segment with no '/' in it
732 strcpy(filename
, path
);
735 // replace the filename portion of the path with a '.'
736 strcpy(filename
, p
+1);
744 return path_to_vnode(path
, v
, kernel
);
747 void *vfs_new_ioctx(void *_parent_ioctx
)
751 struct ioctx
*parent_ioctx
;
753 parent_ioctx
= (struct ioctx
*)_parent_ioctx
;
755 table_size
= parent_ioctx
->table_size
;
757 table_size
= DEFAULT_FD_TABLE_SIZE
;
760 ioctx
= kmalloc(sizeof(struct ioctx
));
764 memset(ioctx
, 0, sizeof(struct ioctx
));
766 ioctx
->fds
= kmalloc(sizeof(struct file_descriptor
*) * table_size
);
767 if(ioctx
->fds
== NULL
) {
772 memset(ioctx
->fds
, 0, sizeof(struct file_descriptor
*) * table_size
);
774 if(mutex_init(&ioctx
->io_mutex
, "ioctx_mutex") < 0) {
781 * copy parent files if they dont have the close-on-exec flag set
786 mutex_lock(&parent_ioctx
->io_mutex
);
788 ioctx
->cwd
= parent_ioctx
->cwd
;
790 inc_vnode_ref_count(ioctx
->cwd
);
794 for(i
= 0; i
< table_size
; i
++) {
795 if(parent_ioctx
->fds
[i
] && !parent_ioctx
->fds
[i
]->coe
) {
796 ioctx
->fds
[i
]= parent_ioctx
->fds
[i
];
797 atomic_add(&ioctx
->fds
[i
]->ref_count
, 1);
801 mutex_unlock(&parent_ioctx
->io_mutex
);
803 ioctx
->cwd
= root_vnode
;
806 inc_vnode_ref_count(ioctx
->cwd
);
810 ioctx
->table_size
= table_size
;
815 int vfs_free_ioctx(void *_ioctx
)
817 struct ioctx
*ioctx
= (struct ioctx
*)_ioctx
;
821 dec_vnode_ref_count(ioctx
->cwd
, true, false);
823 mutex_lock(&ioctx
->io_mutex
);
825 for(i
=0; i
<ioctx
->table_size
; i
++) {
827 put_fd(ioctx
->fds
[i
]);
831 mutex_unlock(&ioctx
->io_mutex
);
833 mutex_destroy(&ioctx
->io_mutex
);
840 int vfs_init(kernel_args
*ka
)
842 dprintf("vfs_init: entry\n");
843 kprintf("initializing fs layer...\n");
845 vnode_table
= hash_init(VNODE_HASH_TABLE_SIZE
, offsetof(struct vnode
, next
),
846 &vnode_compare
, &vnode_hash
);
847 if(vnode_table
== NULL
)
848 panic("vfs_init: error creating vnode hash table\n");
850 mounts_table
= hash_init(MOUNTS_HASH_TABLE_SIZE
, offsetof(struct fs_mount
, next
),
851 &mount_compare
, &mount_hash
);
852 if(mounts_table
== NULL
)
853 panic("vfs_init: error creating mounts hash table\n");
858 if(mutex_init(&vfs_mutex
, "vfs_lock") < 0)
859 panic("vfs_init: error allocating vfs lock\n");
861 if(mutex_init(&vfs_mount_op_mutex
, "vfs_mount_op_lock") < 0)
862 panic("vfs_init: error allocating vfs_mount_op lock\n");
864 if(mutex_init(&vfs_mount_mutex
, "vfs_mount_lock") < 0)
865 panic("vfs_init: error allocating vfs_mount lock\n");
867 if(mutex_init(&vfs_vnode_mutex
, "vfs_vnode_lock") < 0)
868 panic("vfs_init: error allocating vfs_vnode lock\n");
879 dprintf("vfs_test() entry\n");
881 fd
= sys_open("/", STREAM_TYPE_DIR
, 0);
882 dprintf("fd = %d\n", fd
);
885 fd
= sys_open("/", STREAM_TYPE_DIR
, 0);
886 dprintf("fd = %d\n", fd
);
888 sys_create("/foo", STREAM_TYPE_DIR
);
889 sys_create("/foo/bar", STREAM_TYPE_DIR
);
890 sys_create("/foo/bar/gar", STREAM_TYPE_DIR
);
891 sys_create("/foo/bar/tar", STREAM_TYPE_DIR
);
894 fd
= sys_open("/foo/bar", STREAM_TYPE_DIR
, 0);
896 panic("unable to open /foo/bar\n");
902 sys_seek(fd
, 0, _SEEK_SET
);
904 len
= sys_read(fd
, buf
, -1, sizeof(buf
));
906 panic("readdir returned %Ld\n", (long long)len
);
908 dprintf("readdir returned name = '%s'\n", buf
);
914 // do some unlink tests
915 err
= sys_unlink("/foo/bar");
917 panic("unlink of full directory should not have passed\n");
918 sys_unlink("/foo/bar/gar");
919 sys_unlink("/foo/bar/tar");
920 err
= sys_unlink("/foo/bar");
922 panic("unlink of empty directory should have worked\n");
924 sys_create("/test", STREAM_TYPE_DIR
);
925 sys_create("/test", STREAM_TYPE_DIR
);
926 err
= sys_mount("/test", NULL
, "rootfs", NULL
);
928 panic("failed mount test\n");
933 fd
= sys_open("/boot", STREAM_TYPE_DIR
, 0);
934 dprintf("fd = %d\n", fd
);
937 fd
= sys_open("/boot", STREAM_TYPE_DIR
, 0);
939 panic("unable to open dir /boot\n");
944 sys_seek(fd
, 0, _SEEK_SET
);
946 len
= sys_read(fd
, buf
, -1, sizeof(buf
));
948 panic("readdir returned %Ld\n", (long long)len
);
950 dprintf("readdir returned name = '%s'\n", buf
);
957 fd
= sys_open("/boot/kernel", STREAM_TYPE_FILE
, 0);
959 panic("unable to open kernel file '/boot/kernel'\n");
964 len
= sys_read(fd
, buf
, 0, sizeof(buf
));
966 panic("failed on read\n");
967 dprintf("read returned %Ld\n", (long long)len
);
971 struct file_stat stat
;
973 err
= sys_rstat("/boot/kernel", &stat
);
975 panic("err stating '/boot/kernel'\n");
976 dprintf("stat results:\n");
977 dprintf("\tvnid 0x%Lx\n\ttype %d\n\tsize 0x%Lx\n", stat
.vnid
, stat
.type
, stat
.size
);
981 dprintf("vfs_test() done\n");
987 int vfs_register_filesystem(const char *name
, struct fs_calls
*calls
)
989 struct fs_container
*container
;
991 container
= (struct fs_container
*)kmalloc(sizeof(struct fs_container
));
992 if(container
== NULL
)
993 return ERR_NO_MEMORY
;
995 container
->name
= name
;
996 container
->calls
= calls
;
998 mutex_lock(&vfs_mutex
);
1000 container
->next
= fs_list
;
1001 fs_list
= container
;
1003 mutex_unlock(&vfs_mutex
);
1007 int vfs_mount(char *path
, const char *device
, const char *fs_name
, void *args
, bool kernel
)
1009 struct fs_mount
*mount
;
1011 struct vnode
*covered_vnode
= NULL
;
1015 dprintf("vfs_mount: entry. path = '%s', fs_name = '%s'\n", path
, fs_name
);
1018 mutex_lock(&vfs_mount_op_mutex
);
1020 mount
= (struct fs_mount
*)kmalloc(sizeof(struct fs_mount
));
1022 err
= ERR_NO_MEMORY
;
1026 memset(mount
, 0, sizeof(struct fs_mount
));
1028 mount
->mount_point
= kstrdup(path
);
1029 if(mount
->mount_point
== NULL
) {
1030 err
= ERR_NO_MEMORY
;
1034 mount
->fs
= find_fs(fs_name
);
1035 if(mount
->fs
== NULL
) {
1036 err
= ERR_VFS_INVALID_FS
;
1040 recursive_lock_create(&mount
->rlock
);
1041 mount
->id
= next_fsid
++;
1042 mount
->unmounting
= false;
1045 // we haven't mounted anything yet
1046 if(strcmp(path
, "/") != 0) {
1047 err
= ERR_VFS_GENERAL
;
1051 err
= mount
->fs
->calls
->fs_mount(&mount
->fscookie
, mount
->id
, device
, NULL
, &root_id
);
1053 err
= ERR_VFS_GENERAL
;
1057 mount
->covers_vnode
= NULL
; // this is the root mount
1059 err
= path_to_vnode(path
,&covered_vnode
,kernel
);
1064 if(!covered_vnode
) {
1065 err
= ERR_VFS_GENERAL
;
1069 // XXX insert check to make sure covered_vnode is a DIR, or maybe it's okay for it not to be
1071 if((covered_vnode
!= root_vnode
) && (covered_vnode
->mount
->root_vnode
== covered_vnode
)){
1072 err
= ERR_VFS_ALREADY_MOUNTPOINT
;
1076 mount
->covers_vnode
= covered_vnode
;
1079 err
= mount
->fs
->calls
->fs_mount(&mount
->fscookie
, mount
->id
, device
, NULL
, &root_id
);
1084 mutex_lock(&vfs_mount_mutex
);
1086 // insert mount struct into list
1087 hash_insert(mounts_table
, mount
);
1089 mutex_unlock(&vfs_mount_mutex
);
1091 err
= get_vnode(mount
->id
, root_id
, &mount
->root_vnode
, 0);
1095 // XXX may be a race here
1096 if(mount
->covers_vnode
)
1097 mount
->covers_vnode
->covered_by
= mount
->root_vnode
;
1100 root_vnode
= mount
->root_vnode
;
1102 mutex_unlock(&vfs_mount_op_mutex
);
1107 mount
->fs
->calls
->fs_unmount(mount
->fscookie
);
1109 if(mount
->covers_vnode
)
1110 dec_vnode_ref_count(mount
->covers_vnode
, true, false);
1112 recursive_lock_destroy(&mount
->rlock
);
1114 kfree(mount
->mount_point
);
1118 mutex_unlock(&vfs_mount_op_mutex
);
1123 int vfs_unmount(char *path
, bool kernel
)
1126 struct fs_mount
*mount
;
1130 dprintf("vfs_unmount: entry. path = '%s', kernel %d\n", path
, kernel
);
1133 err
= path_to_vnode(path
, &v
, kernel
);
1135 err
= ERR_VFS_PATH_NOT_FOUND
;
1139 mutex_lock(&vfs_mount_op_mutex
);
1141 mount
= fsid_to_mount(v
->fsid
);
1143 panic("vfs_unmount: fsid_to_mount failed on root vnode @%p of mount\n", v
);
1146 if(mount
->root_vnode
!= v
) {
1148 dec_vnode_ref_count(v
, true, false);
1149 err
= ERR_VFS_NOT_MOUNTPOINT
;
1153 /* grab the vnode master mutex to keep someone from creating a vnode
1154 while we're figuring out if we can continue */
1155 mutex_lock(&vfs_vnode_mutex
);
1157 /* simulate the root vnode having it's refcount decremented */
1158 mount
->root_vnode
->ref_count
-= 2;
1160 /* cycle through the list of vnodes associated with this mount and
1161 make sure all of them are not busy or have refs on them */
1163 for(v
= mount
->vnodes_head
; v
; v
= v
->mount_next
) {
1164 if(v
->busy
|| v
->ref_count
!= 0) {
1165 mount
->root_vnode
->ref_count
+= 2;
1166 mutex_unlock(&vfs_vnode_mutex
);
1167 dec_vnode_ref_count(mount
->root_vnode
, true, false);
1168 err
= ERR_VFS_FS_BUSY
;
1173 /* we can safely continue, mark all of the vnodes busy and this mount
1174 structure in unmounting state */
1175 for(v
= mount
->vnodes_head
; v
; v
= v
->mount_next
)
1176 if(v
!= mount
->root_vnode
)
1178 mount
->unmounting
= true;
1180 /* add 2 back to the root vnode's ref */
1181 mount
->root_vnode
->ref_count
+= 2;
1183 mutex_unlock(&vfs_vnode_mutex
);
1185 mount
->covers_vnode
->covered_by
= NULL
;
1186 dec_vnode_ref_count(mount
->covers_vnode
, true, false);
1188 /* release the ref on the root vnode twice */
1189 dec_vnode_ref_count(mount
->root_vnode
, true, false);
1190 dec_vnode_ref_count(mount
->root_vnode
, true, false);
1192 // XXX when full vnode cache in place, will need to force
1193 // a putvnode/removevnode here
1195 /* remove the mount structure from the hash table */
1196 mutex_lock(&vfs_mount_mutex
);
1197 hash_remove(mounts_table
, mount
);
1198 mutex_unlock(&vfs_mount_mutex
);
1200 mutex_unlock(&vfs_mount_op_mutex
);
1202 mount
->fs
->calls
->fs_unmount(mount
->fscookie
);
1204 kfree(mount
->mount_point
);
1210 mutex_unlock(&vfs_mount_op_mutex
);
1217 struct hash_iterator iter
;
1218 struct fs_mount
*mount
;
1221 dprintf("vfs_sync: entry.\n");
1224 /* cycle through and call sync on each mounted fs */
1225 mutex_lock(&vfs_mount_op_mutex
);
1226 mutex_lock(&vfs_mount_mutex
);
1228 hash_open(mounts_table
, &iter
);
1229 while((mount
= hash_next(mounts_table
, &iter
))) {
1230 mount
->fs
->calls
->fs_sync(mount
->fscookie
);
1232 hash_close(mounts_table
, &iter
, false);
1234 mutex_unlock(&vfs_mount_mutex
);
1235 mutex_unlock(&vfs_mount_op_mutex
);
1240 int vfs_opendir(char *path
, bool kernel
)
1246 struct file_descriptor
*f
;
1249 dprintf("vfs_opendir: entry. path = '%s', kernel %d\n", path
, kernel
);
1252 err
= path_to_vnode(path
, &v
, kernel
);
1256 err
= v
->mount
->fs
->calls
->fs_opendir(v
->mount
->fscookie
, v
->priv_vnode
, &cookie
);
1260 // file is opened, create a fd
1264 err
= ERR_NO_MEMORY
;
1272 fd
= new_fd(get_current_ioctx(kernel
), f
);
1274 err
= ERR_VFS_FD_TABLE_FULL
;
1281 free_fd(f
); // calls dec_vnode_ref_count
1284 dec_vnode_ref_count(v
, true, false);
1289 int vfs_closedir(int fd
, bool kernel
)
1291 struct file_descriptor
*f
;
1292 struct ioctx
*ioctx
;
1295 dprintf("vfs_closedir: entry. fd %d, kernel %d\n", fd
, kernel
);
1298 ioctx
= get_current_ioctx(kernel
);
1300 f
= get_fd(ioctx
, fd
);
1302 return ERR_INVALID_HANDLE
;
1305 return ERR_VFS_NOT_DIR
;
1307 remove_fd(ioctx
, fd
);
1313 int vfs_rewinddir(int fd
, bool kernel
)
1316 struct file_descriptor
*f
;
1320 dprintf("vfs_rewinddir: fd = %d, kernel %d\n", fd
, kernel
);
1323 f
= get_fd(get_current_ioctx(kernel
), fd
);
1325 err
= ERR_INVALID_HANDLE
;
1330 return ERR_VFS_NOT_DIR
;
1333 err
= v
->mount
->fs
->calls
->fs_rewinddir(v
->mount
->fscookie
, v
->priv_vnode
, f
->cookie
);
1342 int vfs_readdir(int fd
, void *buf
, size_t len
, bool kernel
)
1345 struct file_descriptor
*f
;
1349 dprintf("vfs_readdir: fd = %d, buf %p, len 0x%lx, kernel %d\n", fd
, buf
, len
, kernel
);
1352 f
= get_fd(get_current_ioctx(kernel
), fd
);
1354 err
= ERR_INVALID_HANDLE
;
1359 return ERR_VFS_NOT_DIR
;
1362 err
= v
->mount
->fs
->calls
->fs_readdir(v
->mount
->fscookie
, v
->priv_vnode
, f
->cookie
, buf
, len
);
1370 static int _vfs_open(struct vnode
*v
, int omode
, bool kernel
)
1374 struct file_descriptor
*f
;
1377 err
= v
->mount
->fs
->calls
->fs_open(v
->mount
->fscookie
, v
->priv_vnode
, &cookie
, omode
);
1381 // file is opened, create a fd
1385 err
= ERR_NO_MEMORY
;
1390 f
->coe
= omode
& O_CLOEXEC
? true : false;
1392 fd
= new_fd(get_current_ioctx(kernel
), f
);
1394 err
= ERR_VFS_FD_TABLE_FULL
;
1401 free_fd(f
); // calls dec_vnode_ref_count
1404 dec_vnode_ref_count(v
, true, false);
1409 int vfs_open(char *path
, int omode
, bool kernel
)
1415 dprintf("vfs_open: entry. path = '%s', omode %d, kernel %d\n", path
, omode
, kernel
);
1418 err
= path_to_vnode(path
, &v
, kernel
);
1422 return _vfs_open(v
, omode
, kernel
);
1425 int vfs_open_vnid(fs_id fsid
, vnode_id vnid
, int omode
, bool kernel
)
1431 dprintf("vfs_open_vnid: entry. fsid 0x%x, vnid 0x%Lx, omode %d, kernel %d\n", fsid
, vnid
, omode
, kernel
);
1434 err
= get_vnode(fsid
, vnid
, &v
, 0);
1438 return _vfs_open(v
, omode
, kernel
);
1441 int vfs_close(int fd
, bool kernel
)
1443 struct file_descriptor
*f
;
1444 struct ioctx
*ioctx
;
1447 dprintf("vfs_close: entry. fd %d, kernel %d\n", fd
, kernel
);
1450 ioctx
= get_current_ioctx(kernel
);
1452 f
= get_fd(ioctx
, fd
);
1454 return ERR_INVALID_HANDLE
;
1457 return ERR_VFS_IS_DIR
;
1459 remove_fd(ioctx
, fd
);
1465 int vfs_fsync(int fd
, bool kernel
)
1467 struct file_descriptor
*f
;
1472 dprintf("vfs_fsync: entry. fd %d kernel %d\n", fd
, kernel
);
1475 f
= get_fd(get_current_ioctx(kernel
), fd
);
1477 return ERR_INVALID_HANDLE
;
1480 err
= v
->mount
->fs
->calls
->fs_fsync(v
->mount
->fscookie
, v
->priv_vnode
);
1487 ssize_t
vfs_read(int fd
, void *buf
, off_t pos
, ssize_t len
, bool kernel
)
1490 struct file_descriptor
*f
;
1494 dprintf("vfs_read: fd = %d, buf %p, pos 0x%Lx, len 0x%lx, kernel %d\n", fd
, buf
, pos
, len
, kernel
);
1497 f
= get_fd(get_current_ioctx(kernel
), fd
);
1499 err
= ERR_INVALID_HANDLE
;
1504 err
= v
->mount
->fs
->calls
->fs_read(v
->mount
->fscookie
, v
->priv_vnode
, f
->cookie
, buf
, pos
, len
);
1512 ssize_t
vfs_write(int fd
, const void *buf
, off_t pos
, ssize_t len
, bool kernel
)
1515 struct file_descriptor
*f
;
1519 dprintf("vfs_write: fd = %d, buf %p, pos 0x%Lx, len 0x%lx, kernel %d\n", fd
, buf
, pos
, len
, kernel
);
1522 f
= get_fd(get_current_ioctx(kernel
), fd
);
1524 err
= ERR_INVALID_HANDLE
;
1529 err
= v
->mount
->fs
->calls
->fs_write(v
->mount
->fscookie
, v
->priv_vnode
, f
->cookie
, buf
, pos
, len
);
1537 int vfs_seek(int fd
, off_t pos
, seek_type seek_type
, bool kernel
)
1540 struct file_descriptor
*f
;
1544 dprintf("vfs_seek: fd = %d, pos 0x%Lx, seek_type %d, kernel %d\n", fd
, pos
, seek_type
, kernel
);
1547 f
= get_fd(get_current_ioctx(kernel
), fd
);
1549 err
= ERR_INVALID_HANDLE
;
1554 err
= v
->mount
->fs
->calls
->fs_seek(v
->mount
->fscookie
, v
->priv_vnode
, f
->cookie
, pos
, seek_type
);
1562 int vfs_ioctl(int fd
, int op
, void *buf
, size_t len
, bool kernel
)
1565 struct file_descriptor
*f
;
1569 dprintf("vfs_ioctl: fd = %d, op 0x%x, buf %p, len 0x%lx, kernel %d\n", fd
, op
, buf
, len
, kernel
);
1572 f
= get_fd(get_current_ioctx(kernel
), fd
);
1574 err
= ERR_INVALID_HANDLE
;
1579 err
= v
->mount
->fs
->calls
->fs_ioctl(v
->mount
->fscookie
, v
->priv_vnode
, f
->cookie
, op
, buf
, len
);
1587 int vfs_create(char *path
, void *args
, bool kernel
)
1592 char filename
[SYS_MAX_NAME_LEN
];
1596 dprintf("vfs_create: path '%s', args %p, kernel %d\n", path
, args
, kernel
);
1599 err
= path_to_dir_vnode(path
, &dir
, filename
, kernel
);
1603 err
= dir
->mount
->fs
->calls
->fs_create(dir
->mount
->fscookie
, dir
->priv_vnode
, filename
, args
, &vnid
);
1604 dec_vnode_ref_count(dir
, true, false);
1608 /* the file system has created a new vnode for us */
1609 // XXX for now just decrement a ref on it to kill it. We will
1610 // eventually create a new file handle and pass it back
1611 err
= get_vnode(dir
->fsid
, vnid
, &v
, false);
1616 dec_vnode_ref_count(v
, true, false);
1617 dec_vnode_ref_count(v
, true, false);
1625 int vfs_unlink(char *path
, bool kernel
)
1629 char filename
[SYS_MAX_NAME_LEN
];
1632 dprintf("vfs_unlink: path '%s', kernel %d\n", path
, kernel
);
1635 err
= path_to_dir_vnode(path
, &v
, filename
, kernel
);
1639 err
= v
->mount
->fs
->calls
->fs_unlink(v
->mount
->fscookie
, v
->priv_vnode
, filename
);
1641 dec_vnode_ref_count(v
, true, false);
1646 int vfs_rename(char *path
, char *newpath
, bool kernel
)
1648 struct vnode
*v1
, *v2
;
1649 char filename1
[SYS_MAX_NAME_LEN
];
1650 char filename2
[SYS_MAX_NAME_LEN
];
1653 err
= path_to_dir_vnode(path
, &v1
, filename1
, kernel
);
1657 err
= path_to_dir_vnode(path
, &v2
, filename2
, kernel
);
1661 if(v1
->fsid
!= v2
->fsid
) {
1662 err
= ERR_VFS_CROSS_FS_RENAME
;
1666 err
= v1
->mount
->fs
->calls
->fs_rename(v1
->mount
->fscookie
, v1
->priv_vnode
, filename1
, v2
->priv_vnode
, filename2
);
1669 dec_vnode_ref_count(v2
, true, false);
1671 dec_vnode_ref_count(v1
, true, false);
1676 int vfs_mkdir(char *path
, bool kernel
)
1680 char filename
[SYS_MAX_NAME_LEN
];
1683 dprintf("vfs_mkdir: path '%s', kernel %d\n", path
, kernel
);
1686 err
= path_to_dir_vnode(path
, &v
, filename
, kernel
);
1690 err
= v
->mount
->fs
->calls
->fs_mkdir(v
->mount
->fscookie
, v
->priv_vnode
, filename
);
1692 dec_vnode_ref_count(v
, true, false);
1697 int vfs_rmdir(char *path
, bool kernel
)
1701 char filename
[SYS_MAX_NAME_LEN
];
1704 dprintf("vfs_rmdir: path '%s', kernel %d\n", path
, kernel
);
1707 err
= path_to_dir_vnode(path
, &v
, filename
, kernel
);
1711 err
= v
->mount
->fs
->calls
->fs_rmdir(v
->mount
->fscookie
, v
->priv_vnode
, filename
);
1713 dec_vnode_ref_count(v
, true, false);
1718 int vfs_rstat(char *path
, struct file_stat
*stat
, bool kernel
)
1724 dprintf("vfs_rstat: path '%s', stat %p, kernel %d\n", path
, stat
, kernel
);
1727 err
= path_to_vnode(path
, &v
, kernel
);
1731 err
= v
->mount
->fs
->calls
->fs_rstat(v
->mount
->fscookie
, v
->priv_vnode
, stat
);
1733 dec_vnode_ref_count(v
, true, false);
1738 int vfs_wstat(char *path
, struct file_stat
*stat
, int stat_mask
, bool kernel
)
1744 dprintf("vfs_wstat: path '%s', stat %p, stat_mask %d, kernel %d\n", path
, stat
, stat_mask
, kernel
);
1747 err
= path_to_vnode(path
, &v
, kernel
);
1751 err
= v
->mount
->fs
->calls
->fs_wstat(v
->mount
->fscookie
, v
->priv_vnode
, stat
, stat_mask
);
1753 dec_vnode_ref_count(v
, true, false);
1758 int vfs_get_vnode_from_fd(int fd
, bool kernel
, void **vnode
)
1760 struct ioctx
*ioctx
;
1762 ioctx
= get_current_ioctx(kernel
);
1763 *vnode
= get_vnode_from_fd(ioctx
, fd
);
1766 return ERR_INVALID_HANDLE
;
1771 int vfs_get_vnode_from_path(const char *path
, bool kernel
, void **vnode
)
1775 char buf
[SYS_MAX_PATH_LEN
+1];
1778 dprintf("vfs_get_vnode_from_path: entry. path = '%s', kernel %d\n", path
, kernel
);
1781 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
1782 buf
[SYS_MAX_PATH_LEN
] = 0;
1784 err
= path_to_vnode(buf
, &v
, kernel
);
1794 int vfs_put_vnode_ptr(void *vnode
)
1796 struct vnode
*v
= vnode
;
1803 ssize_t
vfs_canpage(void *_v
)
1805 struct vnode
*v
= _v
;
1808 dprintf("vfs_canpage: vnode %p\n", v
);
1811 return v
->mount
->fs
->calls
->fs_canpage(v
->mount
->fscookie
, v
->priv_vnode
);
1814 ssize_t
vfs_readpage(void *_v
, iovecs
*vecs
, off_t pos
)
1816 struct vnode
*v
= _v
;
1819 dprintf("vfs_readpage: vnode %p, vecs %p, pos 0x%Lx\n", v
, vecs
, pos
);
1822 return v
->mount
->fs
->calls
->fs_readpage(v
->mount
->fscookie
, v
->priv_vnode
, vecs
, pos
);
1825 ssize_t
vfs_writepage(void *_v
, iovecs
*vecs
, off_t pos
)
1827 struct vnode
*v
= _v
;
1830 dprintf("vfs_writepage: vnode %p, vecs %p, pos 0x%Lx\n", v
, vecs
, pos
);
1833 return v
->mount
->fs
->calls
->fs_writepage(v
->mount
->fscookie
, v
->priv_vnode
, vecs
, pos
);
1836 static int vfs_get_cwd(char* buf
, size_t size
, bool kernel
)
1838 // Get current working directory from io context
1839 // struct vnode* v = get_current_ioctx(kernel)->cwd;
1843 dprintf("vfs_get_cwd: buf %p, 0x%lx\n", buf
, size
);
1845 //TODO: parse cwd back into a full path
1852 rc
= ERR_VFS_INSUFFICIENT_BUF
;
1855 // Tell caller all is ok
1859 static int vfs_set_cwd(char* path
, bool kernel
)
1861 struct ioctx
* curr_ioctx
;
1862 struct vnode
* v
= NULL
;
1863 struct vnode
* old_cwd
;
1864 struct file_stat stat
;
1868 dprintf("vfs_set_cwd: path='%s'\n", path
);
1871 // Get vnode for passed path, and bail if it failed
1872 rc
= path_to_vnode(path
, &v
, kernel
);
1877 rc
= v
->mount
->fs
->calls
->fs_rstat(v
->mount
->fscookie
, v
->priv_vnode
, &stat
);
1882 if(stat
.type
!= STREAM_TYPE_DIR
) {
1883 // nope, can't cwd to here
1884 rc
= ERR_VFS_WRONG_STREAM_TYPE
;
1888 // Get current io context and lock
1889 curr_ioctx
= get_current_ioctx(kernel
);
1890 mutex_lock(&curr_ioctx
->io_mutex
);
1893 old_cwd
= curr_ioctx
->cwd
;
1895 // Set the new vnode
1896 curr_ioctx
->cwd
= v
;
1899 mutex_unlock(&curr_ioctx
->io_mutex
);
1901 // Decrease ref count of previous working dir (as the ref is being replaced)
1903 dec_vnode_ref_count(old_cwd
, true, false);
1908 dec_vnode_ref_count(v
, true, false);
1913 static int vfs_dup(int fd
, bool kernel
)
1915 struct ioctx
* curr_ioctx
;
1916 struct file_descriptor
*f
;
1920 dprintf("vfs_dup: fd=%d\n", fd
);
1923 // Get current io context
1924 curr_ioctx
= get_current_ioctx(kernel
);
1926 // Try to get the fd structure
1927 f
= get_fd(curr_ioctx
, fd
);
1929 rc
= ERR_INVALID_HANDLE
;
1933 // now put the fd in place
1934 rc
= new_fd(curr_ioctx
, f
);
1944 static int vfs_dup2(int ofd
, int nfd
, bool kernel
)
1946 struct ioctx
* curr_ioctx
;
1947 struct file_descriptor
*evicted
;
1951 dprintf("vfs_dup2: ofd=%d nfd=%d\n", ofd
, nfd
);
1955 if((ofd
< 0) || (nfd
< 0)) {
1956 rc
= ERR_INVALID_HANDLE
;
1960 // Get current io context and lock
1961 curr_ioctx
= get_current_ioctx(kernel
);
1962 mutex_lock(&curr_ioctx
->io_mutex
);
1965 // Check for upper boundary, we do in the locked part
1966 // because in the future the fd table might be resizeable
1967 if((ofd
>= curr_ioctx
->table_size
) || !curr_ioctx
->fds
[ofd
]) {
1968 rc
= ERR_INVALID_HANDLE
;
1971 if((nfd
>= curr_ioctx
->table_size
)) {
1972 rc
= ERR_INVALID_HANDLE
;
1977 // Check for identity, note that it cannot be made above
1978 // because we always want to return an error on invalid
1981 mutex_unlock(&curr_ioctx
->io_mutex
);
1987 evicted
= curr_ioctx
->fds
[nfd
];
1988 atomic_add(&curr_ioctx
->fds
[ofd
]->ref_count
, 1);
1989 curr_ioctx
->fds
[nfd
]= curr_ioctx
->fds
[ofd
];
1993 mutex_unlock(&curr_ioctx
->io_mutex
);
1996 // Say bye bye to the evicted fd
2006 mutex_unlock(&curr_ioctx
->io_mutex
);
2011 int sys_mount(const char *path
, const char *device
, const char *fs_name
, void *args
)
2013 char buf
[SYS_MAX_PATH_LEN
+1];
2015 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
2016 buf
[SYS_MAX_PATH_LEN
] = 0;
2018 return vfs_mount(buf
, device
, fs_name
, args
, true);
2021 int sys_unmount(const char *path
)
2023 char buf
[SYS_MAX_PATH_LEN
+1];
2025 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
2026 buf
[SYS_MAX_PATH_LEN
] = 0;
2028 return vfs_unmount(buf
, true);
2036 int sys_opendir(const char *path
)
2038 char buf
[SYS_MAX_PATH_LEN
+1];
2040 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
2041 buf
[SYS_MAX_PATH_LEN
] = 0;
2043 return vfs_opendir(buf
, true);
2046 int sys_closedir(int fd
)
2048 return vfs_closedir(fd
, true);
2051 int sys_rewinddir(int fd
)
2053 return vfs_rewinddir(fd
, true);
2056 int sys_readdir(int fd
, void *buf
, size_t len
)
2058 return vfs_readdir(fd
, buf
, len
, true);
2061 int sys_open(const char *path
, int omode
)
2063 char buf
[SYS_MAX_PATH_LEN
+1];
2065 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
2066 buf
[SYS_MAX_PATH_LEN
] = 0;
2068 return vfs_open(buf
, omode
, true);
2071 int sys_close(int fd
)
2073 return vfs_close(fd
, true);
2076 int sys_fsync(int fd
)
2078 return vfs_fsync(fd
, true);
2081 ssize_t
sys_read(int fd
, void *buf
, off_t pos
, ssize_t len
)
2083 return vfs_read(fd
, buf
, pos
, len
, true);
2086 ssize_t
sys_write(int fd
, const void *buf
, off_t pos
, ssize_t len
)
2088 return vfs_write(fd
, buf
, pos
, len
, true);
2091 int sys_seek(int fd
, off_t pos
, seek_type seek_type
)
2093 return vfs_seek(fd
, pos
, seek_type
, true);
2096 int sys_ioctl(int fd
, int op
, void *buf
, size_t len
)
2098 return vfs_ioctl(fd
, op
, buf
, len
, true);
2101 int sys_create(const char *path
)
2103 char buf
[SYS_MAX_PATH_LEN
+1];
2105 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
2106 buf
[SYS_MAX_PATH_LEN
] = 0;
2108 return vfs_create(buf
, NULL
, true);
2111 int sys_unlink(const char *path
)
2113 char buf
[SYS_MAX_PATH_LEN
+1];
2115 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
2116 buf
[SYS_MAX_PATH_LEN
] = 0;
2118 return vfs_unlink(buf
, true);
2121 int sys_rename(const char *oldpath
, const char *newpath
)
2123 char buf1
[SYS_MAX_PATH_LEN
+1];
2124 char buf2
[SYS_MAX_PATH_LEN
+1];
2126 strncpy(buf1
, oldpath
, SYS_MAX_PATH_LEN
);
2127 buf1
[SYS_MAX_PATH_LEN
] = 0;
2129 strncpy(buf2
, newpath
, SYS_MAX_PATH_LEN
);
2130 buf2
[SYS_MAX_PATH_LEN
] = 0;
2132 return vfs_rename(buf1
, buf2
, true);
2135 int sys_mkdir(const char *path
)
2137 char buf
[SYS_MAX_PATH_LEN
+1];
2139 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
2140 buf
[SYS_MAX_PATH_LEN
] = 0;
2142 return vfs_mkdir(buf
, true);
2145 int sys_rmdir(const char *path
)
2147 char buf
[SYS_MAX_PATH_LEN
+1];
2149 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
2150 buf
[SYS_MAX_PATH_LEN
] = 0;
2152 return vfs_rmdir(buf
, true);
2155 int sys_rstat(const char *path
, struct file_stat
*stat
)
2157 char buf
[SYS_MAX_PATH_LEN
+1];
2159 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
2160 buf
[SYS_MAX_PATH_LEN
] = 0;
2162 return vfs_rstat(buf
, stat
, true);
2165 int sys_wstat(const char *path
, struct file_stat
*stat
, int stat_mask
)
2167 char buf
[SYS_MAX_PATH_LEN
+1];
2169 strncpy(buf
, path
, SYS_MAX_PATH_LEN
);
2170 buf
[SYS_MAX_PATH_LEN
] = 0;
2172 return vfs_wstat(buf
, stat
, stat_mask
, true);
2175 char* sys_getcwd(char *buf
, size_t size
)
2177 char path
[SYS_MAX_PATH_LEN
];
2181 dprintf("sys_getcwd: buf %p, 0x%lx\n", buf
, size
);
2184 // Call vfs to get current working directory
2185 rc
= vfs_get_cwd(path
,SYS_MAX_PATH_LEN
-1,true);
2186 path
[SYS_MAX_PATH_LEN
-1] = 0;
2188 // Copy back the result
2189 strncpy(buf
,path
,size
);
2191 // Return either NULL or the buffer address to indicate failure or success
2192 return (rc
< 0) ? NULL
: buf
;
2195 int sys_setcwd(const char* _path
)
2197 char path
[SYS_MAX_PATH_LEN
];
2200 dprintf("sys_setcwd: path=%p\n", _path
);
2203 // Copy new path to kernel space
2204 strncpy(path
, _path
, SYS_MAX_PATH_LEN
-1);
2205 path
[SYS_MAX_PATH_LEN
-1] = 0;
2207 // Call vfs to set new working directory
2208 return vfs_set_cwd(path
,true);
2213 return vfs_dup(fd
, true);
2216 int sys_dup2(int ofd
, int nfd
)
2218 return vfs_dup2(ofd
, nfd
, true);
2221 int user_mount(const char *upath
, const char *udevice
, const char *ufs_name
, void *args
)
2223 char path
[SYS_MAX_PATH_LEN
+1];
2224 char fs_name
[SYS_MAX_OS_NAME_LEN
+1];
2225 char device
[SYS_MAX_PATH_LEN
+1];
2228 if(is_kernel_address(upath
))
2229 return ERR_VM_BAD_USER_MEMORY
;
2231 if(is_kernel_address(ufs_name
))
2232 return ERR_VM_BAD_USER_MEMORY
;
2235 if(is_kernel_address(udevice
))
2236 return ERR_VM_BAD_USER_MEMORY
;
2239 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
);
2242 path
[SYS_MAX_PATH_LEN
] = 0;
2244 rc
= user_strncpy(fs_name
, ufs_name
, SYS_MAX_OS_NAME_LEN
);
2247 fs_name
[SYS_MAX_OS_NAME_LEN
] = 0;
2250 rc
= user_strncpy(device
, udevice
, SYS_MAX_PATH_LEN
);
2253 device
[SYS_MAX_PATH_LEN
] = 0;
2258 return vfs_mount(path
, device
, fs_name
, args
, false);
2261 int user_unmount(const char *upath
)
2263 char path
[SYS_MAX_PATH_LEN
+1];
2266 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
);
2269 path
[SYS_MAX_PATH_LEN
] = 0;
2271 return vfs_unmount(path
, false);
2279 int user_opendir(const char *upath
)
2281 char path
[SYS_MAX_PATH_LEN
];
2284 if(is_kernel_address(upath
))
2285 return ERR_VM_BAD_USER_MEMORY
;
2287 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
-1);
2290 path
[SYS_MAX_PATH_LEN
-1] = 0;
2292 return vfs_opendir(path
, false);
2295 int user_closedir(int fd
)
2297 return vfs_closedir(fd
, false);
2300 int user_rewinddir(int fd
)
2302 return vfs_rewinddir(fd
, false);
2305 int user_readdir(int fd
, void *buf
, size_t len
)
2307 return vfs_readdir(fd
, buf
, len
, false);
2310 int user_open(const char *upath
, int omode
)
2312 char path
[SYS_MAX_PATH_LEN
];
2315 if(is_kernel_address(upath
))
2316 return ERR_VM_BAD_USER_MEMORY
;
2318 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
-1);
2321 path
[SYS_MAX_PATH_LEN
-1] = 0;
2323 return vfs_open(path
, omode
, false);
2326 int user_close(int fd
)
2328 return vfs_close(fd
, false);
2331 int user_fsync(int fd
)
2333 return vfs_fsync(fd
, false);
2336 ssize_t
user_read(int fd
, void *buf
, off_t pos
, ssize_t len
)
2338 if(is_kernel_address(buf
))
2339 return ERR_VM_BAD_USER_MEMORY
;
2341 return vfs_read(fd
, buf
, pos
, len
, false);
2344 ssize_t
user_write(int fd
, const void *buf
, off_t pos
, ssize_t len
)
2346 if(is_kernel_address(buf
))
2347 return ERR_VM_BAD_USER_MEMORY
;
2349 return vfs_write(fd
, buf
, pos
, len
, false);
2352 int user_seek(int fd
, off_t pos
, seek_type seek_type
)
2354 return vfs_seek(fd
, pos
, seek_type
, false);
2357 int user_ioctl(int fd
, int op
, void *buf
, size_t len
)
2359 if(is_kernel_address(buf
))
2360 return ERR_VM_BAD_USER_MEMORY
;
2361 return vfs_ioctl(fd
, op
, buf
, len
, false);
2364 int user_create(const char *upath
)
2366 char path
[SYS_MAX_PATH_LEN
];
2369 if(is_kernel_address(upath
))
2370 return ERR_VM_BAD_USER_MEMORY
;
2372 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
-1);
2375 path
[SYS_MAX_PATH_LEN
-1] = 0;
2377 return vfs_create(path
, NULL
, false);
2380 int user_unlink(const char *upath
)
2382 char path
[SYS_MAX_PATH_LEN
+1];
2385 if(is_kernel_address(upath
))
2386 return ERR_VM_BAD_USER_MEMORY
;
2388 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
);
2391 path
[SYS_MAX_PATH_LEN
] = 0;
2393 return vfs_unlink(path
, false);
2396 int user_rename(const char *uoldpath
, const char *unewpath
)
2398 char oldpath
[SYS_MAX_PATH_LEN
+1];
2399 char newpath
[SYS_MAX_PATH_LEN
+1];
2402 if(is_kernel_address(uoldpath
))
2403 return ERR_VM_BAD_USER_MEMORY
;
2405 if(is_kernel_address(unewpath
))
2406 return ERR_VM_BAD_USER_MEMORY
;
2408 rc
= user_strncpy(oldpath
, uoldpath
, SYS_MAX_PATH_LEN
);
2411 oldpath
[SYS_MAX_PATH_LEN
] = 0;
2413 rc
= user_strncpy(newpath
, unewpath
, SYS_MAX_PATH_LEN
);
2416 newpath
[SYS_MAX_PATH_LEN
] = 0;
2418 return vfs_rename(oldpath
, newpath
, false);
2421 int user_mkdir(const char *upath
)
2423 char path
[SYS_MAX_PATH_LEN
];
2426 if(is_kernel_address(upath
))
2427 return ERR_VM_BAD_USER_MEMORY
;
2429 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
-1);
2432 path
[SYS_MAX_PATH_LEN
-1] = 0;
2434 return vfs_mkdir(path
, false);
2437 int user_rmdir(const char *upath
)
2439 char path
[SYS_MAX_PATH_LEN
+1];
2442 if(is_kernel_address(upath
))
2443 return ERR_VM_BAD_USER_MEMORY
;
2445 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
);
2448 path
[SYS_MAX_PATH_LEN
] = 0;
2450 return vfs_rmdir(path
, false);
2453 int user_rstat(const char *upath
, struct file_stat
*ustat
)
2455 char path
[SYS_MAX_PATH_LEN
];
2456 struct file_stat stat
;
2459 if(is_kernel_address(upath
))
2460 return ERR_VM_BAD_USER_MEMORY
;
2462 if(is_kernel_address(ustat
))
2463 return ERR_VM_BAD_USER_MEMORY
;
2465 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
-1);
2468 path
[SYS_MAX_PATH_LEN
-1] = 0;
2470 rc
= vfs_rstat(path
, &stat
, false);
2474 rc2
= user_memcpy(ustat
, &stat
, sizeof(struct file_stat
));
2481 int user_wstat(const char *upath
, struct file_stat
*ustat
, int stat_mask
)
2483 char path
[SYS_MAX_PATH_LEN
+1];
2484 struct file_stat stat
;
2487 if(is_kernel_address(upath
))
2488 return ERR_VM_BAD_USER_MEMORY
;
2490 if(is_kernel_address(ustat
))
2491 return ERR_VM_BAD_USER_MEMORY
;
2493 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
);
2496 path
[SYS_MAX_PATH_LEN
] = 0;
2498 rc
= user_memcpy(&stat
, ustat
, sizeof(struct file_stat
));
2502 return vfs_wstat(path
, &stat
, stat_mask
, false);
2505 int user_getcwd(char *buf
, size_t size
)
2507 char path
[SYS_MAX_PATH_LEN
];
2511 dprintf("user_getcwd: buf %p, 0x%lx\n", buf
, size
);
2514 // Check if userspace address is inside "shared" kernel space
2515 if(is_kernel_address(buf
))
2516 return NULL
; //ERR_VM_BAD_USER_MEMORY;
2518 // Call vfs to get current working directory
2519 rc
= vfs_get_cwd(path
, SYS_MAX_PATH_LEN
-1, false);
2523 // Copy back the result
2524 rc2
= user_strncpy(buf
, path
, size
);
2531 int user_setcwd(const char* upath
)
2533 char path
[SYS_MAX_PATH_LEN
];
2537 dprintf("user_setcwd: path=%p\n", upath
);
2540 // Check if userspace address is inside "shared" kernel space
2541 if(is_kernel_address(upath
))
2542 return ERR_VM_BAD_USER_MEMORY
;
2544 // Copy new path to kernel space
2545 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
-1);
2549 path
[SYS_MAX_PATH_LEN
-1] = 0;
2551 // Call vfs to set new working directory
2552 return vfs_set_cwd(path
,false);
2555 int user_dup(int fd
)
2557 return vfs_dup(fd
, false);
2560 int user_dup2(int ofd
, int nfd
)
2562 return vfs_dup2(ofd
, nfd
, false);
2565 image_id
vfs_load_fs_module(const char *name
)
2568 void (*bootstrap
)();
2569 char path
[SYS_MAX_PATH_LEN
];
2571 sprintf(path
, "/boot/addons/fs/%s", name
);
2573 id
= elf_load_kspace(path
, "");
2577 bootstrap
= (void *)elf_lookup_symbol(id
, "fs_bootstrap");
2579 return ERR_VFS_INVALID_FS
;
2586 int vfs_bootstrap_all_filesystems(void)
2591 kprintf("bootstrapping all built in file systems...\n");
2593 // bootstrap the root filesystem
2596 kprintf("\tmounting /");
2597 err
= sys_mount("/", NULL
, "rootfs", NULL
);
2599 panic("error mounting rootfs!\n");
2603 // bootstrap the bootfs
2608 err
= sys_mount("/boot", NULL
, "bootfs", NULL
);
2610 panic("error mounting bootfs\n");
2612 // bootstrap the devfs
2617 err
= sys_mount("/dev", NULL
, "devfs", NULL
);
2619 panic("error mounting devfs\n");
2621 // bootstrap the pipefs
2626 err
= sys_mount("/pipe", NULL
, "pipefs", NULL
);
2628 panic("error mounting pipefs\n");
2632 fd
= sys_opendir("/boot/addons/fs");
2635 char buf
[SYS_MAX_NAME_LEN
];
2637 while((len
= sys_readdir(fd
, buf
, sizeof(buf
))) > 0) {
2638 dprintf("loading '%s' fs module\n", buf
);
2639 vfs_load_fs_module(buf
);
2647 int vfs_getrlimit(int resource
, struct rlimit
* rlp
)
2656 struct ioctx
* ioctx
= get_current_ioctx(false);
2658 mutex_lock(&ioctx
->io_mutex
);
2660 rlp
->rlim_cur
= ioctx
->table_size
;
2661 rlp
->rlim_max
= MAX_FD_TABLE_SIZE
;
2663 mutex_unlock(&ioctx
->io_mutex
);
2673 static int vfs_resize_fd_table(struct ioctx
* ioctx
, const int new_size
)
2678 if (new_size
< 0 || new_size
> MAX_FD_TABLE_SIZE
) {
2682 mutex_lock(&ioctx
->io_mutex
);
2684 if (new_size
< ioctx
->table_size
) {
2687 /* Make sure none of the fds being dropped are in use */
2688 for(i
= new_size
; i
< ioctx
->table_size
; i
++) {
2689 if (ioctx
->fds
[i
]) {
2695 new_fds
= kmalloc(sizeof(struct file_descriptor
*) * new_size
);
2701 memcpy(new_fds
, ioctx
->fds
, sizeof(struct file_descriptor
*) * new_size
);
2703 new_fds
= kmalloc(sizeof(struct file_descriptor
*) * new_size
);
2709 memcpy(new_fds
, ioctx
->fds
, sizeof(struct file_descriptor
*) * ioctx
->table_size
);
2710 memset(((char *)new_fds
) + (sizeof(struct file_descriptor
*) * ioctx
->table_size
), 0,
2711 (sizeof(struct file_descriptor
*) * new_size
) - (sizeof(struct file_descriptor
*) * ioctx
->table_size
));
2715 ioctx
->fds
= new_fds
;
2716 ioctx
->table_size
= new_size
;
2718 mutex_unlock(&ioctx
->io_mutex
);
2723 mutex_unlock(&ioctx
->io_mutex
);
2728 int vfs_setrlimit(int resource
, const struct rlimit
* rlp
)
2736 return vfs_resize_fd_table(get_current_ioctx(false), rlp
->rlim_cur
);