diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2016-08-19 20:04:28 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2016-08-19 20:12:06 +0000 |
commit | fa4a6a633d447e433f22c28800fcd967975ef403 (patch) | |
tree | a4d73ca8422759127a6ece1bae27e29549036fff /usr/src | |
parent | 533b6005f11009bfbddd0c485c45a745d6ca290f (diff) | |
download | illumos-joyent-fa4a6a633d447e433f22c28800fcd967975ef403.tar.gz |
OS-5545 lxbrand move mount(2) emulation into kernel
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Ryan Zezeski <ryan.zezeski@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/lx_brand.c | 6 | ||||
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/mount.c | 691 | ||||
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/os/lx_syscall.c | 10 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/sys/lx_syscalls.h | 6 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/syscall/lx_mount.c | 650 | ||||
-rw-r--r-- | usr/src/uts/intel/Makefile.files | 1 |
7 files changed, 733 insertions, 633 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c index e85c19e6dd..274d5435a4 100644 --- a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c +++ b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c @@ -1177,7 +1177,7 @@ static lx_syscall_handler_t lx_handlers[] = { NULL, /* 163: acct */ lx_settimeofday, /* 164: settimeofday */ lx_mount, /* 165: mount */ - lx_umount2, /* 166: umount2 */ + NULL, /* 166: umount2 */ NULL, /* 167: swapon */ NULL, /* 168: swapoff */ lx_reboot, /* 169: reboot */ @@ -1364,7 +1364,7 @@ static lx_syscall_handler_t lx_handlers[] = { NULL, /* 19: lseek */ NULL, /* 20: getpid */ lx_mount, /* 21: mount */ - lx_umount, /* 22: umount */ + NULL, /* 22: umount */ lx_setuid16, /* 23: setuid16 */ lx_getuid16, /* 24: getuid16 */ lx_stime, /* 25: stime */ @@ -1394,7 +1394,7 @@ static lx_syscall_handler_t lx_handlers[] = { lx_geteuid16, /* 49: geteuid16 */ lx_getegid16, /* 50: getegid16 */ NULL, /* 51: acct */ - lx_umount2, /* 52: umount2 */ + NULL, /* 52: umount2 */ NULL, /* 53: lock */ NULL, /* 54: ioctl */ NULL, /* 55: fcntl */ diff --git a/usr/src/lib/brand/lx/lx_brand/common/mount.c b/usr/src/lib/brand/lx/lx_brand/common/mount.c index 8416b6f0ee..d06379555a 100644 --- a/usr/src/lib/brand/lx/lx_brand/common/mount.c +++ b/usr/src/lib/brand/lx/lx_brand/common/mount.c @@ -25,24 +25,16 @@ * Copyright 2016 Joyent, Inc. */ -#include <alloca.h> #include <assert.h> -#include <ctype.h> -#include <fcntl.h> #include <errno.h> -#include <signal.h> -#include <string.h> #include <strings.h> #include <nfs/mount.h> #include <sys/types.h> #include <sys/mount.h> -#include <sys/param.h> #include <sys/stat.h> -#include <sys/types.h> #include <unistd.h> #include <stdlib.h> -#include <sys/lx_autofs.h> #include <sys/lx_debug.h> #include <sys/lx_misc.h> #include <sys/lx_syscall.h> @@ -57,322 +49,6 @@ union fh_buffer { char fh_data[NFS3_FHSIZE + 2]; }; -typedef enum mount_opt_type { - MOUNT_OPT_INVALID = 0, - MOUNT_OPT_NORMAL = 1, /* option value: none */ - MOUNT_OPT_UINT = 2, /* option value: unsigned int */ - MOUNT_OPT_BYTESIZE = 3 /* option value: byte size, e.g. 25m */ -} mount_opt_type_t; - -typedef struct mount_opt { - char *mo_name; - mount_opt_type_t mo_type; -} mount_opt_t; - - -/* - * Globals - */ -mount_opt_t lofs_options[] = { - { NULL, MOUNT_OPT_INVALID } -}; - -mount_opt_t lx_proc_options[] = { - { NULL, MOUNT_OPT_INVALID } -}; - -mount_opt_t lx_sysfs_options[] = { - { NULL, MOUNT_OPT_INVALID } -}; - -mount_opt_t lx_tmpfs_options[] = { - { "size", MOUNT_OPT_BYTESIZE }, - { "mode", MOUNT_OPT_UINT }, - { "uid", MOUNT_OPT_UINT }, - { "gid", MOUNT_OPT_UINT }, - { NULL, MOUNT_OPT_INVALID } -}; - -mount_opt_t lx_autofs_options[] = { - { LX_MNTOPT_FD, MOUNT_OPT_UINT }, - { LX_MNTOPT_PGRP, MOUNT_OPT_UINT }, - { LX_MNTOPT_MINPROTO, MOUNT_OPT_UINT }, - { LX_MNTOPT_MAXPROTO, MOUNT_OPT_UINT }, - { LX_MNTOPT_INDIRECT, MOUNT_OPT_NORMAL }, - { LX_MNTOPT_DIRECT, MOUNT_OPT_NORMAL }, - { LX_MNTOPT_OFFSET, MOUNT_OPT_NORMAL }, - { NULL, MOUNT_OPT_INVALID } -}; - - -/* - * i_lx_opt_verify() - Check the mount options. - * - * You might wonder why we're being so strict about the mount options - * we allow. The reason is that normally all mount option verification - * is done by the Solaris userland mount command. Once mount options - * are passed to the kernel, invalid options are simply ignored. So - * if we actually want to catch requests for functionality that we - * don't support, or if we want to make sure that we don't randomly - * enable options that we haven't check to make sure they have the - * same syntax on Linux and Solaris, we need to reject any options - * we don't know to be ok here. - */ -static int -i_lx_opt_verify(char *opts, mount_opt_t *mop) -{ - int opts_len = strlen(opts); - char *opts_tmp, *opt; - int opt_len, i; - - assert((opts != NULL) && (mop != NULL)); - - /* If no options were specified, there's no problem. */ - if (opts_len == 0) { - errno = 0; - return (0); - } - - /* If no options are allowed, fail. */ - if (mop[0].mo_name == NULL) { - errno = ENOTSUP; - return (-1); - } - - /* Don't accept leading or trailing ','. */ - if ((opts[0] == ',') || (opts[opts_len] == ',')) { - errno = EINVAL; - return (-1); - } - - /* Don't accept sequential ','. */ - for (i = 1; i < opts_len; i++) { - if ((opts[i - 1] == ',') && (opts[i] == ',')) { - errno = EINVAL; - return (-1); - } - } - - /* - * We're going to use strtok() which modifies the target - * string so make a temporary copy. - */ - opts_tmp = SAFE_ALLOCA(opts_len); - if (opts_tmp == NULL) { - errno = ENOMEM; - return (-1); - } - bcopy(opts, opts_tmp, opts_len + 1); - - /* Verify each prop one at a time. */ - opt = strtok(opts_tmp, ","); - opt_len = strlen(opt); - for (;;) { - - /* Check for matching option/value pair. */ - for (i = 0; mop[i].mo_name != NULL; i++) { - char *ovalue; - int ovalue_len, mo_len; - - /* If the options is too short don't bother comparing */ - mo_len = strlen(mop[i].mo_name); - if (opt_len < mo_len) { - /* Keep trying to find a match. */ - continue; - } - - /* Compare the option to an allowed option. */ - if (strncmp(mop[i].mo_name, opt, mo_len) != 0) { - /* Keep trying to find a match. */ - continue; - } - - if (mop[i].mo_type == MOUNT_OPT_NORMAL) { - /* The option doesn't take a value. */ - if (opt_len == mo_len) { - /* This option is ok. */ - break; - } else { - /* Keep trying to find a match. */ - continue; - } - } - - /* This options takes a value. */ - if ((opt_len == mo_len) || (opt[mo_len] != '=')) { - /* Keep trying to find a match. */ - continue; - } - - /* We have an option match. Verify option value. */ - ovalue = &opt[mo_len] + 1; - ovalue_len = strlen(ovalue); - - /* Value can't be zero length string. */ - if (ovalue_len == 0) { - errno = EINVAL; - return (-1); - } - - if (mop[i].mo_type == MOUNT_OPT_UINT) { - int j; - /* Verify that value is an unsigned int. */ - for (j = 0; j < ovalue_len; j++) { - if (!isdigit(ovalue[j])) { - errno = EINVAL; - return (-1); - } - } - } else if (mop[i].mo_type == MOUNT_OPT_BYTESIZE) { - int j; - int stage = 0; - int suffix; - - /* - * Verify that the value is an unsigned integer - * that ends in a magnitude suffix (i.e. case - * insensitive 'k' 'm' or 'g') or a '%' - * character. - */ - for (j = 0; j < ovalue_len; j++) { - switch (stage) { - case 0: - /* - * Look for at least one digit. - */ - if (!isdigit(ovalue[j])) { - errno = EINVAL; - return (-1); - } - stage = 1; - break; - case 1: - /* - * Allow an unlimited number of - * digits. - */ - if (isdigit(ovalue[j])) { - break; - } - /* - * Allow one (valid) byte - * magnitude character. - */ - suffix = tolower(ovalue[j]); - if (suffix == 'k' || - suffix == 'm' || - suffix == 'g' || - suffix == '%') { - stage = 2; - break; - } - errno = EINVAL; - return (-1); - case 2: - /* - * Invalid trailing characters. - */ - errno = EINVAL; - return (-1); - } - } - - if (stage < 1) { - errno = EINVAL; - return (-1); - } - } else { - /* Unknown option type specified. */ - assert(0); - } - - /* The option is ok. */ - break; - } - - /* If there were no matches this is an unsupported option. */ - if (mop[i].mo_name == NULL) { - errno = EINVAL; - return (-1); - } - - /* This option is ok, move onto the next option. */ - if ((opt = strtok(NULL, ",")) == NULL) - break; - opt_len = strlen(opt); - }; - - /* We verified all the options. */ - return (0); -} - -/* - * Remove an option from the string and save it in the provided buffer. - * The option string should have already been verified as valid. - * Return 0 if not present, -1 if error, and 1 if present and fine. - */ -static int -opt_rm(char *opts, char *rmopt, char *retstr, int retlen) -{ - int opts_len = strlen(opts); - char *optstart, *optend; - int optlen; - - assert((opts != NULL) && (rmopt != NULL)); - - retstr[0] = '\0'; - - /* If no options were specified, there's no problem. */ - if (opts_len == 0) - return (0); - - if ((optstart = strstr(opts, rmopt)) == NULL) - return (0); - - for (optend = optstart; *optend != ',' && *optend != '\0'; optend++) - ; - - optlen = optend - optstart; - if (optlen >= retlen) - return (-1); - (void) strncpy(retstr, optstart, optlen); - retstr[optlen] = '\0'; - - if (*optend == ',') - optend++; - - optlen = strlen(optend) + 1; - bcopy(optend, optstart, optlen); - - if (*optstart == '\0' && optstart != opts) { - /* removed last opt and it had a preceeding opt, remove comma */ - *(optstart - 1) = '\0'; - } - - return (1); -} - -static int -opt_id_val(char *opt, int *valp) -{ - char *vp; - long lval; - - if ((vp = strchr(opt, '=')) == NULL) - return (-1); - - vp++; - if (!isdigit(*vp)) - return (-1); - - lval = strtol(vp, &vp, 10); - if (*vp != '\0' || lval > INT_MAX) - return (-1); - - *valp = (int)lval; - return (0); -} - static int i_add_option(char *option, char *buf, size_t buf_size) { @@ -675,6 +351,10 @@ i_make_nfs_args(lx_nfs_mount_data_t *lx_nmd, struct nfs_args *nfs_args, return (0); } +/* + * The user-level mount(2) code is only used to support NFS mounts. All other + * fstypes are handled in-kernel. + */ long lx_mount(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5) @@ -686,19 +366,12 @@ lx_mount(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, unsigned int flags = (unsigned int)p4; const void *datap = (const void *)p5; - /* Variables needed for all mounts. */ char source[MAXPATHLEN + LX_NMD_MAXHOSTNAMELEN + 1]; char target[MAXPATHLEN]; - char fstype[MAXPATHLEN], options[MAX_MNTOPT_STR]; + char fstype[8], options[MAX_MNTOPT_STR]; int sflags, rv; long res; - boolean_t is_tmpfs = B_FALSE; - /* Variable for tmpfs mounts. */ - int uid = -1; - int gid = -1; - - /* Variables needed for nfs mounts. */ lx_nfs_mount_data_t lx_nmd; struct nfs_args nfs_args; struct netbuf nfs_args_addr; @@ -707,8 +380,9 @@ lx_mount(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, struct sec_data nfs_args_secdata; char *sdataptr = NULL; int sdatalen = 0; + int vers; - /* Initialize Solaris mount arguments. */ + /* Initialize illumos mount arguments. */ sflags = MS_OPTIONSTR; options[0] = '\0'; sdatalen = 0; @@ -730,6 +404,9 @@ lx_mount(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, lx_debug("\tlinux mount target: %s", target); lx_debug("\tlinux mount fstype: %s", fstype); + /* The in-kernel mount code should only call us for an NFS mount. */ + assert(strcmp(fstype, "nfs") == 0); + /* * While SunOS is picky about mount(2) target paths being absolute, * Linux is not so strict. In order to facilitate this looser @@ -760,261 +437,72 @@ lx_mount(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, return (-ENOTSUP); } - /* Do filesystem specific mount work. */ - if (flags & LX_MS_BIND) { - - /* If MS_BIND is set, we turn this into a lofs mount. */ - (void) strcpy(fstype, "lofs"); - - /* Copy in Linux mount options. */ - if (datap != NULL) { - rv = uucopystr((void *)datap, - options, sizeof (options)); - if ((rv == -1) || (rv == sizeof (options))) - return (-EFAULT); - } - lx_debug("\tlinux mount options: \"%s\"", options); - - /* Verify Linux mount options. */ - if (i_lx_opt_verify(options, lofs_options) != 0) { - lx_unsupported("unsupported lofs mount options: %s", - options); - return (-errno); - } - } else if (strcmp(fstype, "tmpfs") == 0) { - char idstr[64]; - - /* Copy in Linux mount options. */ - if (datap != NULL) { - rv = uucopystr((void *)datap, - options, sizeof (options)); - if ((rv == -1) || (rv == sizeof (options))) - return (-EFAULT); - } - lx_debug("\tlinux mount options: \"%s\"", options); - - /* Verify Linux mount options. */ - if (i_lx_opt_verify(options, lx_tmpfs_options) != 0) { - lx_unsupported("unsupported tmpfs mount options: %s", - options); - return (-errno); - } - - /* - * Linux defaults to mode=1777 for tmpfs mounts. - */ - if (strstr(options, "mode=") == NULL) { - if (options[0] != '\0') - (void) strlcat(options, ",", sizeof (options)); - (void) strlcat(options, "mode=1777", sizeof (options)); - } - - switch (opt_rm(options, "uid=", idstr, sizeof (idstr))) { - case 0: - uid = -1; - break; - case 1: - if (opt_id_val(idstr, &uid) < 0) - return (-EINVAL); - break; - default: - return (-E2BIG); - } - switch (opt_rm(options, "gid=", idstr, sizeof (idstr))) { - case 0: - gid = -1; - break; - case 1: - if (opt_id_val(idstr, &gid) < 0) - return (-EINVAL); - break; - default: - return (-E2BIG); - } - - /* - * Linux seems to always allow overlay mounts. We allow this - * everywhere except under /dev where it interferes with device - * emulation. - */ - if (strcmp(targetp, "/dev") != 0 && - strncmp(targetp, "/dev/", 5) != 0) - sflags |= MS_OVERLAY; - - is_tmpfs = B_TRUE; - - } else if (strcmp(fstype, "proc") == 0) { - struct stat64 sb; - - /* Translate proc mount requests to lx_proc requests. */ - (void) strcpy(fstype, "lx_proc"); - - /* Copy in Linux mount options. */ - if (datap != NULL) { - rv = uucopystr((void *)datap, - options, sizeof (options)); - if ((rv == -1) || (rv == sizeof (options))) - return (-EFAULT); - } - lx_debug("\tlinux mount options: \"%s\"", options); - - /* Verify Linux mount options. */ - if (i_lx_opt_verify(options, lx_proc_options) != 0) { - lx_unsupported("unsupported proc mount options: %s", - options); - return (-errno); - } - - /* If mounting proc over itself, just return ok */ - if (stat64(target, &sb) == 0 && - strcmp(sb.st_fstype, "lx_proc") == 0) { - return (0); - } - } else if (strcmp(fstype, "sysfs") == 0) { - /* Translate sysfs mount requests to lx_sysfs requests. */ - (void) strcpy(fstype, "lx_sysfs"); - - /* Copy in Linux mount options. */ - if (datap != NULL) { - rv = uucopystr((void *)datap, - options, sizeof (options)); - if ((rv == -1) || (rv == sizeof (options))) - return (-EFAULT); - } - lx_debug("\tlinux mount options: \"%s\"", options); - - /* Verify Linux mount options. */ - if (i_lx_opt_verify(options, lx_sysfs_options) != 0) { - lx_unsupported("unsupported sysfs mount options: %s", - options); - return (-errno); - } - } else if (strcmp(fstype, "cgroup") == 0) { - /* Translate cgroup mount requests to lx_cgroup requests. */ - (void) strcpy(fstype, "lx_cgroup"); - - /* Copy in Linux mount options. */ - if (datap != NULL) { - rv = uucopystr((void *)datap, - options, sizeof (options)); - if ((rv == -1) || (rv == sizeof (options))) - return (-EFAULT); - } - lx_debug("\tlinux mount options: \"%s\"", options); - - /* - * Currently don't verify Linux mount options since we can - * have asubsystem string provided. - */ - - } else if (strcmp(fstype, "autofs") == 0) { - - /* Translate autofs mount requests to lxautofs requests. */ - (void) strcpy(fstype, LX_AUTOFS_NAME); - - /* Copy in Linux mount options. */ - if (datap != NULL) { - rv = uucopystr((void *)datap, - options, sizeof (options)); - if ((rv == -1) || (rv == sizeof (options))) - return (-EFAULT); - } - lx_debug("\tlinux mount options: \"%s\"", options); - - /* Verify Linux mount options. */ - if (i_lx_opt_verify(options, lx_autofs_options) != 0) { - lx_unsupported("unsupported autofs mount options: %s", - options); - return (-errno); - } - - /* Linux seems to always allow overlay mounts */ - sflags |= MS_OVERLAY; - - } else if (strcmp(fstype, "nfs") == 0) { + /* + * Copy in Linux mount options. Note that for older Linux kernels + * (pre 2.6.23) the mount options pointer (which normally points to a + * string) points to a structure which is populated by the user-level + * code after it has done the preliminary RPCs (similar to how our NFS + * mount cmd works). For newer kernels the options pointer is just a + * string of options. We're unlikely to actually emulate a kernel that + * uses the old style but support is kept and handled in + * i_make_nfs_args(). The new style handling is implemented in + * lx_nfs_mount(). The user-level mount caller is in charge of + * determining the format in which it passes the data parameter. + */ + if (datap == NULL) + return (-EINVAL); + if (uucopy((void *)datap, &vers, sizeof (int)) < 0) + return (-errno); + /* + * As described above, the data parameter might be a versioned lx_nmd + * structure or (most likely on a modern distribution) it is a string. + */ + if (vers < 1 || vers > 6) { /* - * Copy in Linux mount options. Note that for older Linux - * kernels (pre 2.6.23) the mount options pointer (which - * normally points to a string) points to a structure which - * is populated by the user-level code after it has done the - * preliminary RPCs (similar to how our NFS mount cmd works). - * For newer kernels the options pointer is just a string of - * options. We're unlikely to actually emulate a kernel that - * uses the old style but support is kept and handled in - * i_make_nfs_args(). The new style handling is implemented in - * nfs_pre_mount(). The user-level mount caller is in charge of - * determining the format in which it passes the data parameter. + * Handle the modern style with options as a string, make the + * preliminary RPC calls and do the native mount all within + * lx_nfs_mount(). */ - int vers; - - if (datap == NULL) - return (-EINVAL); - if (uucopy((void *)datap, &vers, sizeof (int)) < 0) + if (uucopystr((void *)datap, options, sizeof (options)) < 0) return (-errno); + return (lx_nfs_mount(source, target, fstype, flags, options)); + } - /* - * As described above, the data parameter might be a versioned - * lx_nmd structure or (most likely) it is just a string. - */ - switch (vers) { - case 1: - case 2: - case 3: - case 5: - case 6: - lx_unsupported("unsupported nfs mount request " - "version: %d\n", vers); - return (-ENOTSUP); - - case 4: - if (uucopy((void *)datap, &lx_nmd, sizeof (lx_nmd)) < 0) - return (-errno); - - /* - * For Illumos nfs mounts, the kernel expects a special - * structure, but a pointer to this structure is passed - * in via an extra parameter (sdataptr below.) - */ - if ((rv = i_make_nfs_args(&lx_nmd, &nfs_args, - &nfs_args_addr, &nfs_args_knconf, &nfs_args_fh, - &nfs_args_secdata, fstype, options, - sizeof (options))) != 0) - return (rv); - - break; + /* + * This is an old style NFS mount call and we only support v4. + */ + if (vers != 4) { + lx_unsupported("unsupported nfs mount request version: %d\n", + vers); + return (-ENOTSUP); + } - default: - /* - * Handle new style with options as a string, make - * the preliminary RPC calls and do the native mount - * all within lx_nfs_mount(). - */ - if (uucopystr((void *)datap, options, - sizeof (options)) < 0) - return (-errno); - return (lx_nfs_mount(source, target, fstype, flags, - options)); - break; - } + if (uucopy((void *)datap, &lx_nmd, sizeof (lx_nmd)) < 0) + return (-errno); - /* - * For nfs mounts we need to tell the mount system call - * to expect extra parameters. - */ - sflags |= MS_DATA; - sdataptr = (char *)&nfs_args; - sdatalen = sizeof (nfs_args); + /* + * For illumos NFS mounts, the kernel expects a special structure, but + * a pointer to this structure is passed in via an extra parameter + * (sdataptr below.) + */ + if ((rv = i_make_nfs_args(&lx_nmd, &nfs_args, &nfs_args_addr, + &nfs_args_knconf, &nfs_args_fh, &nfs_args_secdata, fstype, options, + sizeof (options))) != 0) + return (rv); - /* Linux seems to always allow overlay mounts */ - sflags |= MS_OVERLAY; + /* + * For the following old-style NFS mount we need to tell the mount + * system call to expect extra parameters. + */ + sflags |= MS_DATA; + sdataptr = (char *)&nfs_args; + sdatalen = sizeof (nfs_args); - } else { - lx_unsupported("unsupported mount filesystem type: %s", fstype); - return (-ENODEV); - } + /* Linux seems to always allow overlay mounts */ + sflags |= MS_OVERLAY; - /* Convert some Linux flags to Illumos flags. */ + /* Convert some Linux flags to illumos flags. */ if (flags & LX_MS_RDONLY) sflags |= MS_RDONLY; if (flags & LX_MS_NOSUID) @@ -1023,7 +511,7 @@ lx_mount(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, sflags |= MS_REMOUNT; /* - * Convert some Linux flags to Illumos option strings. + * Convert some Linux flags to illumos option strings. */ if (flags & LX_MS_STRICTATIME) { /* @@ -1048,48 +536,5 @@ lx_mount(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, res = mount(source, target, sflags, fstype, sdataptr, sdatalen, options, sizeof (options)); - if (res == 0) { - if (is_tmpfs) { - /* Handle uid/gid mount options. */ - if (uid != -1 || gid != -1) - (void) chown(target, uid, gid); - return (0); - - } else { - return (0); - } - } else { - return (-errno); - } -} - -/* - * umount() is identical, though it is implemented on top of umount2() in - * Solaris so it cannot be a pass-thru system call. - */ -long -lx_umount(uintptr_t p1) -{ - return (umount((char *)p1) ? -errno : 0); -} - -/* - * The Linux umount2() system call is identical but has a different value for - * MNT_FORCE (the logical equivalent to MS_FORCE). - */ -#define LX_MNT_FORCE 0x1 - -long -lx_umount2(uintptr_t p1, uintptr_t p2) -{ - char *path = (char *)p1; - int flags = 0; - - if (p2 & ~LX_MNT_FORCE) - return (-EINVAL); - - if (p2 & LX_MNT_FORCE) - flags |= MS_FORCE; - - return (umount2(path, flags) ? -errno : 0); + return ((res == 0) ? 0 : -errno); } diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h index 8369298514..b1cdba338f 100644 --- a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h +++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h @@ -159,8 +159,6 @@ extern long lx_mmap2(uintptr_t, uintptr_t, uintptr_t, uintptr_t, extern long lx_remap(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); extern long lx_mount(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); -extern long lx_umount(uintptr_t); -extern long lx_umount2(uintptr_t, uintptr_t); extern long lx_statfs(uintptr_t, uintptr_t); extern long lx_fstatfs(uintptr_t, uintptr_t); diff --git a/usr/src/uts/common/brand/lx/os/lx_syscall.c b/usr/src/uts/common/brand/lx/os/lx_syscall.c index f360225974..5d4b10a012 100644 --- a/usr/src/uts/common/brand/lx/os/lx_syscall.c +++ b/usr/src/uts/common/brand/lx/os/lx_syscall.c @@ -542,8 +542,8 @@ lx_sysent_t lx_sysent32[] = { {"stat", NULL, NOSYS_OBSOLETE, 0}, /* 18 */ {"lseek", lx_lseek32, 0, 3}, /* 19 */ {"getpid", lx_getpid, 0, 0}, /* 20 */ - {"mount", NULL, 0, 5}, /* 21 */ - {"umount", NULL, 0, 1}, /* 22 */ + {"mount", lx_mount, 0, 5}, /* 21 */ + {"umount", lx_umount, 0, 1}, /* 22 */ {"setuid16", NULL, 0, 1}, /* 23 */ {"getuid16", NULL, 0, 0}, /* 24 */ {"stime", NULL, 0, 1}, /* 25 */ @@ -573,7 +573,7 @@ lx_sysent_t lx_sysent32[] = { {"geteuid16", NULL, 0, 0}, /* 49 */ {"getegid16", NULL, 0, 0}, /* 50 */ {"acct", NULL, NOSYS_NO_EQUIV, 0}, /* 51 */ - {"umount2", NULL, 0, 2}, /* 52 */ + {"umount2", lx_umount2, 0, 2}, /* 52 */ {"lock", NULL, NOSYS_OBSOLETE, 0}, /* 53 */ {"ioctl", lx_ioctl, 0, 3}, /* 54 */ {"fcntl", lx_fcntl, 0, 3}, /* 55 */ @@ -1057,8 +1057,8 @@ lx_sysent_t lx_sysent64[] = { {"sync", NULL, 0, 0}, /* 162 */ {"acct", NULL, NOSYS_NO_EQUIV, 0}, /* 163 */ {"settimeofday", NULL, 0, 2}, /* 164 */ - {"mount", NULL, 0, 5}, /* 165 */ - {"umount2", NULL, 0, 2}, /* 166 */ + {"mount", lx_mount, 0, 5}, /* 165 */ + {"umount2", lx_umount2, 0, 2}, /* 166 */ {"swapon", NULL, NOSYS_KERNEL, 0}, /* 167 */ {"swapoff", NULL, NOSYS_KERNEL, 0}, /* 168 */ {"reboot", NULL, 0, 4}, /* 169 */ diff --git a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h index 5b46e66035..2c0d982bd6 100644 --- a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h +++ b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h @@ -111,6 +111,7 @@ extern long lx_listxattr(); extern long lx_mkdir(); extern long lx_mkdirat(); extern long lx_modify_ldt(); +extern long lx_mount(); extern long lx_nanosleep(); extern long lx_oldgetrlimit(); extern long lx_open(); @@ -171,6 +172,8 @@ extern long lx_removexattr(); extern long lx_tgkill(); extern long lx_time(); extern long lx_tkill(); +extern long lx_umount(); +extern long lx_umount2(); extern long lx_uname(); extern long lx_wait4(); extern long lx_waitid(); @@ -199,6 +202,7 @@ extern long lx_writev(); #if defined(__amd64) #define LX_SYS_close 3 #define LX_SYS_gettimeofday 96 +#define LX_SYS_mount 165 #define LX_SYS_time 201 #define LX_SYS_io_setup 206 #define LX_SYS_clock_gettime 228 @@ -207,11 +211,13 @@ extern long lx_writev(); #define LX_SYS32_close 6 #define LX_SYS32_gettimeofday 78 #define LX_SYS32_time 13 +#define LX_SYS32_mount 21 #define LX_SYS32_clock_gettime 265 #define LX_SYS32_io_setup 245 #define LX_SYS32_getcpu 318 #elif defined(__i386) #define LX_SYS_close 6 +#define LX_SYS_mount 21 #define LX_SYS_gettimeofday 78 #define LX_SYS_time 13 #define LX_SYS_clock_gettime 265 diff --git a/usr/src/uts/common/brand/lx/syscall/lx_mount.c b/usr/src/uts/common/brand/lx/syscall/lx_mount.c new file mode 100644 index 0000000000..825d70cf6a --- /dev/null +++ b/usr/src/uts/common/brand/lx/syscall/lx_mount.c @@ -0,0 +1,650 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +#include <sys/ctype.h> +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/vnode.h> +#include <sys/pathname.h> +#include <sys/types.h> +#include <sys/brand.h> +#include <sys/lx_brand.h> +#include <sys/lx_syscalls.h> +#include <sys/lx_autofs.h> + +#define tolower(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' + 'a' : (x)) + +/* + * mount(2) is significantly different between Linux and illumos. One of the + * main differences is between the set of flags. Some flags on Linux can be + * translated to an illumos equivalent, some are converted to a + * filesystem-specific option, while others have no equivalent whatsoever. + * + * Another big difference is that mounting NFS is fully handled in the kernel on + * Linux whereas on illumos a lot of preliminary work is done by the NFS mount + * command before calling mount(2). As a simplification, we forward NFS + * mount calls back out to the user-level library which does the same kind of + * preliminary processing that is done by the native user-level NFS mount code. + */ +#define LX_MS_MGC_VAL 0xC0ED0000 +#define LX_MS_RDONLY 0x00000001 +#define LX_MS_NOSUID 0x00000002 +#define LX_MS_NODEV 0x00000004 +#define LX_MS_NOEXEC 0x00000008 +#define LX_MS_SYNCHRONOUS 0x00000010 +#define LX_MS_REMOUNT 0x00000020 +#define LX_MS_MANDLOCK 0x00000040 +#define LX_MS_NOATIME 0x00000400 +#define LX_MS_NODIRATIME 0x00000800 +#define LX_MS_BIND 0x00001000 +#define LX_MS_MOVE 0x00002000 +#define LX_MS_REC 0x00004000 +#define LX_MS_SILENT 0x00008000 +#define LX_MS_POSIXACL 0x00010000 +#define LX_MS_UNBINDABLE 0x00020000 +#define LX_MS_PRIVATE 0x00040000 +#define LX_MS_SLAVE 0x00080000 +#define LX_MS_SHARED 0x00100000 +#define LX_MS_RELATIME 0x00200000 +#define LX_MS_KERNMOUNT 0x00400000 +#define LX_MS_I_VERSION 0x00800000 +#define LX_MS_STRICTATIME 0x01000000 +#define LX_MS_LAZYTIME 0x02000000 + +/* Linux kernel-internal flags - ignored if passed in */ +#define LX_MS_NOSEC 0x10000000 +#define LX_MS_BORN 0x20000000 +#define LX_MS_ACTIVE 0x40000000 +#define LX_MS_NOUSER 0x80000000 + +#define LX_MS_SUPPORTED (LX_MS_MGC_VAL | \ + LX_MS_RDONLY | LX_MS_NOSUID | \ + LX_MS_NODEV | LX_MS_NOEXEC | \ + LX_MS_REMOUNT | LX_MS_NOATIME | \ + LX_MS_BIND | LX_MS_SILENT | \ + LX_MS_STRICTATIME | LX_MS_NOSEC | \ + LX_MS_BORN | LX_MS_ACTIVE | LX_MS_NOUSER) + +/* + * support definitions + */ +typedef enum mount_opt_type { + MOUNT_OPT_INVALID = 0, + MOUNT_OPT_NORMAL = 1, /* option value: none */ + MOUNT_OPT_UINT = 2, /* option value: unsigned int */ + MOUNT_OPT_PASSTHRU = 3 /* option value: validated downstream */ +} mount_opt_type_t; + +typedef struct mount_opt { + char *mo_name; + mount_opt_type_t mo_type; +} mount_opt_t; + +/* From uts/common/syscall/umount.c */ +extern int umount2(char *, int); + +/* + * Globals + */ +static mount_opt_t lofs_options[] = { + { NULL, MOUNT_OPT_INVALID } +}; + +static mount_opt_t lx_proc_options[] = { + { NULL, MOUNT_OPT_INVALID } +}; + +static mount_opt_t lx_sysfs_options[] = { + { NULL, MOUNT_OPT_INVALID } +}; + +static mount_opt_t lx_tmpfs_options[] = { + { "size", MOUNT_OPT_PASSTHRU }, + { "mode", MOUNT_OPT_UINT }, + { "uid", MOUNT_OPT_UINT }, + { "gid", MOUNT_OPT_UINT }, + { NULL, MOUNT_OPT_INVALID } +}; + +static mount_opt_t lx_autofs_options[] = { + { LX_MNTOPT_FD, MOUNT_OPT_UINT }, + { LX_MNTOPT_PGRP, MOUNT_OPT_UINT }, + { LX_MNTOPT_MINPROTO, MOUNT_OPT_UINT }, + { LX_MNTOPT_MAXPROTO, MOUNT_OPT_UINT }, + { LX_MNTOPT_INDIRECT, MOUNT_OPT_NORMAL }, + { LX_MNTOPT_DIRECT, MOUNT_OPT_NORMAL }, + { LX_MNTOPT_OFFSET, MOUNT_OPT_NORMAL }, + { NULL, MOUNT_OPT_INVALID } +}; + + +/* + * Check the mount options. + * + * On illumos all mount option verification is done by the user-level mount + * command. Invalid options are simply ignored by domount(). Thus, we check + * here for invalid/unsupported options. + */ +static int +lx_mnt_opt_verify(char *opts, mount_opt_t *mop) +{ + int opts_len = strlen(opts); + char *opt, *tp; + int opt_len, i; + boolean_t last = B_FALSE; + + ASSERT((opts != NULL) && (mop != NULL)); + + /* If no options were specified, nothing to do. */ + if (opts_len == 0) + return (0); + + /* If no options are allowed, fail. */ + if (mop[0].mo_name == NULL) + return (ENOTSUP); + + /* Don't accept leading or trailing ','. */ + if ((opts[0] == ',') || (opts[opts_len] == ',')) + return (EINVAL); + + /* Don't accept sequential ','. */ + for (i = 1; i < opts_len; i++) { + if ((opts[i - 1] == ',') && (opts[i] == ',')) + return (EINVAL); + } + + /* + * Verify each prop one at a time. There is no strtok in the kernel but + * it's easy to tokenize the entry ourselves. + */ + opt = opts; + for (tp = opt; *tp != ',' && *tp != '\0'; tp++) + ; + if (*tp == ',') { + *tp = '\0'; + } else { + last = B_TRUE; + } + for (;;) { + opt_len = strlen(opt); + + /* Check for matching option/value pair. */ + for (i = 0; mop[i].mo_name != NULL; i++) { + char *ovalue; + int ovalue_len, mo_len; + + /* If the options is too short don't bother comparing */ + mo_len = strlen(mop[i].mo_name); + if (opt_len < mo_len) { + /* Keep trying to find a match. */ + continue; + } + + /* Compare the option to an allowed option. */ + if (strncmp(mop[i].mo_name, opt, mo_len) != 0) { + /* Keep trying to find a match. */ + continue; + } + + if (mop[i].mo_type == MOUNT_OPT_NORMAL) { + /* The option doesn't take a value. */ + if (opt_len == mo_len) { + /* This option is ok. */ + break; + } else { + /* Keep trying to find a match. */ + continue; + } + } + + /* This options takes a value. */ + if ((opt_len == mo_len) || (opt[mo_len] != '=')) { + /* Keep trying to find a match. */ + continue; + } + + /* We have an option match. Verify option value. */ + ovalue = &opt[mo_len] + 1; + ovalue_len = strlen(ovalue); + + /* Value can't be zero length string. */ + if (ovalue_len == 0) { + goto bad; + } + + if (mop[i].mo_type == MOUNT_OPT_UINT) { + int j; + /* Verify that value is an unsigned int. */ + for (j = 0; j < ovalue_len; j++) { + if (!ISDIGIT(ovalue[j])) { + goto bad; + } + } + } else if (mop[i].mo_type == MOUNT_OPT_PASSTHRU) { + /* Filesystem will do its own validation. */ + break; + } else { + /* Unknown option type specified. */ + goto bad; + } + + /* The option is ok. */ + break; + } + + /* If there were no matches this is an unsupported option. */ + if (mop[i].mo_name == NULL) { + goto bad; + } + + /* + * This option is ok, either we're done or move on to the next + * option. + */ + if (last) + break; + + *tp = ','; + opt = tp + 1; + for (tp = opt; *tp != ',' && *tp != '\0'; tp++) + ; + if (*tp == ',') { + *tp = '\0'; + } else { + last = B_TRUE; + } + }; + + /* We verified all the options. */ + return (0); + +bad: + if (!last) { + *tp = ','; + } + return (EINVAL); +} + +/* + * Remove an option from the string and save it in the provided buffer. + * The option string should have already been verified as valid. + * Return 0 if not present, -1 if error, and 1 if present and fine. + */ +static int +lx_mnt_opt_rm(char *opts, char *rmopt, char *retstr, int retlen) +{ + int opts_len = strlen(opts); + char *optstart, *optend; + int optlen; + + ASSERT((opts != NULL) && (rmopt != NULL)); + + retstr[0] = '\0'; + + /* If no options were specified, there's no problem. */ + if (opts_len == 0) + return (0); + + if ((optstart = strstr(opts, rmopt)) == NULL) + return (0); + + for (optend = optstart; *optend != ',' && *optend != '\0'; optend++) + ; + + /*LINTED*/ + optlen = optend - optstart; + if (optlen >= retlen) + return (-1); + (void) strncpy(retstr, optstart, optlen); + retstr[optlen] = '\0'; + + if (*optend == ',') + optend++; + + optlen = strlen(optend) + 1; + bcopy(optend, optstart, optlen); + + if (*optstart == '\0' && optstart != opts) { + /* removed last opt and it had a preceeding opt, remove comma */ + *(optstart - 1) = '\0'; + } + + return (1); +} + +static int +lx_mnt_opt_val(char *opt, int *valp) +{ + char *op, *ep; + long lval; + + if ((op = strchr(opt, '=')) == NULL) + return (-1); + + op++; + if (!ISDIGIT(*op)) + return (-1); + + if (ddi_strtoul(op, &ep, 10, (ulong_t *)&lval) != 0 || lval > INT_MAX) { + return (-1); + } + + if (*ep != '\0') + return (-1); + + *valp = (int)lval; + return (0); +} + +static int +lx_mnt_add_opt(char *option, char *buf, size_t buf_size) +{ + char *fmt_str = NULL; + size_t len; + + ASSERT((option != NULL) && (strlen(option) > 0)); + ASSERT((buf != NULL) && (buf_size > 0)); + + if (buf[0] == '\0') { + fmt_str = "%s"; + } else { + fmt_str = ",%s"; + } + + len = strlen(buf); + VERIFY(len <= buf_size); + buf_size -= len; + buf += len; + + if (snprintf(buf, buf_size, fmt_str, option) > (buf_size - 1)) + return (EOVERFLOW); + return (0); +} + +static int +lx_mnt_copyin_arg(const char *from, char *to, size_t len) +{ + size_t slen; + int rv; + + rv = copyinstr(from, to, len, &slen); + if (rv == ENAMETOOLONG || slen == len) + return (ENAMETOOLONG); + if (rv != 0) + return (EFAULT); + + return (0); +} + +long +lx_mount(const char *sourcep, const char *targetp, const char *fstypep, + uint_t flags, const void *datap) +{ + char fstype[16]; + char source[MAXPATHLEN]; + char target[MAXPATHLEN]; + char options[MAX_MNTOPT_STR]; + int sflags, rv; + struct mounta ma, *map = &ma; + vfs_t *vfsp; + vnode_t *vp = NULL; + int uid = -1; + int gid = -1; + + if ((rv = lx_mnt_copyin_arg(fstypep, fstype, sizeof (fstype))) != 0) { + if (rv == ENAMETOOLONG) + return (set_errno(ENODEV)); + return (set_errno(rv)); + } + + /* + * Vector back out to userland emulation for NFS. + */ + if (strcmp(fstype, "nfs") == 0) { + uintptr_t uargs[5] = {(uintptr_t)sourcep, (uintptr_t)targetp, + (uintptr_t)fstypep, (uintptr_t)flags, (uintptr_t)datap}; + + /* The userspace emulation will do the lx_syscall_return() */ + ttolxlwp(curthread)->br_eosys = JUSTRETURN; + +#if defined(_LP64) + if (get_udatamodel() != DATAMODEL_NATIVE) { + lx_emulate_user32(ttolwp(curthread), LX_SYS32_mount, + uargs); + } else +#endif + { + lx_emulate_user(ttolwp(curthread), LX_SYS_mount, uargs); + } + return (0); + } + + sflags = MS_SYSSPACE | MS_OPTIONSTR; + options[0] = '\0'; + + /* Copy in parameters that are always present. */ + if ((rv = lx_mnt_copyin_arg(sourcep, source, sizeof (source))) != 0) + return (set_errno(rv)); + + if ((rv = lx_mnt_copyin_arg(targetp, target, sizeof (target))) != 0) + return (set_errno(rv)); + + /* + * While SunOS is picky about mount(2) target paths being absolute, + * Linux is not so strict. In order to facilitate this looser + * requirement we must lookup the full path. + */ + if (target[0] != '/') { + vnode_t *vp; + + if ((rv = lookupnameatcred(target, UIO_SYSSPACE, FOLLOW, + NULLVPP, &vp, NULL, CRED())) != 0) + return (set_errno(rv)); + + rv = vnodetopath(NULL, vp, target, MAXPATHLEN, CRED()); + VN_RELE(vp); + if (rv != 0) + return (set_errno(rv)); + } + + /* Make sure we support the requested mount flags. */ + if ((flags & ~LX_MS_SUPPORTED) != 0) + return (set_errno(ENOTSUP)); + + /* Copy in Linux mount options. */ + if (datap != NULL && + (rv = lx_mnt_copyin_arg(datap, options, sizeof (options))) != 0) + return (set_errno(rv)); + + /* Do filesystem specific mount work. */ + if (flags & LX_MS_BIND) { + /* If MS_BIND is set, we turn this into a lofs mount. */ + (void) strcpy(fstype, "lofs"); + + /* Verify Linux mount options. */ + if ((rv = lx_mnt_opt_verify(options, lofs_options)) != 0) + return (set_errno(rv)); + } else if (strcmp(fstype, "tmpfs") == 0) { + char idstr[64]; + + /* Verify Linux mount options. */ + if ((rv = lx_mnt_opt_verify(options, lx_tmpfs_options)) != 0) + return (set_errno(rv)); + + /* + * Linux defaults to mode=1777 for tmpfs mounts. + */ + if (strstr(options, "mode=") == NULL) { + if (options[0] != '\0') + (void) strlcat(options, ",", sizeof (options)); + (void) strlcat(options, "mode=1777", sizeof (options)); + } + + switch (lx_mnt_opt_rm(options, "uid=", idstr, sizeof (idstr))) { + case 0: + uid = -1; + break; + case 1: + if (lx_mnt_opt_val(idstr, &uid) < 0) + return (set_errno(EINVAL)); + break; + default: + return (set_errno(E2BIG)); + } + switch (lx_mnt_opt_rm(options, "gid=", idstr, sizeof (idstr))) { + case 0: + gid = -1; + break; + case 1: + if (lx_mnt_opt_val(idstr, &gid) < 0) + return (set_errno(EINVAL)); + break; + default: + return (set_errno(E2BIG)); + } + + /* + * Linux seems to always allow overlay mounts. We allow this + * everywhere except under /dev where it interferes with device + * emulation. + */ + if (strcmp(targetp, "/dev") != 0 && + strncmp(targetp, "/dev/", 5) != 0) + sflags |= MS_OVERLAY; + } else if (strcmp(fstype, "proc") == 0) { + /* Translate proc mount requests to lx_proc requests. */ + (void) strcpy(fstype, "lx_proc"); + + /* Verify Linux mount options. */ + if ((rv = lx_mnt_opt_verify(options, lx_proc_options)) != 0) + return (set_errno(rv)); + } else if (strcmp(fstype, "sysfs") == 0) { + /* Translate sysfs mount requests to lx_sysfs requests. */ + (void) strcpy(fstype, "lx_sysfs"); + + /* Verify Linux mount options. */ + if ((rv = lx_mnt_opt_verify(options, lx_sysfs_options)) != 0) + return (set_errno(rv)); + } else if (strcmp(fstype, "cgroup") == 0) { + /* Translate cgroup mount requests to lx_cgroup requests. */ + (void) strcpy(fstype, "lx_cgroup"); + + /* + * Currently don't verify Linux mount options since we can + * have a subsystem string provided. + */ + } else if (strcmp(fstype, "autofs") == 0) { + /* Translate autofs mount requests to lxautofs requests. */ + (void) strcpy(fstype, LX_AUTOFS_NAME); + + /* Verify Linux mount options. */ + if ((rv = lx_mnt_opt_verify(options, lx_autofs_options)) != 0) + return (set_errno(rv)); + + /* Linux seems to always allow overlay mounts */ + sflags |= MS_OVERLAY; + } else { + return (set_errno(ENODEV)); + } + + /* Convert some Linux flags to illumos flags. */ + if (flags & LX_MS_RDONLY) + sflags |= MS_RDONLY; + if (flags & LX_MS_NOSUID) + sflags |= MS_NOSUID; + if (flags & LX_MS_REMOUNT) + sflags |= MS_REMOUNT; + + /* + * Convert some Linux flags to illumos option strings. + */ + if (flags & LX_MS_STRICTATIME) { + /* + * The "strictatime" mount option ensures that none of the + * weaker atime-related mode options are in effect. + */ + flags &= ~(LX_MS_RELATIME | LX_MS_NOATIME); + } + if ((flags & LX_MS_NODEV) && + (rv = lx_mnt_add_opt("nodev", options, sizeof (options))) != 0) + return (set_errno(rv)); + if ((flags & LX_MS_NOEXEC) && + (rv = lx_mnt_add_opt("noexec", options, sizeof (options))) != 0) + return (set_errno(rv)); + if ((flags & LX_MS_NOATIME) && + (rv = lx_mnt_add_opt("noatime", options, sizeof (options))) != 0) + return (set_errno(rv)); + + if ((rv = lookupname(target, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp)) != 0) + return (set_errno(rv)); + + /* If mounting proc over itself, just return ok */ + if (strcmp(fstype, "lx_proc") == 0 && strcmp("lx_proc", + vfssw[vp->v_vfsp->vfs_fstype].vsw_name) == 0) { + VN_RELE(vp); + return (0); + } + + map->spec = source; + map->dir = target; + map->flags = sflags; + map->fstype = fstype; + map->dataptr = NULL; + map->datalen = 0; + map->optptr = options; + map->optlen = sizeof (options); + + rv = domount(NULL, map, vp, CRED(), &vfsp); + VN_RELE(vp); + if (rv != 0) + return (set_errno(rv)); + + VFS_RELE(vfsp); + if (strcmp(fstype, "tmpfs") == 0 && (uid != -1 || gid != -1)) { + /* Handle tmpfs uid/gid mount options. */ + (void) lx_chown(target, uid, gid); + } + + return (0); +} + +/* + * umount() is identical to illumos, though implemented on top of umount2(). + */ +long +lx_umount(char *path) +{ + return (umount2(path, 0)); +} + +/* + * The Linux umount2() system call is identical to illumos but has a different + * value for MNT_FORCE (the logical equivalent to MS_FORCE). + */ +#define LX_MNT_FORCE 0x1 + +long +lx_umount2(char *path, int flg) +{ + int flags = 0; + + if (flg & ~LX_MNT_FORCE) + return (set_errno(EINVAL)); + + if (flg & LX_MNT_FORCE) + flags |= MS_FORCE; + + return (umount2(path, flags)); +} diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files index d279def122..3f8865ff1c 100644 --- a/usr/src/uts/intel/Makefile.files +++ b/usr/src/uts/intel/Makefile.files @@ -335,6 +335,7 @@ LX_BRAND_OBJS = \ lx_misc.o \ lx_mkdir.o \ lx_modify_ldt.o \ + lx_mount.o \ lx_open.o \ lx_personality.o \ lx_pid.o \ |