diff --git a/include/sys/mount.h b/include/sys/mount.h index 71feb8a15..0115b0ef2 100644 --- a/include/sys/mount.h +++ b/include/sys/mount.h @@ -34,7 +34,7 @@ typedef struct vfsconf vfsconf_t; typedef struct statvfs statvfs_t; /* VFS operations */ -typedef int vfs_mount_t(mount_t *m); +typedef int vfs_mount_t(mount_t *m, vnode_t *vsrc); typedef int vfs_root_t(mount_t *m, vnode_t **vp); typedef int vfs_statvfs_t(mount_t *m, statvfs_t *sb); typedef int vfs_vget_t(mount_t *m, ino_t ino, vnode_t **vp); @@ -78,8 +78,8 @@ typedef struct mount { void *mnt_data; /* Filesystem-specific arbitrary data */ } mount_t; -static inline int VFS_MOUNT(mount_t *m) { - return m->mnt_vfsops->vfs_mount(m); +static inline int VFS_MOUNT(mount_t *m, vnode_t *vsrc) { + return m->mnt_vfsops->vfs_mount(m, vsrc); } static inline int VFS_ROOT(mount_t *m, vnode_t **vp) { @@ -105,9 +105,10 @@ vfsconf_t *vfs_get_by_name(const char *name); * list. */ mount_t *vfs_mount_alloc(vnode_t *v, vfsconf_t *vfc); -/* Mount a new instance of the filesystem vfc at the vnode v. Does not support - * remounting. TODO: Additional filesystem-specific arguments. */ -int vfs_domount(vfsconf_t *vfc, vnode_t *v); +/* Mount a new instance of the filesystem vfc at the vnode vdst. Does not + * support remounting. Use vsrc as a source for fs data if not NULL. + *TODO: Additional filesystem-specific arguments. */ +int vfs_domount(vfsconf_t *vfc, vnode_t *vdst, vnode_t *vsrc); #else /* !_KERNEL */ #include diff --git a/include/sys/syscallargs.h b/include/sys/syscallargs.h index 31b095262..2f6e1b4ef 100644 --- a/include/sys/syscallargs.h +++ b/include/sys/syscallargs.h @@ -79,6 +79,7 @@ typedef struct { } mmap_args_t; typedef struct { + SYSCALLARG(const char *) source; SYSCALLARG(const char *) type; SYSCALLARG(const char *) path; } mount_args_t; diff --git a/include/sys/vfs.h b/include/sys/vfs.h index f42d0b4a9..a71f0fed3 100644 --- a/include/sys/vfs.h +++ b/include/sys/vfs.h @@ -106,7 +106,7 @@ int do_utimensat(proc_t *p, int fd, char *path, timespec_t *times, int flag); int do_pathconf(proc_t *p, char *path, int name, register_t *res); /* Mount a new instance of the filesystem named fs at the requested path. */ -int do_mount(proc_t *p, const char *fs, const char *path); +int do_mount(proc_t *p, const char *source, const char *fs, const char *path); int do_getdents(proc_t *p, int fd, uio_t *uio); int do_statvfs(proc_t *p, char *path, statvfs_t *buf); int do_fstatvfs(proc_t *p, int fd, statvfs_t *buf); diff --git a/sys/kern/devfs.c b/sys/kern/devfs.c index ad11b787b..4ada4a4e9 100644 --- a/sys/kern/devfs.c +++ b/sys/kern/devfs.c @@ -374,7 +374,7 @@ static vnodeops_t devfs_dir_vnodeops = { /* We are using a single vnode for each devfs_node * instead of allocating a new one each time, to simplify things. */ -static int devfs_mount(mount_t *m) { +static int devfs_mount(mount_t *m, vnode_t *vsrc) { devfs.root->dn_vnode->v_mount = m; m->mnt_data = &devfs; return 0; diff --git a/sys/kern/initrd.c b/sys/kern/initrd.c index d3b7cdb64..da5872827 100644 --- a/sys/kern/initrd.c +++ b/sys/kern/initrd.c @@ -340,7 +340,7 @@ static int initrd_root(mount_t *m, vnode_t **v) { return 0; } -static int initrd_mount(mount_t *m) { +static int initrd_mount(mount_t *m, vnode_t *vsrc) { vnode_t *root = vnode_new(V_DIR, &initrd_vops, root_node); root->v_mount = m; root_node->c_vnode = root; diff --git a/sys/kern/main.c b/sys/kern/main.c index 850cf927d..a6b30d190 100644 --- a/sys/kern/main.c +++ b/sys/kern/main.c @@ -34,9 +34,9 @@ userspace init program. */ static void mount_fs(void) { proc_t *p = &proc0; - do_mount(p, "initrd", "/"); - do_mount(p, "devfs", "/dev"); - do_mount(p, "tmpfs", "/tmp"); + do_mount(p, NULL, "initrd", "/"); + do_mount(p, NULL, "devfs", "/dev"); + do_mount(p, NULL, "tmpfs", "/tmp"); do_fchmodat(p, AT_FDCWD, "/tmp", ACCESSPERMS | S_ISTXT, 0); } diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 13f0faab3..feade4ff8 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -338,9 +338,11 @@ static int sys_getcwd(proc_t *p, getcwd_args_t *args, register_t *res) { static int sys_mount(proc_t *p, mount_args_t *args, register_t *res) { const char *u_type = SCARG(args, type); const char *u_path = SCARG(args, path); + const char *u_source = SCARG(args, source); char *type = kmalloc(M_TEMP, PATH_MAX, 0); char *path = kmalloc(M_TEMP, PATH_MAX, 0); + char *source = NULL; size_t n = 0; int error; @@ -351,13 +353,21 @@ static int sys_mount(proc_t *p, mount_args_t *args, register_t *res) { /* Copyout pathname. */ if ((error = copyinstr(u_path, path, PATH_MAX, &n))) goto end; + /* Alloc and copyout source pathanme */ + if (u_source) { + source = kmalloc(M_TEMP, PATH_MAX, 0); + if ((error = copyinstr(u_source, source, PATH_MAX, &n))) + goto end; + } klog("mount(\"%s\", \"%s\")", path, type); - error = do_mount(p, type, path); + error = do_mount(p, source, type, path); end: kfree(M_TEMP, type); kfree(M_TEMP, path); + if (u_source) + kfree(M_TEMP, source); return error; } diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 0bb23c2ae..1dfb06c42 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -24,7 +24,7 @@ 12 { void *sys_sbrk(intptr_t increment); } 13 { void *sys_mmap(void *addr, size_t len, int prot, int flags, \ int fd, off_t pos); } -14 { int sys_mount(const char *type, const char *path); } +14 { int sys_mount(const char *source, const char *type, const char *path); } 15 { int sys_getdents(int fd, void *buf, size_t len); } 16 { int sys_dup(int fd); } 17 { int sys_dup2(int from, int to); } diff --git a/sys/kern/sysent.h b/sys/kern/sysent.h index d91464cfe..57d9f6dcb 100644 --- a/sys/kern/sysent.h +++ b/sys/kern/sysent.h @@ -110,7 +110,7 @@ struct sysent sysent[] = { [SYS_fstat] = { .name = "fstat", .nargs = 2, .call = (syscall_t *)sys_fstat }, [SYS_sbrk] = { .name = "sbrk", .nargs = 1, .call = (syscall_t *)sys_sbrk }, [SYS_mmap] = { .name = "mmap", .nargs = 6, .call = (syscall_t *)sys_mmap }, - [SYS_mount] = { .name = "mount", .nargs = 2, .call = (syscall_t *)sys_mount }, + [SYS_mount] = { .name = "mount", .nargs = 3, .call = (syscall_t *)sys_mount }, [SYS_getdents] = { .name = "getdents", .nargs = 3, .call = (syscall_t *)sys_getdents }, [SYS_dup] = { .name = "dup", .nargs = 1, .call = (syscall_t *)sys_dup }, [SYS_dup2] = { .name = "dup2", .nargs = 2, .call = (syscall_t *)sys_dup2 }, diff --git a/sys/kern/tmpfs.c b/sys/kern/tmpfs.c index 66bd0c560..411a0cea7 100644 --- a/sys/kern/tmpfs.c +++ b/sys/kern/tmpfs.c @@ -1041,7 +1041,7 @@ static void tmpfs_update_time(tmpfs_node_t *v, tmpfs_time_type_t type) { /* tmpfs vfs operations */ -static int tmpfs_mount(mount_t *mp) { +static int tmpfs_mount(mount_t *mp, vnode_t *vsrc) { /* Allocate the tmpfs mount structure and fill it. */ tmpfs_mount_t *tfm = &tmpfs; diff --git a/sys/kern/vfs.c b/sys/kern/vfs.c index 5983ba1a5..c056537d4 100644 --- a/sys/kern/vfs.c +++ b/sys/kern/vfs.c @@ -131,24 +131,24 @@ mount_t *vfs_mount_alloc(vnode_t *v, vfsconf_t *vfc) { return m; } -int vfs_domount(vfsconf_t *vfc, vnode_t *v) { +int vfs_domount(vfsconf_t *vfc, vnode_t *vdst, vnode_t *vsrc) { int error; /* Start by checking whether this vnode can be used for mounting */ - if (v->v_type != V_DIR) + if (vdst->v_type != V_DIR) return ENOTDIR; - if (is_mountpoint(v)) + if (is_mountpoint(vdst)) return EBUSY; /* TODO: Mark the vnode is in-progress of mounting? See VI_MOUNT in FreeBSD */ - mount_t *m = vfs_mount_alloc(v, vfc); + mount_t *m = vfs_mount_alloc(vdst, vfc); /* Mount the filesystem. */ - if ((error = VFS_MOUNT(m))) + if ((error = VFS_MOUNT(m, vsrc))) return error; - v->v_mountedhere = m; + vdst->v_mountedhere = m; WITH_MTX_LOCK (&mount_list_mtx) TAILQ_INSERT_TAIL(&mount_list, m, mnt_list); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index b33f25cba..5952badda 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -218,17 +218,19 @@ int do_fstatat(proc_t *p, int fd, char *path, stat_t *sb, int flag) { return error; } -int do_mount(proc_t *p, const char *fs, const char *path) { +int do_mount(proc_t *p, const char *source, const char *fs, const char *path) { vfsconf_t *vfs; - vnode_t *v; + vnode_t *vdest, *vsource = NULL; int error; if (!(vfs = vfs_get_by_name(fs))) return EINVAL; - if ((error = vfs_namelookup(path, &v, &p->p_cred))) + if ((error = vfs_namelookup(path, &vdest, &p->p_cred))) + return error; + if (source && (error = vfs_namelookup(source, &vsource, &p->p_cred))) return error; - return vfs_domount(vfs, v); + return vfs_domount(vfs, vdest, vsource); } int do_getdents(proc_t *p, int fd, uio_t *uio) {