diff options
author | pjd <pjd@FreeBSD.org> | 2008-11-17 20:49:29 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2008-11-17 20:49:29 +0000 |
commit | bbe899b96e388a8b82439f81ed3707e0d9c6070d (patch) | |
tree | 81b89fa4ac6467771d5aa291a97f4665981a6108 /sys/cddl/compat/opensolaris/kern | |
parent | d2f579595c362ce27b4d87e2c40e1c4e09b929e3 (diff) | |
download | FreeBSD-src-bbe899b96e388a8b82439f81ed3707e0d9c6070d.zip FreeBSD-src-bbe899b96e388a8b82439f81ed3707e0d9c6070d.tar.gz |
Update ZFS from version 6 to 13 and bring some FreeBSD-specific changes.
This bring huge amount of changes, I'll enumerate only user-visible changes:
- Delegated Administration
Allows regular users to perform ZFS operations, like file system
creation, snapshot creation, etc.
- L2ARC
Level 2 cache for ZFS - allows to use additional disks for cache.
Huge performance improvements mostly for random read of mostly
static content.
- slog
Allow to use additional disks for ZFS Intent Log to speed up
operations like fsync(2).
- vfs.zfs.super_owner
Allows regular users to perform privileged operations on files stored
on ZFS file systems owned by him. Very careful with this one.
- chflags(2)
Not all the flags are supported. This still needs work.
- ZFSBoot
Support to boot off of ZFS pool. Not finished, AFAIK.
Submitted by: dfr
- Snapshot properties
- New failure modes
Before if write requested failed, system paniced. Now one
can select from one of three failure modes:
- panic - panic on write error
- wait - wait for disk to reappear
- continue - serve read requests if possible, block write requests
- Refquota, refreservation properties
Just quota and reservation properties, but don't count space consumed
by children file systems, clones and snapshots.
- Sparse volumes
ZVOLs that don't reserve space in the pool.
- External attributes
Compatible with extattr(2).
- NFSv4-ACLs
Not sure about the status, might not be complete yet.
Submitted by: trasz
- Creation-time properties
- Regression tests for zpool(8) command.
Obtained from: OpenSolaris
Diffstat (limited to 'sys/cddl/compat/opensolaris/kern')
-rw-r--r-- | sys/cddl/compat/opensolaris/kern/opensolaris_atomic.c | 9 | ||||
-rw-r--r-- | sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c | 23 | ||||
-rw-r--r-- | sys/cddl/compat/opensolaris/kern/opensolaris_lookup.c | 112 | ||||
-rw-r--r-- | sys/cddl/compat/opensolaris/kern/opensolaris_misc.c | 18 | ||||
-rw-r--r-- | sys/cddl/compat/opensolaris/kern/opensolaris_policy.c | 136 | ||||
-rw-r--r-- | sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c | 69 | ||||
-rw-r--r-- | sys/cddl/compat/opensolaris/kern/opensolaris_zone.c | 104 |
7 files changed, 337 insertions, 134 deletions
diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_atomic.c b/sys/cddl/compat/opensolaris/kern/opensolaris_atomic.c index 37de21f..bdb8f02 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_atomic.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_atomic.c @@ -61,6 +61,15 @@ atomic_add_64(volatile uint64_t *target, int64_t delta) *target += delta; mtx_unlock(&atomic_mtx); } + +void +atomic_dec_64(volatile uint64_t *target) +{ + + mtx_lock(&atomic_mtx); + *target -= 1; + mtx_unlock(&atomic_mtx); +} #endif uint64_t diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c b/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c index 139d018..a24ca83 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c @@ -94,7 +94,7 @@ zfs_kmem_free(void *buf, size_t size __unused) { #ifdef KMEM_DEBUG if (buf == NULL) { - printf("%s: attempt to free NULL\n",__func__); + printf("%s: attempt to free NULL\n", __func__); return; } struct kmem_item *i; @@ -156,7 +156,7 @@ kmem_cache_create(char *name, size_t bufsize, size_t align, cache->kc_constructor = constructor; cache->kc_destructor = destructor; cache->kc_private = private; -#ifdef _KERNEL +#if defined(_KERNEL) && !defined(KMEM_DEBUG) cache->kc_zone = uma_zcreate(cache->kc_name, bufsize, constructor != NULL ? kmem_std_constructor : NULL, destructor != NULL ? kmem_std_destructor : NULL, @@ -171,23 +171,23 @@ kmem_cache_create(char *name, size_t bufsize, size_t align, void kmem_cache_destroy(kmem_cache_t *cache) { +#if defined(_KERNEL) && !defined(KMEM_DEBUG) uma_zdestroy(cache->kc_zone); +#endif kmem_free(cache, sizeof(*cache)); } void * kmem_cache_alloc(kmem_cache_t *cache, int flags) { -#ifdef _KERNEL +#if defined(_KERNEL) && !defined(KMEM_DEBUG) return (uma_zalloc_arg(cache->kc_zone, cache, flags)); #else void *p; p = kmem_alloc(cache->kc_size, flags); - if (p != NULL) { - kmem_std_constructor(p, cache->kc_size, cache->kc_private, - flags); - } + if (p != NULL && cache->kc_constructor != NULL) + kmem_std_constructor(p, cache->kc_size, cache, flags); return (p); #endif } @@ -195,10 +195,11 @@ kmem_cache_alloc(kmem_cache_t *cache, int flags) void kmem_cache_free(kmem_cache_t *cache, void *buf) { -#ifdef _KERNEL +#if defined(_KERNEL) && !defined(KMEM_DEBUG) uma_zfree_arg(cache->kc_zone, buf, cache); #else - kmem_std_destructor(buf, cache->kc_size, cache->kc_private); + if (cache->kc_destructor != NULL) + kmem_std_destructor(buf, cache->kc_size, cache); kmem_free(buf, cache->kc_size); #endif } @@ -207,7 +208,9 @@ kmem_cache_free(kmem_cache_t *cache, void *buf) void kmem_cache_reap_now(kmem_cache_t *cache) { +#ifndef KMEM_DEBUG zone_drain(cache->kc_zone); +#endif } void @@ -253,6 +256,8 @@ kmem_show(void *dummy __unused) printf("KMEM_DEBUG: Leaked elements:\n\n"); LIST_FOREACH(i, &kmem_items, next) { printf("address=%p\n", i); + stack_print_ddb(&i->stack); + printf("\n"); } } mtx_unlock(&kmem_items_mtx); diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_lookup.c b/sys/cddl/compat/opensolaris/kern/opensolaris_lookup.c new file mode 100644 index 0000000..47df799 --- /dev/null +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_lookup.c @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/pathname.h> +#include <sys/vfs.h> +#include <sys/vnode.h> + +int +lookupname(char *dirname, enum uio_seg seg, enum symfollow follow, + vnode_t **dirvpp, vnode_t **compvpp) +{ + + return (lookupnameat(dirname, seg, follow, dirvpp, compvpp, NULL)); +} + +int +lookupnameat(char *dirname, enum uio_seg seg, enum symfollow follow, + vnode_t **dirvpp, vnode_t **compvpp, vnode_t *startvp) +{ + struct nameidata nd; + int error, ltype; + + ASSERT(dirvpp == NULL); + + vref(startvp); + ltype = VOP_ISLOCKED(startvp); + VOP_UNLOCK(startvp, 0); + NDINIT_ATVP(&nd, LOOKUP, LOCKLEAF | MPSAFE | follow, seg, dirname, + startvp, curthread); + error = namei(&nd); + *compvpp = nd.ni_vp; + NDFREE(&nd, NDF_ONLY_PNBUF); + vn_lock(startvp, ltype | LK_RETRY); + return (error); +} + +int +traverse(vnode_t **cvpp, int lktype) +{ + kthread_t *td = curthread; + vnode_t *cvp; + vnode_t *tvp; + vfs_t *vfsp; + int error; + + cvp = *cvpp; + tvp = NULL; + + /* + * If this vnode is mounted on, then we transparently indirect + * to the vnode which is the root of the mounted file system. + * Before we do this we must check that an unmount is not in + * progress on this vnode. + */ + + for (;;) { + /* + * Reached the end of the mount chain? + */ + vfsp = vn_mountedvfs(cvp); + if (vfsp == NULL) + break; + /* + * tvp is NULL for *cvpp vnode, which we can't unlock. + */ + if (tvp != NULL) + vput(cvp); + else + vrele(cvp); + + /* + * The read lock must be held across the call to VFS_ROOT() to + * prevent a concurrent unmount from destroying the vfs. + */ + error = VFS_ROOT(vfsp, lktype, &tvp, td); + if (error != 0) + return (error); + cvp = tvp; + } + + *cvpp = cvp; + return (0); +} diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c b/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c index a89d478..279ae4c 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_misc.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/libkern.h> +#include <sys/limits.h> #include <sys/misc.h> #include <sys/sunddi.h> @@ -40,17 +41,30 @@ struct opensolaris_utsname utsname = { }; int +ddi_strtol(const char *str, char **nptr, int base, long *result) +{ + + *result = strtol(str, nptr, base); + if (*result == 0) + return (EINVAL); + else if (*result == LONG_MIN || *result == LONG_MAX) + return (ERANGE); + return (0); +} + +int ddi_strtoul(const char *str, char **nptr, int base, unsigned long *result) { - char *end; if (str == hw_serial) { *result = hostid; return (0); } - *result = strtoul(str, &end, base); + *result = strtoul(str, nptr, base); if (*result == 0) return (EINVAL); + else if (*result == ULONG_MAX) + return (ERANGE); return (0); } diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c b/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c index 272fe59..837d736 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_policy.c @@ -30,9 +30,20 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/priv.h> #include <sys/vnode.h> +#include <sys/mntent.h> #include <sys/mount.h> #include <sys/stat.h> +#include <sys/jail.h> #include <sys/policy.h> +#include <sys/zfs_vfsops.h> + +int +secpolicy_nfs(struct ucred *cred) +{ + + /* TODO: Change PRIV_ROOT! */ + return (priv_check_cred(cred, PRIV_ROOT, 0)); +} int secpolicy_zfs(struct ucred *cred) @@ -62,16 +73,32 @@ secpolicy_fs_unmount(struct ucred *cred, struct mount *vfsp __unused) return (priv_check_cred(cred, PRIV_VFS_UNMOUNT, 0)); } +int +secpolicy_fs_owner(struct mount *mp, struct ucred *cred) +{ + + if (zfs_super_owner) { + if (cred->cr_uid == mp->mnt_cred->cr_uid && + (!jailed(cred) || + cred->cr_prison == mp->mnt_cred->cr_prison)) { + return (0); + } + } + return (priv_check_cred(cred, PRIV_VFS_MOUNT_OWNER, 0)); +} + /* * This check is done in kern_link(), so we could just return 0 here. */ extern int hardlink_check_uid; int -secpolicy_basic_link(struct ucred *cred) +secpolicy_basic_link(struct vnode *vp, struct ucred *cred) { if (!hardlink_check_uid) return (0); + if (secpolicy_fs_owner(vp->v_mount, cred) == 0) + return (0); return (priv_check_cred(cred, PRIV_VFS_LINK, 0)); } @@ -83,9 +110,11 @@ secpolicy_vnode_stky_modify(struct ucred *cred) } int -secpolicy_vnode_remove(struct ucred *cred) +secpolicy_vnode_remove(struct vnode *vp, struct ucred *cred) { + if (secpolicy_fs_owner(vp->v_mount, cred) == 0) + return (0); return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0)); } @@ -94,9 +123,11 @@ secpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner, accmode_t accmode) { - if ((accmode & VREAD) && priv_check_cred(cred, PRIV_VFS_READ, 0) != 0) { + if (secpolicy_fs_owner(vp->v_mount, cred) == 0) + return (0); + + if ((accmode & VREAD) && priv_check_cred(cred, PRIV_VFS_READ, 0) != 0) return (EACCES); - } if ((accmode & VWRITE) && priv_check_cred(cred, PRIV_VFS_WRITE, 0) != 0) { return (EACCES); @@ -116,11 +147,13 @@ secpolicy_vnode_access(struct ucred *cred, struct vnode *vp, uint64_t owner, } int -secpolicy_vnode_setdac(struct ucred *cred, uid_t owner) +secpolicy_vnode_setdac(struct vnode *vp, struct ucred *cred, uid_t owner) { if (owner == cred->cr_uid) return (0); + if (secpolicy_fs_owner(vp->v_mount, cred) == 0) + return (0); return (priv_check_cred(cred, PRIV_VFS_ADMIN, 0)); } @@ -148,7 +181,7 @@ secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap, * In the specific case of creating a set-uid root * file, we need even more permissions. */ - error = secpolicy_vnode_setdac(cred, ovap->va_uid); + error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid); if (error) return (error); error = secpolicy_setid_setsticky_clear(vp, vap, ovap, cred); @@ -158,7 +191,7 @@ secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap, vap->va_mode = ovap->va_mode; } if (mask & (AT_UID | AT_GID)) { - error = secpolicy_vnode_setdac(cred, ovap->va_uid); + error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid); if (error) return (error); @@ -170,14 +203,16 @@ secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap, if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || ((mask & AT_GID) && vap->va_gid != ovap->va_gid && !groupmember(vap->va_gid, cred))) { - error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0); - if (error) - return (error); + if (secpolicy_fs_owner(vp->v_mount, cred) != 0) { + error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0); + if (error) + return (error); + } } if (((mask & AT_UID) && vap->va_uid != ovap->va_uid) || ((mask & AT_GID) && vap->va_gid != ovap->va_gid)) { - secpolicy_setid_clear(vap, cred); + secpolicy_setid_clear(vap, vp, cred); } } if (mask & (AT_ATIME | AT_MTIME)) { @@ -189,7 +224,7 @@ secpolicy_vnode_setattr(struct ucred *cred, struct vnode *vp, struct vattr *vap, * If times is non-NULL, ... The caller must be the owner of * the file or be the super-user. */ - error = secpolicy_vnode_setdac(cred, ovap->va_uid); + error = secpolicy_vnode_setdac(vp, cred, ovap->va_uid); if (error && (vap->va_vaflags & VA_UTIMES_NULL)) error = unlocked_access(node, VWRITE, cred); if (error) @@ -206,25 +241,33 @@ secpolicy_vnode_create_gid(struct ucred *cred) } int -secpolicy_vnode_setids_setgids(struct ucred *cred, gid_t gid) +secpolicy_vnode_setids_setgids(struct vnode *vp, struct ucred *cred, gid_t gid) { - if (!groupmember(gid, cred)) - return (priv_check_cred(cred, PRIV_VFS_SETGID, 0)); - return (0); + if (groupmember(gid, cred)) + return (0); + if (secpolicy_fs_owner(vp->v_mount, cred) == 0) + return (0); + return (priv_check_cred(cred, PRIV_VFS_SETGID, 0)); } int -secpolicy_vnode_setid_retain(struct ucred *cred, boolean_t issuidroot __unused) +secpolicy_vnode_setid_retain(struct vnode *vp, struct ucred *cred, + boolean_t issuidroot __unused) { + if (secpolicy_fs_owner(vp->v_mount, cred) == 0) + return (0); return (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)); } void -secpolicy_setid_clear(struct vattr *vap, struct ucred *cred) +secpolicy_setid_clear(struct vattr *vap, struct vnode *vp, struct ucred *cred) { + if (secpolicy_fs_owner(vp->v_mount, cred) == 0) + return; + if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0) { if (priv_check_cred(cred, PRIV_VFS_RETAINSUGID, 0)) { vap->va_mask |= AT_MODE; @@ -239,6 +282,9 @@ secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap, { int error; + if (secpolicy_fs_owner(vp->v_mount, cred) == 0) + return (0); + /* * Privileged processes may set the sticky bit on non-directories, * as well as set the setgid bit on a file with a group that the process @@ -253,9 +299,61 @@ secpolicy_setid_setsticky_clear(struct vnode *vp, struct vattr *vap, * group-id bit. */ if ((vap->va_mode & S_ISGID) != 0) { - error = secpolicy_vnode_setids_setgids(cred, ovap->va_gid); + error = secpolicy_vnode_setids_setgids(vp, cred, ovap->va_gid); if (error) return (error); } return (0); } + +int +secpolicy_fs_mount(cred_t *cr, vnode_t *mvp, struct mount *vfsp) +{ + + return (priv_check_cred(cr, PRIV_VFS_MOUNT, 0)); +} + +int +secpolicy_vnode_owner(struct vnode *vp, cred_t *cred, uid_t owner) +{ + + if (owner == cred->cr_uid) + return (0); + if (secpolicy_fs_owner(vp->v_mount, cred) == 0) + return (0); + + /* XXX: vfs_suser()? */ + return (priv_check_cred(cred, PRIV_VFS_MOUNT_OWNER, 0)); +} + +int +secpolicy_vnode_chown(struct vnode *vp, cred_t *cred, boolean_t check_self) +{ + + if (secpolicy_fs_owner(vp->v_mount, cred) == 0) + return (0); + return (priv_check_cred(cred, PRIV_VFS_CHOWN, 0)); +} + +void +secpolicy_fs_mount_clearopts(cred_t *cr, struct mount *vfsp) +{ + + if (priv_check_cred(cr, PRIV_VFS_MOUNT_NONUSER, 0) != 0) { + MNT_ILOCK(vfsp); + vfsp->vfs_flag |= VFS_NOSETUID | MNT_USER; + vfs_clearmntopt(vfsp, MNTOPT_SETUID); + vfs_setmntopt(vfsp, MNTOPT_NOSETUID, NULL, 0); + MNT_IUNLOCK(vfsp); + } +} + +/* + * Check privileges for setting xvattr attributes + */ +int +secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype) +{ + + return (priv_check_cred(cr, PRIV_VFS_SYSFLAGS, 0)); +} diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c b/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c index e9120ee..f1bb4e2 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_vfs.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/malloc.h> #include <sys/mount.h> #include <sys/cred.h> #include <sys/vfs.h> @@ -110,60 +111,12 @@ vfs_optionisset(const vfs_t *vfsp, const char *opt, char **argp) } int -traverse(vnode_t **cvpp, int lktype) -{ - kthread_t *td = curthread; - vnode_t *cvp; - vnode_t *tvp; - vfs_t *vfsp; - int error; - - cvp = *cvpp; - tvp = NULL; - - /* - * If this vnode is mounted on, then we transparently indirect - * to the vnode which is the root of the mounted file system. - * Before we do this we must check that an unmount is not in - * progress on this vnode. - */ - - for (;;) { - /* - * Reached the end of the mount chain? - */ - vfsp = vn_mountedvfs(cvp); - if (vfsp == NULL) - break; - /* - * tvp is NULL for *cvpp vnode, which we can't unlock. - */ - if (tvp != NULL) - vput(cvp); - else - vrele(cvp); - - /* - * The read lock must be held across the call to VFS_ROOT() to - * prevent a concurrent unmount from destroying the vfs. - */ - error = VFS_ROOT(vfsp, lktype, &tvp, td); - if (error != 0) - return (error); - cvp = tvp; - } - - *cvpp = cvp; - return (0); -} - -int domount(kthread_t *td, vnode_t *vp, const char *fstype, char *fspath, char *fspec, int fsflags) { struct mount *mp; struct vfsconf *vfsp; - struct ucred *newcr, *oldcr; + struct ucred *cr; int error; /* @@ -203,29 +156,31 @@ domount(kthread_t *td, vnode_t *vp, const char *fstype, char *fspath, /* * Set the mount level flags. - * crdup() can sleep, so do it before acquiring a mutex. */ - newcr = crdup(kcred); - MNT_ILOCK(mp); if (fsflags & MNT_RDONLY) mp->mnt_flag |= MNT_RDONLY; mp->mnt_flag &=~ MNT_UPDATEMASK; mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE | MNT_ROOTFS); /* * Unprivileged user can trigger mounting a snapshot, but we don't want - * him to unmount it, so we switch to privileged credentials. + * him to unmount it, so we switch to privileged of original mount. */ - oldcr = mp->mnt_cred; - mp->mnt_cred = newcr; + crfree(mp->mnt_cred); + mp->mnt_cred = crdup(vp->v_mount->mnt_cred); mp->mnt_stat.f_owner = mp->mnt_cred->cr_uid; - MNT_IUNLOCK(mp); - crfree(oldcr); /* * Mount the filesystem. * XXX The final recipients of VFS_MOUNT just overwrite the ndp they * get. No freeing of cn_pnbuf. */ + /* + * XXX: This is evil, but we can't mount a snapshot as a regular user. + * XXX: Is is safe when snapshot is mounted from within a jail? + */ + cr = td->td_ucred; + td->td_ucred = kcred; error = VFS_MOUNT(mp, td); + td->td_ucred = cr; if (!error) { if (mp->mnt_opt != NULL) diff --git a/sys/cddl/compat/opensolaris/kern/opensolaris_zone.c b/sys/cddl/compat/opensolaris/kern/opensolaris_zone.c index 3059a78..8489052 100644 --- a/sys/cddl/compat/opensolaris/kern/opensolaris_zone.c +++ b/sys/cddl/compat/opensolaris/kern/opensolaris_zone.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <sys/malloc.h> #include <sys/queue.h> #include <sys/jail.h> +#include <sys/osd.h> #include <sys/priv.h> #include <sys/zone.h> @@ -52,7 +53,7 @@ typedef struct zone_dataset { LIST_HEAD(zone_dataset_head, zone_dataset); -static struct prison_service *zone_prison_service = NULL; +static int zone_slot; int zone_dataset_attach(struct ucred *cred, const char *dataset, int jailid) @@ -60,7 +61,7 @@ zone_dataset_attach(struct ucred *cred, const char *dataset, int jailid) struct zone_dataset_head *head; zone_dataset_t *zd, *zd2; struct prison *pr; - int error; + int dofree, error; if ((error = priv_check_cred(cred, PRIV_ZFS_JAIL, 0)) != 0) return (error); @@ -76,18 +77,33 @@ zone_dataset_attach(struct ucred *cred, const char *dataset, int jailid) return (ENOENT); } - head = prison_service_data_get(zone_prison_service, pr); - LIST_FOREACH(zd2, head, zd_next) { - if (strcmp(dataset, zd2->zd_dataset) == 0) { - free(zd, M_ZONES); - error = EEXIST; - goto failure; + head = osd_jail_get(pr, zone_slot); + if (head != NULL) { + dofree = 0; + LIST_FOREACH(zd2, head, zd_next) { + if (strcmp(dataset, zd2->zd_dataset) == 0) { + free(zd, M_ZONES); + error = EEXIST; + goto end; + } } + } else { + dofree = 1; + prison_hold_locked(pr); + mtx_unlock(&pr->pr_mtx); + head = malloc(sizeof(*head), M_ZONES, M_WAITOK); + LIST_INIT(head); + mtx_lock(&pr->pr_mtx); + error = osd_jail_set(pr, zone_slot, head); + KASSERT(error == 0, ("osd_jail_set() failed (error=%d)", error)); } strcpy(zd->zd_dataset, dataset); LIST_INSERT_HEAD(head, zd, zd_next); -failure: - mtx_unlock(&pr->pr_mtx); +end: + if (dofree) + prison_free_locked(pr); + else + mtx_unlock(&pr->pr_mtx); return (error); } @@ -107,16 +123,25 @@ zone_dataset_detach(struct ucred *cred, const char *dataset, int jailid) sx_sunlock(&allprison_lock); if (pr == NULL) return (ENOENT); - head = prison_service_data_get(zone_prison_service, pr); + head = osd_jail_get(pr, zone_slot); + if (head == NULL) { + error = ENOENT; + goto end; + } LIST_FOREACH(zd, head, zd_next) { - if (strcmp(dataset, zd->zd_dataset) == 0) { - LIST_REMOVE(zd, zd_next); - free(zd, M_ZONES); - goto success; - } + if (strcmp(dataset, zd->zd_dataset) == 0) + break; } - error = ENOENT; -success: + if (zd == NULL) + error = ENOENT; + else { + LIST_REMOVE(zd, zd_next); + free(zd, M_ZONES); + if (LIST_EMPTY(head)) + osd_jail_del(pr, zone_slot); + error = 0; + } +end: mtx_unlock(&pr->pr_mtx); return (error); } @@ -136,14 +161,16 @@ zone_dataset_visible(const char *dataset, int *write) if (dataset[0] == '\0') return (0); - if (INGLOBALZONE(curproc)) { + if (INGLOBALZONE(curthread)) { if (write != NULL) *write = 1; return (1); } pr = curthread->td_ucred->cr_prison; mtx_lock(&pr->pr_mtx); - head = prison_service_data_get(zone_prison_service, pr); + head = osd_jail_get(pr, zone_slot); + if (head == NULL) + goto end; /* * Walk the list once, looking for datasets which match exactly, or @@ -188,49 +215,32 @@ end: return (ret); } -static int -zone_create(struct prison_service *psrv, struct prison *pr) -{ - struct zone_dataset_head *head; - - head = malloc(sizeof(*head), M_ZONES, M_WAITOK); - LIST_INIT(head); - mtx_lock(&pr->pr_mtx); - prison_service_data_set(psrv, pr, head); - mtx_unlock(&pr->pr_mtx); - return (0); -} - -static int -zone_destroy(struct prison_service *psrv, struct prison *pr) +static void +zone_destroy(void *arg) { struct zone_dataset_head *head; zone_dataset_t *zd; - mtx_lock(&pr->pr_mtx); - head = prison_service_data_del(psrv, pr); - mtx_unlock(&pr->pr_mtx); - while ((zd = LIST_FIRST(head)) != NULL) { - LIST_REMOVE(zd, zd_next); - free(zd, M_ZONES); - } - free(head, M_ZONES); - return (0); + head = arg; + while ((zd = LIST_FIRST(head)) != NULL) { + LIST_REMOVE(zd, zd_next); + free(zd, M_ZONES); + } + free(head, M_ZONES); } static void zone_sysinit(void *arg __unused) { - zone_prison_service = prison_service_register("zfs", zone_create, - zone_destroy); + zone_slot = osd_jail_register(zone_destroy); } static void zone_sysuninit(void *arg __unused) { - prison_service_deregister(zone_prison_service); + osd_jail_deregister(zone_slot); } SYSINIT(zone_sysinit, SI_SUB_DRIVERS, SI_ORDER_ANY, zone_sysinit, NULL); |