[BACK]Return to vfs_syscalls.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/kern/vfs_syscalls.c between version 1.350 and 1.350.2.9

version 1.350, 2008/04/25 13:40:55 version 1.350.2.9, 2010/10/09 03:32:33
Line 1 
Line 1 
 /*      $NetBSD$        */  /*      $NetBSD$        */
   
 /*-  /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.   * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
  * All rights reserved.   * All rights reserved.
  *   *
    * This code is derived from software contributed to The NetBSD Foundation
    * by Andrew Doran.
    *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
  * are met:   * are met:
Line 12 
Line 15 
  * 2. Redistributions in binary form must reproduce the above copyright   * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the   *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.   *    documentation and/or other materials provided with the distribution.
  * 3. All advertising materials mentioning features or use of this software  
  *    must display the following acknowledgement:  
  *      This product includes software developed by the NetBSD  
  *      Foundation, Inc. and its contributors.  
  * 4. Neither the name of The NetBSD Foundation nor the names of its  
  *    contributors may be used to endorse or promote products derived  
  *    from this software without specific prior written permission.  
  *   *
  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS   * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
Line 72 
Line 68 
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD$");  __KERNEL_RCSID(0, "$NetBSD$");
   
 #include "opt_compat_netbsd.h"  #ifdef _KERNEL_OPT
 #include "opt_compat_43.h"  
 #include "opt_fileassoc.h"  #include "opt_fileassoc.h"
 #include "fss.h"  
 #include "veriexec.h"  #include "veriexec.h"
   #endif
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
Line 89  __KERNEL_RCSID(0, "$NetBSD$");
Line 84  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/mount.h>  #include <sys/mount.h>
 #include <sys/proc.h>  #include <sys/proc.h>
 #include <sys/uio.h>  #include <sys/uio.h>
 #include <sys/malloc.h>  
 #include <sys/kmem.h>  #include <sys/kmem.h>
 #include <sys/dirent.h>  #include <sys/dirent.h>
 #include <sys/sysctl.h>  #include <sys/sysctl.h>
Line 102  __KERNEL_RCSID(0, "$NetBSD$");
Line 96  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/verified_exec.h>  #include <sys/verified_exec.h>
 #include <sys/kauth.h>  #include <sys/kauth.h>
 #include <sys/atomic.h>  #include <sys/atomic.h>
   #include <sys/module.h>
   #include <sys/buf.h>
   
 #include <miscfs/genfs/genfs.h>  #include <miscfs/genfs/genfs.h>
 #include <miscfs/syncfs/syncfs.h>  #include <miscfs/syncfs/syncfs.h>
 #include <miscfs/specfs/specdev.h>  #include <miscfs/specfs/specdev.h>
   
 #ifdef COMPAT_30  
 #include "opt_nfsserver.h"  
 #include <nfs/rpcv2.h>  #include <nfs/rpcv2.h>
 #endif  
 #include <nfs/nfsproto.h>  #include <nfs/nfsproto.h>
 #ifdef COMPAT_30  
 #include <nfs/nfs.h>  #include <nfs/nfs.h>
 #include <nfs/nfs_var.h>  #include <nfs/nfs_var.h>
 #endif  
   
 #if NFSS > 0  
 #include <dev/fssvar.h>  
 #endif  
   
 MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct");  MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct");
   
 static int change_dir(struct nameidata *, struct lwp *);  
 static int change_flags(struct vnode *, u_long, struct lwp *);  static int change_flags(struct vnode *, u_long, struct lwp *);
 static int change_mode(struct vnode *, int, struct lwp *l);  static int change_mode(struct vnode *, int, struct lwp *l);
 static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int);  static int change_owner(struct vnode *, uid_t, gid_t, struct lwp *, int);
   
 void checkdirs(struct vnode *);  void checkdirs(struct vnode *);
   
 int dovfsusermount = 0;  
   
 /*  /*
  * Virtual File System System Calls   * Virtual File System System Calls
  */   */
Line 140  int dovfsusermount = 0;
Line 124  int dovfsusermount = 0;
  * Mount a file system.   * Mount a file system.
  */   */
   
 #if defined(COMPAT_09) || defined(COMPAT_43)  
 /*  /*
  * This table is used to maintain compatibility with 4.3BSD   * This table is used to maintain compatibility with 4.3BSD
  * and NetBSD 0.9 mount syscalls.  Note, the order is important!   * and NetBSD 0.9 mount syscalls - and possibly other systems.
    * Note, the order is important!
  *   *
  * Do not modify this table. It should only contain filesystems   * Do not modify this table. It should only contain filesystems
  * supported by NetBSD 0.9 and 4.3BSD.   * supported by NetBSD 0.9 and 4.3BSD.
Line 162  const char * const mountcompatnames[] = 
Line 146  const char * const mountcompatnames[] = 
 };  };
 const int nmountcompatnames = sizeof(mountcompatnames) /  const int nmountcompatnames = sizeof(mountcompatnames) /
     sizeof(mountcompatnames[0]);      sizeof(mountcompatnames[0]);
 #endif /* COMPAT_09 || COMPAT_43 */  
   
 static int  static int
 mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags,  mount_update(struct lwp *l, struct vnode *vp, const char *path, int flags,
Line 182  mount_update(struct lwp *l, struct vnode
Line 165  mount_update(struct lwp *l, struct vnode
   
         /*          /*
          * We only allow the filesystem to be reloaded if it           * We only allow the filesystem to be reloaded if it
          * is currently mounted read-only.           * is currently mounted read-only.  Additionally, we
            * prevent read-write to read-only downgrades.
          */           */
         if (flags & MNT_RELOAD && !(mp->mnt_flag & MNT_RDONLY)) {          if ((flags & (MNT_RELOAD | MNT_RDONLY)) != 0 &&
               (mp->mnt_flag & MNT_RDONLY) == 0) {
                 error = EOPNOTSUPP;     /* Needs translation */                  error = EOPNOTSUPP;     /* Needs translation */
                 goto out;                  goto out;
         }          }
Line 194  mount_update(struct lwp *l, struct vnode
Line 179  mount_update(struct lwp *l, struct vnode
         if (error)          if (error)
                 goto out;                  goto out;
   
         if (vfs_trybusy(mp, RW_WRITER, 0)) {          if (vfs_busy(mp, NULL)) {
                 error = EPERM;                  error = EPERM;
                 goto out;                  goto out;
         }          }
   
           mutex_enter(&mp->mnt_updating);
   
         mp->mnt_flag &= ~MNT_OP_FLAGS;          mp->mnt_flag &= ~MNT_OP_FLAGS;
         mp->mnt_flag |= flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);          mp->mnt_flag |= flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
   
Line 212  mount_update(struct lwp *l, struct vnode
Line 199  mount_update(struct lwp *l, struct vnode
         mp->mnt_flag &=          mp->mnt_flag &=
           ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |            ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
             MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |              MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
             MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP);              MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
               MNT_LOG);
         mp->mnt_flag |= flags &          mp->mnt_flag |= flags &
            (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |             (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
             MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |              MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
             MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |              MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
             MNT_IGNORE);              MNT_LOG | MNT_IGNORE);
   
         error = VFS_MOUNT(mp, path, data, data_len);          error = VFS_MOUNT(mp, path, data, data_len);
   
 #if defined(COMPAT_30) && defined(NFSSERVER)  
         if (error && data != NULL) {          if (error && data != NULL) {
                 int error2;                  int error2;
   
                 /* Update failed; let's try and see if it was an                  /*
                  * export request. */                   * Update failed; let's try and see if it was an
                 error2 = nfs_update_exports_30(mp, path, data, l);                   * export request.  For compat with 3.0 and earlier.
                    */
                   error2 = vfs_hooks_reexport(mp, path, data);
   
                 /* Only update error code if the export request was                  /*
                    * Only update error code if the export request was
                  * understood but some problem occurred while                   * understood but some problem occurred while
                  * processing it. */                   * processing it.
                    */
                 if (error2 != EJUSTRETURN)                  if (error2 != EJUSTRETURN)
                         error = error2;                          error = error2;
         }          }
 #endif  
         if (mp->mnt_iflag & IMNT_WANTRDWR)          if (mp->mnt_iflag & IMNT_WANTRDWR)
                 mp->mnt_flag &= ~MNT_RDONLY;                  mp->mnt_flag &= ~MNT_RDONLY;
         if (error)          if (error)
Line 249  mount_update(struct lwp *l, struct vnode
Line 240  mount_update(struct lwp *l, struct vnode
                 if (mp->mnt_syncer != NULL)                  if (mp->mnt_syncer != NULL)
                         vfs_deallocate_syncvnode(mp);                          vfs_deallocate_syncvnode(mp);
         }          }
         vfs_unbusy(mp, false);          mutex_exit(&mp->mnt_updating);
           vfs_unbusy(mp, false, NULL);
   
  out:   out:
         return (error);          return (error);
Line 264  mount_get_vfsops(const char *fstype, str
Line 256  mount_get_vfsops(const char *fstype, str
         /* Copy file-system type from userspace.  */          /* Copy file-system type from userspace.  */
         error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL);          error = copyinstr(fstype, fstypename, sizeof(fstypename), NULL);
         if (error) {          if (error) {
 #if defined(COMPAT_09) || defined(COMPAT_43)  
                 /*                  /*
                  * Historically, filesystem types were identified by numbers.                   * Historically, filesystem types were identified by numbers.
                  * If we get an integer for the filesystem type instead of a                   * If we get an integer for the filesystem type instead of a
Line 277  mount_get_vfsops(const char *fstype, str
Line 268  mount_get_vfsops(const char *fstype, str
                         return ENODEV;                          return ENODEV;
                 strlcpy(fstypename, mountcompatnames[fsindex],                  strlcpy(fstypename, mountcompatnames[fsindex],
                     sizeof(fstypename));                      sizeof(fstypename));
 #else  
                 return error;  
 #endif  
         }          }
   
 #ifdef  COMPAT_10          /* Accept `ufs' as an alias for `ffs', for compatibility. */
         /* Accept `ufs' as an alias for `ffs'. */  
         if (strcmp(fstypename, "ufs") == 0)          if (strcmp(fstypename, "ufs") == 0)
                 fstypename[0] = 'f';                  fstypename[0] = 'f';
 #endif  
   
         if ((*vfsops = vfs_getopsbyname(fstypename)) == NULL)          if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
                 return ENODEV;                  return 0;
         return 0;  
           /* If we can autoload a vfs module, try again */
           (void)module_autoload(fstypename, MODULE_CLASS_VFS);
   
           if ((*vfsops = vfs_getopsbyname(fstypename)) != NULL)
                   return 0;
   
           return ENODEV;
 }  }
   
 static int  static int
 mount_domount(struct lwp *l, struct vnode **vpp, struct vfsops *vfsops,  mount_domount(struct lwp *l, struct vnode **vpp, struct vfsops *vfsops,
     const char *path, int flags, void *data, size_t *data_len, u_int recurse)      const char *path, int flags, void *data, size_t *data_len)
 {  {
         struct mount *mp = NULL;          struct mount *mp;
         struct vnode *vp = *vpp;          struct vnode *vp = *vpp;
         struct vattr va;          struct vattr va;
           struct nameidata nd;
         int error;          int error;
   
         error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,          error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
             KAUTH_REQ_SYSTEM_MOUNT_NEW, vp, KAUTH_ARG(flags), data);              KAUTH_REQ_SYSTEM_MOUNT_NEW, vp, KAUTH_ARG(flags), data);
         if (error)          if (error) {
                   vfs_delref(vfsops);
                 return error;                  return error;
           }
   
         /* Can't make a non-dir a mount-point (from here anyway). */          /* Can't make a non-dir a mount-point (from here anyway). */
         if (vp->v_type != VDIR)          if (vp->v_type != VDIR) {
                   vfs_delref(vfsops);
                 return ENOTDIR;                  return ENOTDIR;
           }
   
         /*          /*
          * If the user is not root, ensure that they own the directory           * If the user is not root, ensure that they own the directory
          * onto which we are attempting to mount.           * onto which we are attempting to mount.
          */           */
         if ((error = VOP_GETATTR(vp, &va, l->l_cred)) != 0 ||          vn_lock(vp, LK_SHARED | LK_RETRY);
             (va.va_uid != kauth_cred_geteuid(l->l_cred) &&          error = VOP_GETATTR(vp, &va, l->l_cred);
           VOP_UNLOCK(vp);
           if (error != 0) {
                   vfs_delref(vfsops);
                   return error;
           }
           if ((va.va_uid != kauth_cred_geteuid(l->l_cred) &&
             (error = kauth_authorize_generic(l->l_cred,              (error = kauth_authorize_generic(l->l_cred,
             KAUTH_GENERIC_ISSUSER, NULL)) != 0)) {              KAUTH_GENERIC_ISSUSER, NULL)) != 0)) {
                   vfs_delref(vfsops);
                 return error;                  return error;
         }          }
   
         if (flags & MNT_EXPORTED)          if (flags & MNT_EXPORTED) {
                   vfs_delref(vfsops);
                 return EINVAL;                  return EINVAL;
           }
   
         if ((error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0)) != 0)          if ((mp = vfs_mountalloc(vfsops, vp)) == NULL) {
                 return error;                  vfs_delref(vfsops);
   
         /*  
          * Check if a file-system is not already mounted on this vnode.  
          */  
         if (vp->v_mountedhere != NULL)  
                 return EBUSY;  
   
         mp = kmem_zalloc(sizeof(*mp), KM_SLEEP);  
         if (mp == NULL)  
                 return ENOMEM;                  return ENOMEM;
           }
   
         mp->mnt_op = vfsops;  
         mp->mnt_refcnt = 1;  
   
         TAILQ_INIT(&mp->mnt_vnodelist);  
         rw_init(&mp->mnt_lock);  
         mutex_init(&mp->mnt_renamelock, MUTEX_DEFAULT, IPL_NONE);  
         (void)vfs_busy(mp, RW_WRITER, 0);  
   
         mp->mnt_vnodecovered = vp;  
         mp->mnt_stat.f_owner = kauth_cred_geteuid(l->l_cred);          mp->mnt_stat.f_owner = kauth_cred_geteuid(l->l_cred);
         mount_initspecific(mp);  
   
         /*          /*
          * The underlying file system may refuse the mount for           * The underlying file system may refuse the mount for
Line 360  mount_domount(struct lwp *l, struct vnod
Line 349  mount_domount(struct lwp *l, struct vnod
            (MNT_FORCE | MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |             (MNT_FORCE | MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
             MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |              MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
             MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |              MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
             MNT_IGNORE | MNT_RDONLY);              MNT_LOG | MNT_IGNORE | MNT_RDONLY);
   
           mutex_enter(&mp->mnt_updating);
         error = VFS_MOUNT(mp, path, data, data_len);          error = VFS_MOUNT(mp, path, data, data_len);
         mp->mnt_flag &= ~MNT_OP_FLAGS;          mp->mnt_flag &= ~MNT_OP_FLAGS;
   
           if (error != 0)
                   goto err_unmounted;
   
         /*          /*
          * Put the new filesystem on the mount list after root.           * Validate and prepare the mount point.
          */           */
         cache_purge(vp);          NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT,
               UIO_USERSPACE, path);
           error = namei(&nd);
         if (error != 0) {          if (error != 0) {
                 vp->v_mountedhere = NULL;                  goto err_mounted;
                 mp->mnt_op->vfs_refcount--;          }
                 vfs_unbusy(mp, false);          if (nd.ni_vp != vp) {
                 vfs_destroy(mp);                  vput(nd.ni_vp);
                 return error;                  error = EINVAL;
                   goto err_mounted;
           }
           if (vp->v_mountedhere != NULL) {
                   vput(nd.ni_vp);
                   error = EBUSY;
                   goto err_mounted;
           }
           error = vinvalbuf(vp, V_SAVE, l->l_cred, l, 0, 0);
           if (error != 0) {
                   vput(nd.ni_vp);
                   goto err_mounted;
         }          }
   
           /*
            * Put the new filesystem on the mount list after root.
            */
           cache_purge(vp);
         mp->mnt_iflag &= ~IMNT_WANTRDWR;          mp->mnt_iflag &= ~IMNT_WANTRDWR;
   
         mutex_enter(&mountlist_lock);          mutex_enter(&mountlist_lock);
         vp->v_mountedhere = mp;  
         CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);          CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
         mutex_exit(&mountlist_lock);          mutex_exit(&mountlist_lock);
         vn_restorerecurse(vp, recurse);  
         VOP_UNLOCK(vp, 0);  
         checkdirs(vp);  
         if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)          if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
                 error = vfs_allocate_syncvnode(mp);                  error = vfs_allocate_syncvnode(mp);
           if (error == 0)
                   vp->v_mountedhere = mp;
           vput(nd.ni_vp);
           if (error != 0)
                   goto err_onmountlist;
   
           checkdirs(vp);
           mutex_exit(&mp->mnt_updating);
   
         /* Hold an additional reference to the mount across VFS_START(). */          /* Hold an additional reference to the mount across VFS_START(). */
         vfs_unbusy(mp, true);          vfs_unbusy(mp, true, NULL);
         (void) VFS_STATVFS(mp, &mp->mnt_stat);          (void) VFS_STATVFS(mp, &mp->mnt_stat);
         error = VFS_START(mp, 0);          error = VFS_START(mp, 0);
         if (error) {          if (error)
                 vrele(vp);                  vrele(vp);
                 vfs_destroy(mp);  
         }  
         /* Drop reference held for VFS_START(). */          /* Drop reference held for VFS_START(). */
         vfs_destroy(mp);          vfs_destroy(mp);
         *vpp = NULL;          *vpp = NULL;
         return error;          return error;
   
   err_onmountlist:
           mutex_enter(&mountlist_lock);
           CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
           mp->mnt_iflag |= IMNT_GONE;
           mutex_exit(&mountlist_lock);
   
   err_mounted:
           if (VFS_UNMOUNT(mp, MNT_FORCE) != 0)
                   panic("Unmounting fresh file system failed");
   
   err_unmounted:
           vp->v_mountedhere = NULL;
           mutex_exit(&mp->mnt_updating);
           vfs_unbusy(mp, false, NULL);
           vfs_destroy(mp);
   
           return error;
 }  }
   
 static int  static int
Line 423  mount_getargs(struct lwp *l, struct vnod
Line 455  mount_getargs(struct lwp *l, struct vnod
         if ((vp->v_vflag & VV_ROOT) == 0)          if ((vp->v_vflag & VV_ROOT) == 0)
                 return EINVAL;                  return EINVAL;
   
         if (vfs_trybusy(mp, RW_WRITER, NULL))          if (vfs_busy(mp, NULL))
                 return EPERM;                  return EPERM;
   
           mutex_enter(&mp->mnt_updating);
         mp->mnt_flag &= ~MNT_OP_FLAGS;          mp->mnt_flag &= ~MNT_OP_FLAGS;
         mp->mnt_flag |= MNT_GETARGS;          mp->mnt_flag |= MNT_GETARGS;
         error = VFS_MOUNT(mp, path, data, data_len);          error = VFS_MOUNT(mp, path, data, data_len);
         mp->mnt_flag &= ~MNT_OP_FLAGS;          mp->mnt_flag &= ~MNT_OP_FLAGS;
           mutex_exit(&mp->mnt_updating);
   
         vfs_unbusy(mp, false);          vfs_unbusy(mp, false, NULL);
         return (error);          return (error);
 }  }
   
 #ifdef COMPAT_40  
 /* ARGSUSED */  
 int  
 compat_40_sys_mount(struct lwp *l, const struct compat_40_sys_mount_args *uap, register_t *retval)  
 {  
         /* {  
                 syscallarg(const char *) type;  
                 syscallarg(const char *) path;  
                 syscallarg(int) flags;  
                 syscallarg(void *) data;  
         } */  
         register_t dummy;  
   
         return do_sys_mount(l, NULL, SCARG(uap, type), SCARG(uap, path),  
             SCARG(uap, flags), SCARG(uap, data), UIO_USERSPACE, 0, &dummy);  
 }  
 #endif  
   
 int  int
 sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval)  sys___mount50(struct lwp *l, const struct sys___mount50_args *uap, register_t *retval)
 {  {
Line 475  do_sys_mount(struct lwp *l, struct vfsop
Line 491  do_sys_mount(struct lwp *l, struct vfsop
     size_t data_len, register_t *retval)      size_t data_len, register_t *retval)
 {  {
         struct vnode *vp;          struct vnode *vp;
         struct nameidata nd;  
         void *data_buf = data;          void *data_buf = data;
         u_int recurse;          bool vfsopsrele = false;
         int error;          int error;
   
           /* XXX: The calling convention of this routine is totally bizarre */
           if (vfsops)
                   vfsopsrele = true;
   
         /*          /*
          * Get vnode to be covered           * Get vnode to be covered
          */           */
         NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, path);          error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0) {
                 return (error);                  vp = NULL;
         vp = nd.ni_vp;                  goto done;
           }
   
         /*  
          * A lookup in VFS_MOUNT might result in an attempt to  
          * lock this vnode again, so make the lock recursive.  
          */  
         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);  
         recurse = vn_setrecurse(vp);  
   
         if (vfsops == NULL) {          if (vfsops == NULL) {
                 if (flags & (MNT_GETARGS | MNT_UPDATE))                  if (flags & (MNT_GETARGS | MNT_UPDATE)) {
                         vfsops = vp->v_mount->mnt_op;                          vfsops = vp->v_mount->mnt_op;
                 else {                  } else {
                         /* 'type' is userspace */                          /* 'type' is userspace */
                         error = mount_get_vfsops(type, &vfsops);                          error = mount_get_vfsops(type, &vfsops);
                         if (error != 0)                          if (error != 0)
                                 goto done;                                  goto done;
                           vfsopsrele = true;
                 }                  }
         }          }
   
Line 511  do_sys_mount(struct lwp *l, struct vfsop
Line 525  do_sys_mount(struct lwp *l, struct vfsop
                         /* No length supplied, use default for filesystem */                          /* No length supplied, use default for filesystem */
                         data_len = vfsops->vfs_min_mount_data;                          data_len = vfsops->vfs_min_mount_data;
                         if (data_len > VFS_MAX_MOUNT_DATA) {                          if (data_len > VFS_MAX_MOUNT_DATA) {
                                 /* maybe a force loaded old LKM */  
                                 error = EINVAL;                                  error = EINVAL;
                                 goto done;                                  goto done;
                         }                          }
 #ifdef COMPAT_30                          /*
                         /* Hopefully a longer buffer won't make copyin() fail */                           * Hopefully a longer buffer won't make copyin() fail.
                            * For compatibility with 3.0 and earlier.
                            */
                         if (flags & MNT_UPDATE                          if (flags & MNT_UPDATE
                             && data_len < sizeof (struct mnt_export_args30))                              && data_len < sizeof (struct mnt_export_args30))
                                 data_len = sizeof (struct mnt_export_args30);                                  data_len = sizeof (struct mnt_export_args30);
 #endif  
                 }                  }
                 data_buf = malloc(data_len, M_TEMP, M_WAITOK);                  data_buf = kmem_alloc(data_len, KM_SLEEP);
   
                 /* NFS needs the buffer even for mnt_getargs .... */                  /* NFS needs the buffer even for mnt_getargs .... */
                 error = copyin(data, data_buf, data_len);                  error = copyin(data, data_buf, data_len);
Line 545  do_sys_mount(struct lwp *l, struct vfsop
Line 559  do_sys_mount(struct lwp *l, struct vfsop
                 error = mount_update(l, vp, path, flags, data_buf, &data_len);                  error = mount_update(l, vp, path, flags, data_buf, &data_len);
         } else {          } else {
                 /* Locking is handled internally in mount_domount(). */                  /* Locking is handled internally in mount_domount(). */
                   KASSERT(vfsopsrele == true);
                 error = mount_domount(l, &vp, vfsops, path, flags, data_buf,                  error = mount_domount(l, &vp, vfsops, path, flags, data_buf,
                     &data_len, recurse);                      &data_len);
                   vfsopsrele = false;
         }          }
   
     done:      done:
           if (vfsopsrele)
                   vfs_delref(vfsops);
         if (vp != NULL) {          if (vp != NULL) {
                 vn_restorerecurse(vp, recurse);                  vrele(vp);
                 vput(vp);  
         }          }
         if (data_buf != data)          if (data_buf != data)
                 free(data_buf, M_TEMP);                  kmem_free(data_buf, data_len);
         return (error);          return (error);
 }  }
   
Line 568  void
Line 585  void
 checkdirs(struct vnode *olddp)  checkdirs(struct vnode *olddp)
 {  {
         struct cwdinfo *cwdi;          struct cwdinfo *cwdi;
         struct vnode *newdp;          struct vnode *newdp, *rele1, *rele2;
         struct proc *p;          struct proc *p;
           bool retry;
   
         if (olddp->v_usecount == 1)          if (olddp->v_usecount == 1)
                 return;                  return;
         if (VFS_ROOT(olddp->v_mountedhere, &newdp))          if (VFS_ROOT(olddp->v_mountedhere, &newdp))
                 panic("mount: lost mount");                  panic("mount: lost mount");
         mutex_enter(proc_lock);  
         /* XXXAD Should not be acquiring these locks with proc_lock held!! */          do {
         PROCLIST_FOREACH(p, &allproc) {                  retry = false;
                 cwdi = p->p_cwdi;                  mutex_enter(proc_lock);
                 if (!cwdi)                  PROCLIST_FOREACH(p, &allproc) {
                         continue;                          if ((cwdi = p->p_cwdi) == NULL)
                 rw_enter(&cwdi->cwdi_lock, RW_WRITER);                                  continue;
                 if (cwdi->cwdi_cdir == olddp) {                          /*
                         vrele(cwdi->cwdi_cdir);                           * Can't change to the old directory any more,
                         VREF(newdp);                           * so even if we see a stale value it's not a
                         cwdi->cwdi_cdir = newdp;                           * problem.
                 }                           */
                 if (cwdi->cwdi_rdir == olddp) {                          if (cwdi->cwdi_cdir != olddp &&
                         vrele(cwdi->cwdi_rdir);                              cwdi->cwdi_rdir != olddp)
                         VREF(newdp);                                  continue;
                         cwdi->cwdi_rdir = newdp;                          retry = true;
                           rele1 = NULL;
                           rele2 = NULL;
                           atomic_inc_uint(&cwdi->cwdi_refcnt);
                           mutex_exit(proc_lock);
                           rw_enter(&cwdi->cwdi_lock, RW_WRITER);
                           if (cwdi->cwdi_cdir == olddp) {
                                   rele1 = cwdi->cwdi_cdir;
                                   vref(newdp);
                                   cwdi->cwdi_cdir = newdp;
                           }
                           if (cwdi->cwdi_rdir == olddp) {
                                   rele2 = cwdi->cwdi_rdir;
                                   vref(newdp);
                                   cwdi->cwdi_rdir = newdp;
                           }
                           rw_exit(&cwdi->cwdi_lock);
                           cwdfree(cwdi);
                           if (rele1 != NULL)
                                   vrele(rele1);
                           if (rele2 != NULL)
                                   vrele(rele2);
                           mutex_enter(proc_lock);
                           break;
                 }                  }
                 rw_exit(&cwdi->cwdi_lock);                  mutex_exit(proc_lock);
         }          } while (retry);
         mutex_exit(proc_lock);  
         if (rootvnode == olddp) {          if (rootvnode == olddp) {
                 vrele(rootvnode);                  vrele(rootvnode);
                 VREF(newdp);                  vref(newdp);
                 rootvnode = newdp;                  rootvnode = newdp;
         }          }
         vput(newdp);          vput(newdp);
Line 628  sys_unmount(struct lwp *l, const struct 
Line 669  sys_unmount(struct lwp *l, const struct 
                 return (error);                  return (error);
         vp = nd.ni_vp;          vp = nd.ni_vp;
         mp = vp->v_mount;          mp = vp->v_mount;
         VOP_UNLOCK(vp, 0);          atomic_inc_uint(&mp->mnt_refcnt);
           VOP_UNLOCK(vp);
   
         error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,          error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
             KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL);              KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT, mp, NULL, NULL);
         if (error) {          if (error) {
                 vrele(vp);                  vrele(vp);
                   vfs_destroy(mp);
                 return (error);                  return (error);
         }          }
   
Line 642  sys_unmount(struct lwp *l, const struct 
Line 685  sys_unmount(struct lwp *l, const struct 
          */           */
         if (mp->mnt_flag & MNT_ROOTFS) {          if (mp->mnt_flag & MNT_ROOTFS) {
                 vrele(vp);                  vrele(vp);
                   vfs_destroy(mp);
                 return (EINVAL);                  return (EINVAL);
         }          }
   
Line 650  sys_unmount(struct lwp *l, const struct 
Line 694  sys_unmount(struct lwp *l, const struct 
          */           */
         if ((vp->v_vflag & VV_ROOT) == 0) {          if ((vp->v_vflag & VV_ROOT) == 0) {
                 vrele(vp);                  vrele(vp);
                   vfs_destroy(mp);
                 return (EINVAL);                  return (EINVAL);
         }          }
   
         /*  
          * XXX Freeze syncer.  Must do this before locking the  
          * mount point.  See dounmount() for details.  
          */  
         mutex_enter(&syncer_mutex);  
         error = vfs_busy(mp, RW_WRITER, NULL);  
         vrele(vp);          vrele(vp);
         if (error != 0) {          error = dounmount(mp, SCARG(uap, flags), l);
                 mutex_exit(&syncer_mutex);          vfs_destroy(mp);
                 return (error);          return error;
         }  
   
         return (dounmount(mp, SCARG(uap, flags), l));  
 }  }
   
 /*  /*
  * Do the actual file system unmount. File system is assumed to have been   * Do the actual file system unmount.  File system is assumed to have
  * marked busy by the caller.   * been locked by the caller.
    *
    * => Caller hold reference to the mount, explicitly for dounmount().
  */   */
 int  int
 dounmount(struct mount *mp, int flags, struct lwp *l)  dounmount(struct mount *mp, int flags, struct lwp *l)
Line 680  dounmount(struct mount *mp, int flags, s
Line 718  dounmount(struct mount *mp, int flags, s
         int async;          int async;
         int used_syncer;          int used_syncer;
   
         KASSERT(rw_write_held(&mp->mnt_lock));  
   
 #if NVERIEXEC > 0  #if NVERIEXEC > 0
         error = veriexec_unmountchk(mp);          error = veriexec_unmountchk(mp);
         if (error)          if (error)
                 return (error);                  return (error);
 #endif /* NVERIEXEC > 0 */  #endif /* NVERIEXEC > 0 */
   
           /*
            * XXX Freeze syncer.  Must do this before locking the
            * mount point.  See dounmount() for details.
            */
           mutex_enter(&syncer_mutex);
           rw_enter(&mp->mnt_unmounting, RW_WRITER);
           if ((mp->mnt_iflag & IMNT_GONE) != 0) {
                   rw_exit(&mp->mnt_unmounting);
                   mutex_exit(&syncer_mutex);
                   return ENOENT;
           }
   
         used_syncer = (mp->mnt_syncer != NULL);          used_syncer = (mp->mnt_syncer != NULL);
   
         /*          /*
          * XXX Syncer must be frozen when we get here.  This should really           * XXX Syncer must be frozen when we get here.  This should really
          * be done on a per-mountpoint basis, but especially the softdep           * be done on a per-mountpoint basis, but the syncer doesn't work
          * code possibly called from the syncer doesn't exactly work on a           * like that.
          * per-mountpoint basis, so the softdep code would become a maze  
          * of vfs_busy() calls.  
          *           *
          * The caller of dounmount() must acquire syncer_mutex because           * The caller of dounmount() must acquire syncer_mutex because
          * the syncer itself acquires locks in syncer_mutex -> vfs_busy           * the syncer itself acquires locks in syncer_mutex -> vfs_busy
Line 715  dounmount(struct mount *mp, int flags, s
Line 761  dounmount(struct mount *mp, int flags, s
                 vfs_deallocate_syncvnode(mp);                  vfs_deallocate_syncvnode(mp);
         error = 0;          error = 0;
         if ((mp->mnt_flag & MNT_RDONLY) == 0) {          if ((mp->mnt_flag & MNT_RDONLY) == 0) {
 #if NFSS > 0                  error = VFS_SYNC(mp, MNT_WAIT, l->l_cred);
                 error = fss_umount_hook(mp, (flags & MNT_FORCE));  
 #endif  
                 if (error == 0)  
                         error = VFS_SYNC(mp, MNT_WAIT, l->l_cred);  
         }          }
         vfs_scrubvnlist(mp);          vfs_scrubvnlist(mp);
         if (error == 0 || (flags & MNT_FORCE))          if (error == 0 || (flags & MNT_FORCE))
Line 729  dounmount(struct mount *mp, int flags, s
Line 771  dounmount(struct mount *mp, int flags, s
                         (void) vfs_allocate_syncvnode(mp);                          (void) vfs_allocate_syncvnode(mp);
                 mp->mnt_iflag &= ~IMNT_UNMOUNT;                  mp->mnt_iflag &= ~IMNT_UNMOUNT;
                 mp->mnt_flag |= async;                  mp->mnt_flag |= async;
                   rw_exit(&mp->mnt_unmounting);
                 if (used_syncer)                  if (used_syncer)
                         mutex_exit(&syncer_mutex);                          mutex_exit(&syncer_mutex);
                 vfs_unbusy(mp, false);  
                 return (error);                  return (error);
         }          }
         vfs_scrubvnlist(mp);          vfs_scrubvnlist(mp);
         mutex_enter(&mountlist_lock);          mutex_enter(&mountlist_lock);
         CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);  
         if ((coveredvp = mp->mnt_vnodecovered) != NULLVP)          if ((coveredvp = mp->mnt_vnodecovered) != NULLVP)
                 coveredvp->v_mountedhere = NULL;                  coveredvp->v_mountedhere = NULL;
           CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
           mp->mnt_iflag |= IMNT_GONE;
         mutex_exit(&mountlist_lock);          mutex_exit(&mountlist_lock);
         if (TAILQ_FIRST(&mp->mnt_vnodelist) != NULL)          if (TAILQ_FIRST(&mp->mnt_vnodelist) != NULL)
                 panic("unmount: dangling vnode");                  panic("unmount: dangling vnode");
         mp->mnt_iflag |= IMNT_GONE;  
         if (used_syncer)          if (used_syncer)
                 mutex_exit(&syncer_mutex);                  mutex_exit(&syncer_mutex);
         vfs_hooks_unmount(mp);          vfs_hooks_unmount(mp);
         vfs_unbusy(mp, false);          rw_exit(&mp->mnt_unmounting);
         vfs_destroy(mp);          vfs_destroy(mp);        /* reference from mount() */
         if (coveredvp != NULLVP)          if (coveredvp != NULLVP)
                 vrele(coveredvp);                  vrele(coveredvp);
         return (0);          return (0);
Line 772  sys_sync(struct lwp *l, const void *v, r
Line 814  sys_sync(struct lwp *l, const void *v, r
                 l = &lwp0;                  l = &lwp0;
   
         mutex_enter(&mountlist_lock);          mutex_enter(&mountlist_lock);
         for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) {          for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
                 if (vfs_trybusy(mp, RW_READER, &mountlist_lock)) {               mp = nmp) {
                         nmp = mp->mnt_list.cqe_prev;                  if (vfs_busy(mp, &nmp)) {
                         continue;                          continue;
                 }                  }
                   mutex_enter(&mp->mnt_updating);
                 if ((mp->mnt_flag & MNT_RDONLY) == 0) {                  if ((mp->mnt_flag & MNT_RDONLY) == 0) {
                         asyncflag = mp->mnt_flag & MNT_ASYNC;                          asyncflag = mp->mnt_flag & MNT_ASYNC;
                         mp->mnt_flag &= ~MNT_ASYNC;                          mp->mnt_flag &= ~MNT_ASYNC;
Line 784  sys_sync(struct lwp *l, const void *v, r
Line 827  sys_sync(struct lwp *l, const void *v, r
                         if (asyncflag)                          if (asyncflag)
                                  mp->mnt_flag |= MNT_ASYNC;                                   mp->mnt_flag |= MNT_ASYNC;
                 }                  }
                 mutex_enter(&mountlist_lock);                  mutex_exit(&mp->mnt_updating);
                 nmp = mp->mnt_list.cqe_prev;                  vfs_unbusy(mp, false, &nmp);
                 vfs_unbusy(mp, false);  
   
         }          }
         mutex_exit(&mountlist_lock);          mutex_exit(&mountlist_lock);
 #ifdef DEBUG  #ifdef DEBUG
Line 812  sys_quotactl(struct lwp *l, const struct
Line 853  sys_quotactl(struct lwp *l, const struct
         } */          } */
         struct mount *mp;          struct mount *mp;
         int error;          int error;
         struct nameidata nd;          struct vnode *vp;
   
         NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_FOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
         mp = nd.ni_vp->v_mount;          mp = vp->v_mount;
         error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),          error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
             SCARG(uap, arg));              SCARG(uap, arg));
         vrele(nd.ni_vp);          vrele(vp);
         return (error);          return (error);
 }  }
   
Line 855  done:
Line 896  done:
         if (cwdi->cwdi_rdir != NULL) {          if (cwdi->cwdi_rdir != NULL) {
                 size_t len;                  size_t len;
                 char *bp;                  char *bp;
                   char c;
                 char *path = PNBUF_GET();                  char *path = PNBUF_GET();
   
                 bp = path + MAXPATHLEN;                  bp = path + MAXPATHLEN;
Line 868  done:
Line 910  done:
                         return error;                          return error;
                 }                  }
                 len = strlen(bp);                  len = strlen(bp);
                 /*                  if (len != 1) {
                  * for mount points that are below our root, we can see                          /*
                  * them, so we fix up the pathname and return them. The                           * for mount points that are below our root, we can see
                  * rest we cannot see, so we don't allow viewing the                           * them, so we fix up the pathname and return them. The
                  * data.                           * rest we cannot see, so we don't allow viewing the
                  */                           * data.
                 if (strncmp(bp, sp->f_mntonname, len) == 0) {                           */
                         strlcpy(sp->f_mntonname, &sp->f_mntonname[len],                          if (strncmp(bp, sp->f_mntonname, len) == 0 &&
                             sizeof(sp->f_mntonname));                              ((c = sp->f_mntonname[len]) == '/' || c == '\0')) {
                         if (sp->f_mntonname[0] == '\0')                                  (void)strlcpy(sp->f_mntonname,
                                 (void)strlcpy(sp->f_mntonname, "/",                                      c == '\0' ? "/" : &sp->f_mntonname[len],
                                     sizeof(sp->f_mntonname));  
                 } else {  
                         if (root)  
                                 (void)strlcpy(sp->f_mntonname, "/",  
                                     sizeof(sp->f_mntonname));                                      sizeof(sp->f_mntonname));
                         else                          } else {
                                 error = EPERM;                                  if (root)
                                           (void)strlcpy(sp->f_mntonname, "/",
                                               sizeof(sp->f_mntonname));
                                   else
                                           error = EPERM;
                           }
                 }                  }
                 PNBUF_PUT(path);                  PNBUF_PUT(path);
         }          }
Line 901  do_sys_pstatvfs(struct lwp *l, const cha
Line 944  do_sys_pstatvfs(struct lwp *l, const cha
 {  {
         struct mount *mp;          struct mount *mp;
         int error;          int error;
         struct nameidata nd;          struct vnode *vp;
   
         NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, path);          error = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return error;                  return error;
         mp = nd.ni_vp->v_mount;          mp = vp->v_mount;
         error = dostatvfs(mp, sb, l, flags, 1);          error = dostatvfs(mp, sb, l, flags, 1);
         vrele(nd.ni_vp);          vrele(vp);
         return error;          return error;
 }  }
   
Line 993  do_sys_getvfsstat(struct lwp *l, void *s
Line 1036  do_sys_getvfsstat(struct lwp *l, void *s
         count = 0;          count = 0;
         for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;          for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
              mp = nmp) {               mp = nmp) {
                 if (vfs_trybusy(mp, RW_READER, &mountlist_lock)) {                  if (vfs_busy(mp, &nmp)) {
                         nmp = CIRCLEQ_NEXT(mp, mnt_list);  
                         continue;                          continue;
                 }                  }
                 if (sfsp && count < maxcount) {                  if (sfsp && count < maxcount) {
                         error = dostatvfs(mp, sb, l, flags, 0);                          error = dostatvfs(mp, sb, l, flags, 0);
                         if (error) {                          if (error) {
                                 mutex_enter(&mountlist_lock);                                  vfs_unbusy(mp, false, &nmp);
                                 nmp = CIRCLEQ_NEXT(mp, mnt_list);                                  error = 0;
                                 vfs_unbusy(mp, false);  
                                 continue;                                  continue;
                         }                          }
                         error = copyfn(sb, sfsp, entry_sz);                          error = copyfn(sb, sfsp, entry_sz);
                         if (error) {                          if (error) {
                                 vfs_unbusy(mp, false);                                  vfs_unbusy(mp, false, NULL);
                                 goto out;                                  goto out;
                         }                          }
                         sfsp = (char *)sfsp + entry_sz;                          sfsp = (char *)sfsp + entry_sz;
                         root |= strcmp(sb->f_mntonname, "/") == 0;                          root |= strcmp(sb->f_mntonname, "/") == 0;
                 }                  }
                 count++;                  count++;
                 mutex_enter(&mountlist_lock);                  vfs_unbusy(mp, false, &nmp);
                 nmp = CIRCLEQ_NEXT(mp, mnt_list);  
                 vfs_unbusy(mp, false);  
         }          }
   
         mutex_exit(&mountlist_lock);          mutex_exit(&mountlist_lock);
   
         if (root == 0 && p->p_cwdi->cwdi_rdir) {          if (root == 0 && p->p_cwdi->cwdi_rdir) {
                 /*                  /*
                  * fake a root entry                   * fake a root entry
Line 1028  do_sys_getvfsstat(struct lwp *l, void *s
Line 1067  do_sys_getvfsstat(struct lwp *l, void *s
                     sb, l, flags, 1);                      sb, l, flags, 1);
                 if (error != 0)                  if (error != 0)
                         goto out;                          goto out;
                 if (sfsp)                  if (sfsp) {
                         error = copyfn(sb, sfsp, entry_sz);                          error = copyfn(sb, sfsp, entry_sz);
                           if (error != 0)
                                   goto out;
                   }
                 count++;                  count++;
         }          }
         if (sfsp && count > maxcount)          if (sfsp && count > maxcount)
Line 1077  sys_fchdir(struct lwp *l, const struct s
Line 1119  sys_fchdir(struct lwp *l, const struct s
                 return (error);                  return (error);
         vp = fp->f_data;          vp = fp->f_data;
   
         VREF(vp);          vref(vp);
         vn_lock(vp,  LK_EXCLUSIVE | LK_RETRY);          vn_lock(vp,  LK_EXCLUSIVE | LK_RETRY);
         if (vp->v_type != VDIR)          if (vp->v_type != VDIR)
                 error = ENOTDIR;                  error = ENOTDIR;
Line 1088  sys_fchdir(struct lwp *l, const struct s
Line 1130  sys_fchdir(struct lwp *l, const struct s
                 goto out;                  goto out;
         }          }
         while ((mp = vp->v_mountedhere) != NULL) {          while ((mp = vp->v_mountedhere) != NULL) {
                 if (vfs_busy(mp, RW_READER, NULL))                  error = vfs_busy(mp, NULL);
                         continue;  
                 vput(vp);                  vput(vp);
                   if (error != 0)
                           goto out;
                 error = VFS_ROOT(mp, &tdp);                  error = VFS_ROOT(mp, &tdp);
                 vfs_unbusy(mp, false);                  vfs_unbusy(mp, false, NULL);
                 if (error)                  if (error)
                         goto out;                          goto out;
                 vp = tdp;                  vp = tdp;
         }          }
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp);
   
         /*          /*
          * Disallow changing to a directory not under the process's           * Disallow changing to a directory not under the process's
Line 1127  int
Line 1170  int
 sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval)  sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval)
 {  {
         struct proc *p = l->l_proc;          struct proc *p = l->l_proc;
         struct cwdinfo *cwdi;  
         struct vnode    *vp;          struct vnode    *vp;
         file_t  *fp;          file_t  *fp;
         int              error, fd = SCARG(uap, fd);          int              error, fd = SCARG(uap, fd);
Line 1136  sys_fchroot(struct lwp *l, const struct 
Line 1178  sys_fchroot(struct lwp *l, const struct 
             KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0)              KAUTH_REQ_SYSTEM_CHROOT_FCHROOT, NULL, NULL, NULL)) != 0)
                 return error;                  return error;
         /* fd_getvnode() will use the descriptor for us */          /* fd_getvnode() will use the descriptor for us */
         if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)          if ((error = fd_getvnode(fd, &fp)) != 0)
                 return error;                  return error;
         vp = fp->f_data;          vp = fp->f_data;
         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);          vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
Line 1144  sys_fchroot(struct lwp *l, const struct 
Line 1186  sys_fchroot(struct lwp *l, const struct 
                 error = ENOTDIR;                  error = ENOTDIR;
         else          else
                 error = VOP_ACCESS(vp, VEXEC, l->l_cred);                  error = VOP_ACCESS(vp, VEXEC, l->l_cred);
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp);
         if (error)          if (error)
                 goto out;                  goto out;
         VREF(vp);          vref(vp);
   
         /*  
          * Prevent escaping from chroot by putting the root under  
          * the working directory.  Silently chdir to / if we aren't  
          * already there.  
          */  
         cwdi = p->p_cwdi;  
         rw_enter(&cwdi->cwdi_lock, RW_WRITER);  
         if (!vn_isunder(cwdi->cwdi_cdir, vp, l)) {  
                 /*  
                  * XXX would be more failsafe to change directory to a  
                  * deadfs node here instead  
                  */  
                 vrele(cwdi->cwdi_cdir);  
                 VREF(vp);  
                 cwdi->cwdi_cdir = vp;  
         }  
   
         if (cwdi->cwdi_rdir != NULL)          change_root(p->p_cwdi, vp, l);
                 vrele(cwdi->cwdi_rdir);  
         cwdi->cwdi_rdir = vp;  
         rw_exit(&cwdi->cwdi_lock);  
   
  out:   out:
         fd_putfile(fd);          fd_putfile(fd);
Line 1189  sys_chdir(struct lwp *l, const struct sy
Line 1211  sys_chdir(struct lwp *l, const struct sy
         struct proc *p = l->l_proc;          struct proc *p = l->l_proc;
         struct cwdinfo *cwdi;          struct cwdinfo *cwdi;
         int error;          int error;
         struct nameidata nd;          struct vnode *vp;
   
         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,          if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
             SCARG(uap, path));                                    &vp, l)) != 0)
         if ((error = change_dir(&nd, l)) != 0)  
                 return (error);                  return (error);
         cwdi = p->p_cwdi;          cwdi = p->p_cwdi;
         rw_enter(&cwdi->cwdi_lock, RW_WRITER);          rw_enter(&cwdi->cwdi_lock, RW_WRITER);
         vrele(cwdi->cwdi_cdir);          vrele(cwdi->cwdi_cdir);
         cwdi->cwdi_cdir = nd.ni_vp;          cwdi->cwdi_cdir = vp;
         rw_exit(&cwdi->cwdi_lock);          rw_exit(&cwdi->cwdi_lock);
         return (0);          return (0);
 }  }
Line 1214  sys_chroot(struct lwp *l, const struct s
Line 1235  sys_chroot(struct lwp *l, const struct s
                 syscallarg(const char *) path;                  syscallarg(const char *) path;
         } */          } */
         struct proc *p = l->l_proc;          struct proc *p = l->l_proc;
         struct cwdinfo *cwdi;  
         struct vnode *vp;  
         int error;          int error;
         struct nameidata nd;          struct vnode *vp;
   
         if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,          if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
             KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0)              KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0)
                 return (error);                  return (error);
         NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, UIO_USERSPACE,          if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
             SCARG(uap, path));                                    &vp, l)) != 0)
         if ((error = change_dir(&nd, l)) != 0)  
                 return (error);                  return (error);
   
         cwdi = p->p_cwdi;          change_root(p->p_cwdi, vp, l);
   
           return (0);
   }
   
   /*
    * Common routine for chroot and fchroot.
    * NB: callers need to properly authorize the change root operation.
    */
   void
   change_root(struct cwdinfo *cwdi, struct vnode *vp, struct lwp *l)
   {
   
         rw_enter(&cwdi->cwdi_lock, RW_WRITER);          rw_enter(&cwdi->cwdi_lock, RW_WRITER);
         if (cwdi->cwdi_rdir != NULL)          if (cwdi->cwdi_rdir != NULL)
                 vrele(cwdi->cwdi_rdir);                  vrele(cwdi->cwdi_rdir);
         vp = nd.ni_vp;  
         cwdi->cwdi_rdir = vp;          cwdi->cwdi_rdir = vp;
   
         /*          /*
Line 1245  sys_chroot(struct lwp *l, const struct s
Line 1274  sys_chroot(struct lwp *l, const struct s
                  * deadfs node here instead                   * deadfs node here instead
                  */                   */
                 vrele(cwdi->cwdi_cdir);                  vrele(cwdi->cwdi_cdir);
                 VREF(vp);                  vref(vp);
                 cwdi->cwdi_cdir = vp;                  cwdi->cwdi_cdir = vp;
         }          }
         rw_exit(&cwdi->cwdi_lock);          rw_exit(&cwdi->cwdi_lock);
   
         return (0);  
 }  }
   
 /*  /*
  * Common routine for chroot and chdir.   * Common routine for chroot and chdir.
  */   */
 static int  int
 change_dir(struct nameidata *ndp, struct lwp *l)  chdir_lookup(const char *path, int where, struct vnode **vpp, struct lwp *l)
 {  {
         struct vnode *vp;          struct nameidata nd;
         int error;          int error;
   
         if ((error = namei(ndp)) != 0)          NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, where,
               path);
           if ((error = namei(&nd)) != 0)
                 return (error);                  return (error);
         vp = ndp->ni_vp;          *vpp = nd.ni_vp;
         if (vp->v_type != VDIR)          if ((*vpp)->v_type != VDIR)
                 error = ENOTDIR;                  error = ENOTDIR;
         else          else
                 error = VOP_ACCESS(vp, VEXEC, l->l_cred);                  error = VOP_ACCESS(*vpp, VEXEC, l->l_cred);
   
         if (error)          if (error)
                 vput(vp);                  vput(*vpp);
         else          else
                 VOP_UNLOCK(vp, 0);                  VOP_UNLOCK(*vpp);
         return (error);          return (error);
 }  }
   
Line 1339  sys_open(struct lwp *l, const struct sys
Line 1368  sys_open(struct lwp *l, const struct sys
                 type = F_FLOCK;                  type = F_FLOCK;
                 if ((flags & FNONBLOCK) == 0)                  if ((flags & FNONBLOCK) == 0)
                         type |= F_WAIT;                          type |= F_WAIT;
                 VOP_UNLOCK(vp, 0);                  VOP_UNLOCK(vp);
                 error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);                  error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
                 if (error) {                  if (error) {
                         (void) vn_close(vp, fp->f_flag, fp->f_cred);                          (void) vn_close(vp, fp->f_flag, fp->f_cred);
Line 1349  sys_open(struct lwp *l, const struct sys
Line 1378  sys_open(struct lwp *l, const struct sys
                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);                  vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                 atomic_or_uint(&fp->f_flag, FHASLOCK);                  atomic_or_uint(&fp->f_flag, FHASLOCK);
         }          }
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp);
         *retval = indx;          *retval = indx;
         fd_affix(p, fp, indx);          fd_affix(p, fp, indx);
         return (0);          return (0);
Line 1639  dofhopen(struct lwp *l, const void *ufhp
Line 1668  dofhopen(struct lwp *l, const void *ufhp
         if (error != 0)          if (error != 0)
                 goto bad;                  goto bad;
         if (flags & O_TRUNC) {          if (flags & O_TRUNC) {
                 VOP_UNLOCK(vp, 0);                      /* XXX */                  VOP_UNLOCK(vp);                 /* XXX */
                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);   /* XXX */                  vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);   /* XXX */
                 VATTR_NULL(&va);                  vattr_null(&va);
                 va.va_size = 0;                  va.va_size = 0;
                 error = VOP_SETATTR(vp, &va, cred);                  error = VOP_SETATTR(vp, &va, cred);
                 if (error)                  if (error)
Line 1672  dofhopen(struct lwp *l, const void *ufhp
Line 1701  dofhopen(struct lwp *l, const void *ufhp
                 type = F_FLOCK;                  type = F_FLOCK;
                 if ((flags & FNONBLOCK) == 0)                  if ((flags & FNONBLOCK) == 0)
                         type |= F_WAIT;                          type |= F_WAIT;
                 VOP_UNLOCK(vp, 0);                  VOP_UNLOCK(vp);
                 error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);                  error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
                 if (error) {                  if (error) {
                         (void) vn_close(vp, fp->f_flag, fp->f_cred);                          (void) vn_close(vp, fp->f_flag, fp->f_cred);
Line 1682  dofhopen(struct lwp *l, const void *ufhp
Line 1711  dofhopen(struct lwp *l, const void *ufhp
                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);                  vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                 atomic_or_uint(&fp->f_flag, FHASLOCK);                  atomic_or_uint(&fp->f_flag, FHASLOCK);
         }          }
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp);
         *retval = indx;          *retval = indx;
         fd_affix(p, fp, indx);          fd_affix(p, fp, indx);
         vfs_copyinfh_free(fh);          vfs_copyinfh_free(fh);
Line 1740  do_fhstat(struct lwp *l, const void *ufh
Line 1769  do_fhstat(struct lwp *l, const void *ufh
   
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys___fhstat40(struct lwp *l, const struct sys___fhstat40_args *uap, register_t *retval)  sys___fhstat50(struct lwp *l, const struct sys___fhstat50_args *uap, register_t *retval)
 {  {
         /* {          /* {
                 syscallarg(const void *) fhp;                  syscallarg(const void *) fhp;
Line 1813  sys___fhstatvfs140(struct lwp *l, const 
Line 1842  sys___fhstatvfs140(struct lwp *l, const 
  */   */
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys_mknod(struct lwp *l, const struct sys_mknod_args *uap, register_t *retval)  sys___mknod50(struct lwp *l, const struct sys___mknod50_args *uap,
       register_t *retval)
 {  {
         /* {          /* {
                 syscallarg(const char *) path;                  syscallarg(const char *) path;
                 syscallarg(int) mode;                  syscallarg(mode_t) mode;
                 syscallarg(int) dev;                  syscallarg(dev_t) dev;
         } */          } */
           return do_sys_mknod(l, SCARG(uap, path), SCARG(uap, mode),
               SCARG(uap, dev), retval, UIO_USERSPACE);
   }
   
   int
   do_sys_mknod(struct lwp *l, const char *pathname, mode_t mode, dev_t dev,
       register_t *retval, enum uio_seg seg)
   {
         struct proc *p = l->l_proc;          struct proc *p = l->l_proc;
         struct vnode *vp;          struct vnode *vp;
         struct vattr vattr;          struct vattr vattr;
Line 1827  sys_mknod(struct lwp *l, const struct sy
Line 1865  sys_mknod(struct lwp *l, const struct sy
         struct nameidata nd;          struct nameidata nd;
         char *path;          char *path;
         const char *cpath;          const char *cpath;
         enum uio_seg seg = UIO_USERSPACE;  
   
         if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MKNOD,          if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MKNOD,
             0, NULL, NULL, NULL)) != 0)              0, NULL, NULL, NULL)) != 0)
Line 1835  sys_mknod(struct lwp *l, const struct sy
Line 1872  sys_mknod(struct lwp *l, const struct sy
   
         optype = VOP_MKNOD_DESCOFFSET;          optype = VOP_MKNOD_DESCOFFSET;
   
         VERIEXEC_PATH_GET(SCARG(uap, path), seg, cpath, path);          VERIEXEC_PATH_GET(pathname, seg, cpath, path);
         NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, seg, cpath);          NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, seg, cpath);
   
         if ((error = namei(&nd)) != 0)          if ((error = namei(&nd)) != 0)
Line 1844  sys_mknod(struct lwp *l, const struct sy
Line 1881  sys_mknod(struct lwp *l, const struct sy
         if (vp != NULL)          if (vp != NULL)
                 error = EEXIST;                  error = EEXIST;
         else {          else {
                 VATTR_NULL(&vattr);                  vattr_null(&vattr);
                 /* We will read cwdi->cwdi_cmask unlocked. */                  /* We will read cwdi->cwdi_cmask unlocked. */
                 vattr.va_mode =                  vattr.va_mode = (mode & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
                     (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;                  vattr.va_rdev = dev;
                 vattr.va_rdev = SCARG(uap, dev);  
   
                 switch (SCARG(uap, mode) & S_IFMT) {                  switch (mode & S_IFMT) {
                 case S_IFMT:    /* used by badsect to flag bad sectors */                  case S_IFMT:    /* used by badsect to flag bad sectors */
                         vattr.va_type = VBAD;                          vattr.va_type = VBAD;
                         break;                          break;
Line 1943  sys_mkfifo(struct lwp *l, const struct s
Line 1979  sys_mkfifo(struct lwp *l, const struct s
                 vrele(nd.ni_vp);                  vrele(nd.ni_vp);
                 return (EEXIST);                  return (EEXIST);
         }          }
         VATTR_NULL(&vattr);          vattr_null(&vattr);
         vattr.va_type = VFIFO;          vattr.va_type = VFIFO;
         /* We will read cwdi->cwdi_cmask unlocked. */          /* We will read cwdi->cwdi_cmask unlocked. */
         vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;          vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
Line 1968  sys_link(struct lwp *l, const struct sys
Line 2004  sys_link(struct lwp *l, const struct sys
         struct nameidata nd;          struct nameidata nd;
         int error;          int error;
   
         NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_FOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
         vp = nd.ni_vp;  
         NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, UIO_USERSPACE,          NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, UIO_USERSPACE,
             SCARG(uap, link));              SCARG(uap, link));
         if ((error = namei(&nd)) != 0)          if ((error = namei(&nd)) != 0)
Line 1993  out:
Line 2028  out:
         return (error);          return (error);
 }  }
   
 /*  
  * Make a symbolic link.  
  */  
 /* ARGSUSED */  
 int  int
 sys_symlink(struct lwp *l, const struct sys_symlink_args *uap, register_t *retval)  do_sys_symlink(const char *patharg, const char *link, enum uio_seg seg)
 {  {
         /* {          struct proc *p = curproc;
                 syscallarg(const char *) path;  
                 syscallarg(const char *) link;  
         } */  
         struct proc *p = l->l_proc;  
         struct vattr vattr;          struct vattr vattr;
         char *path;          char *path;
         int error;          int error;
         struct nameidata nd;          struct nameidata nd;
   
         path = PNBUF_GET();          path = PNBUF_GET();
         error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);          if (seg == UIO_USERSPACE) {
         if (error)                  if ((error = copyinstr(patharg, path, MAXPATHLEN, NULL)) != 0)
                 goto out;                          goto out;
         NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, UIO_USERSPACE,          } else {
             SCARG(uap, link));                  KASSERT(strlen(patharg) < MAXPATHLEN);
                   strcpy(path, patharg);
           }
           NDINIT(&nd, CREATE, LOCKPARENT | TRYEMULROOT, seg, link);
         if ((error = namei(&nd)) != 0)          if ((error = namei(&nd)) != 0)
                 goto out;                  goto out;
         if (nd.ni_vp) {          if (nd.ni_vp) {
Line 2028  sys_symlink(struct lwp *l, const struct 
Line 2058  sys_symlink(struct lwp *l, const struct 
                 error = EEXIST;                  error = EEXIST;
                 goto out;                  goto out;
         }          }
         VATTR_NULL(&vattr);          vattr_null(&vattr);
         vattr.va_type = VLNK;          vattr.va_type = VLNK;
         /* We will read cwdi->cwdi_cmask unlocked. */          /* We will read cwdi->cwdi_cmask unlocked. */
         vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;          vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;
Line 2041  out:
Line 2071  out:
 }  }
   
 /*  /*
    * Make a symbolic link.
    */
   /* ARGSUSED */
   int
   sys_symlink(struct lwp *l, const struct sys_symlink_args *uap, register_t *retval)
   {
           /* {
                   syscallarg(const char *) path;
                   syscallarg(const char *) link;
           } */
   
           return do_sys_symlink(SCARG(uap, path), SCARG(uap, link),
               UIO_USERSPACE);
   }
   
   /*
  * Delete a whiteout from the filesystem.   * Delete a whiteout from the filesystem.
  */   */
 /* ARGSUSED */  /* ARGSUSED */
Line 2095  do_sys_unlink(const char *arg, enum uio_
Line 2141  do_sys_unlink(const char *arg, enum uio_
         struct vnode *vp;          struct vnode *vp;
         int error;          int error;
         struct nameidata nd;          struct nameidata nd;
         kauth_cred_t cred;  
         char *path;          char *path;
         const char *cpath;          const char *cpath;
   
Line 2133  do_sys_unlink(const char *arg, enum uio_
Line 2178  do_sys_unlink(const char *arg, enum uio_
         }          }
 #endif /* NVERIEXEC > 0 */  #endif /* NVERIEXEC > 0 */
   
         cred = kauth_cred_get();  
 #ifdef FILEASSOC  #ifdef FILEASSOC
         (void)fileassoc_file_delete(vp);          (void)fileassoc_file_delete(vp);
 #endif /* FILEASSOC */  #endif /* FILEASSOC */
Line 2178  sys_lseek(struct lwp *l, const struct sy
Line 2222  sys_lseek(struct lwp *l, const struct sy
                 newoff = fp->f_offset + SCARG(uap, offset);                  newoff = fp->f_offset + SCARG(uap, offset);
                 break;                  break;
         case SEEK_END:          case SEEK_END:
                   vn_lock(vp, LK_SHARED | LK_RETRY);
                 error = VOP_GETATTR(vp, &vattr, cred);                  error = VOP_GETATTR(vp, &vattr, cred);
                   VOP_UNLOCK(vp);
                 if (error) {                  if (error) {
                         goto out;                          goto out;
                 }                  }
Line 2403  do_sys_stat(const char *path, unsigned i
Line 2449  do_sys_stat(const char *path, unsigned i
  */   */
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys___stat30(struct lwp *l, const struct sys___stat30_args *uap, register_t *retval)  sys___stat50(struct lwp *l, const struct sys___stat50_args *uap, register_t *retval)
 {  {
         /* {          /* {
                 syscallarg(const char *) path;                  syscallarg(const char *) path;
Line 2423  sys___stat30(struct lwp *l, const struct
Line 2469  sys___stat30(struct lwp *l, const struct
  */   */
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys___lstat30(struct lwp *l, const struct sys___lstat30_args *uap, register_t *retval)  sys___lstat50(struct lwp *l, const struct sys___lstat50_args *uap, register_t *retval)
 {  {
         /* {          /* {
                 syscallarg(const char *) path;                  syscallarg(const char *) path;
Line 2517  sys_chflags(struct lwp *l, const struct 
Line 2563  sys_chflags(struct lwp *l, const struct 
         } */          } */
         struct vnode *vp;          struct vnode *vp;
         int error;          int error;
         struct nameidata nd;  
   
         NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_FOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
         vp = nd.ni_vp;  
         error = change_flags(vp, SCARG(uap, flags), l);          error = change_flags(vp, SCARG(uap, flags), l);
         vput(vp);          vput(vp);
         return (error);          return (error);
Line 2549  sys_fchflags(struct lwp *l, const struct
Line 2593  sys_fchflags(struct lwp *l, const struct
                 return (error);                  return (error);
         vp = fp->f_data;          vp = fp->f_data;
         error = change_flags(vp, SCARG(uap, flags), l);          error = change_flags(vp, SCARG(uap, flags), l);
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp);
         fd_putfile(SCARG(uap, fd));          fd_putfile(SCARG(uap, fd));
         return (error);          return (error);
 }  }
Line 2567  sys_lchflags(struct lwp *l, const struct
Line 2611  sys_lchflags(struct lwp *l, const struct
         } */          } */
         struct vnode *vp;          struct vnode *vp;
         int error;          int error;
         struct nameidata nd;  
   
         NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_NOFOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
         vp = nd.ni_vp;  
         error = change_flags(vp, SCARG(uap, flags), l);          error = change_flags(vp, SCARG(uap, flags), l);
         vput(vp);          vput(vp);
         return (error);          return (error);
Line 2601  change_flags(struct vnode *vp, u_long fl
Line 2643  change_flags(struct vnode *vp, u_long fl
                         goto out;                          goto out;
                 }                  }
         }          }
         VATTR_NULL(&vattr);          vattr_null(&vattr);
         vattr.va_flags = flags;          vattr.va_flags = flags;
         error = VOP_SETATTR(vp, &vattr, l->l_cred);          error = VOP_SETATTR(vp, &vattr, l->l_cred);
 out:  out:
Line 2620  sys_chmod(struct lwp *l, const struct sy
Line 2662  sys_chmod(struct lwp *l, const struct sy
                 syscallarg(int) mode;                  syscallarg(int) mode;
         } */          } */
         int error;          int error;
         struct nameidata nd;          struct vnode *vp;
   
         NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_FOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
   
         error = change_mode(nd.ni_vp, SCARG(uap, mode), l);          error = change_mode(vp, SCARG(uap, mode), l);
   
         vrele(nd.ni_vp);          vrele(vp);
         return (error);          return (error);
 }  }
   
Line 2667  sys_lchmod(struct lwp *l, const struct s
Line 2709  sys_lchmod(struct lwp *l, const struct s
                 syscallarg(int) mode;                  syscallarg(int) mode;
         } */          } */
         int error;          int error;
         struct nameidata nd;          struct vnode *vp;
   
         NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_NOFOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
   
         error = change_mode(nd.ni_vp, SCARG(uap, mode), l);          error = change_mode(vp, SCARG(uap, mode), l);
   
         vrele(nd.ni_vp);          vrele(vp);
         return (error);          return (error);
 }  }
   
Line 2690  change_mode(struct vnode *vp, int mode, 
Line 2732  change_mode(struct vnode *vp, int mode, 
         int error;          int error;
   
         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);          vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
         VATTR_NULL(&vattr);          vattr_null(&vattr);
         vattr.va_mode = mode & ALLPERMS;          vattr.va_mode = mode & ALLPERMS;
         error = VOP_SETATTR(vp, &vattr, l->l_cred);          error = VOP_SETATTR(vp, &vattr, l->l_cred);
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp);
         return (error);          return (error);
 }  }
   
Line 2710  sys_chown(struct lwp *l, const struct sy
Line 2752  sys_chown(struct lwp *l, const struct sy
                 syscallarg(gid_t) gid;                  syscallarg(gid_t) gid;
         } */          } */
         int error;          int error;
         struct nameidata nd;          struct vnode *vp;
   
         NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_FOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
   
         error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);          error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
   
         vrele(nd.ni_vp);          vrele(vp);
         return (error);          return (error);
 }  }
   
Line 2737  sys___posix_chown(struct lwp *l, const s
Line 2779  sys___posix_chown(struct lwp *l, const s
                 syscallarg(gid_t) gid;                  syscallarg(gid_t) gid;
         } */          } */
         int error;          int error;
         struct nameidata nd;          struct vnode *vp;
   
         NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_FOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
   
         error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);          error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
   
         vrele(nd.ni_vp);          vrele(vp);
         return (error);          return (error);
 }  }
   
Line 2811  sys_lchown(struct lwp *l, const struct s
Line 2853  sys_lchown(struct lwp *l, const struct s
                 syscallarg(gid_t) gid;                  syscallarg(gid_t) gid;
         } */          } */
         int error;          int error;
         struct nameidata nd;          struct vnode *vp;
   
         NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_NOFOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
   
         error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);          error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 0);
   
         vrele(nd.ni_vp);          vrele(vp);
         return (error);          return (error);
 }  }
   
Line 2838  sys___posix_lchown(struct lwp *l, const 
Line 2880  sys___posix_lchown(struct lwp *l, const 
                 syscallarg(gid_t) gid;                  syscallarg(gid_t) gid;
         } */          } */
         int error;          int error;
         struct nameidata nd;          struct vnode *vp;
   
         NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_NOFOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
   
         error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);          error = change_owner(vp, SCARG(uap, uid), SCARG(uap, gid), l, 1);
   
         vrele(nd.ni_vp);          vrele(vp);
         return (error);          return (error);
 }  }
   
Line 2893  change_owner(struct vnode *vp, uid_t uid
Line 2935  change_owner(struct vnode *vp, uid_t uid
         if (vattr.va_mode == newmode)          if (vattr.va_mode == newmode)
                 newmode = VNOVAL;                  newmode = VNOVAL;
   
         VATTR_NULL(&vattr);          vattr_null(&vattr);
         vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL;          vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL;
         vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL;          vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL;
         vattr.va_mode = newmode;          vattr.va_mode = newmode;
Line 2901  change_owner(struct vnode *vp, uid_t uid
Line 2943  change_owner(struct vnode *vp, uid_t uid
 #undef CHANGED  #undef CHANGED
   
 out:  out:
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp);
         return (error);          return (error);
 }  }
   
Line 2911  out:
Line 2953  out:
  */   */
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys_utimes(struct lwp *l, const struct sys_utimes_args *uap, register_t *retval)  sys___utimes50(struct lwp *l, const struct sys___utimes50_args *uap,
       register_t *retval)
 {  {
         /* {          /* {
                 syscallarg(const char *) path;                  syscallarg(const char *) path;
Line 2927  sys_utimes(struct lwp *l, const struct s
Line 2970  sys_utimes(struct lwp *l, const struct s
  */   */
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 sys_futimes(struct lwp *l, const struct sys_futimes_args *uap, register_t *retval)  sys___futimes50(struct lwp *l, const struct sys___futimes50_args *uap,
       register_t *retval)
 {  {
         /* {          /* {
                 syscallarg(int) fd;                  syscallarg(int) fd;
Line 2950  sys_futimes(struct lwp *l, const struct 
Line 2994  sys_futimes(struct lwp *l, const struct 
  * version does not follow links.   * version does not follow links.
  */   */
 int  int
 sys_lutimes(struct lwp *l, const struct sys_lutimes_args *uap, register_t *retval)  sys___lutimes50(struct lwp *l, const struct sys___lutimes50_args *uap,
       register_t *retval)
 {  {
         /* {          /* {
                 syscallarg(const char *) path;                  syscallarg(const char *) path;
Line 2969  do_sys_utimes(struct lwp *l, struct vnod
Line 3014  do_sys_utimes(struct lwp *l, struct vnod
     const struct timeval *tptr, enum uio_seg seg)      const struct timeval *tptr, enum uio_seg seg)
 {  {
         struct vattr vattr;          struct vattr vattr;
         struct nameidata nd;          int error, dorele = 0;
         int error;          namei_simple_flags_t sflags;
   
           bool vanull, setbirthtime;
           struct timespec ts[2];
   
           /*
            * I have checked all callers and they pass either FOLLOW,
            * NOFOLLOW, or 0 (when they don't pass a path), and NOFOLLOW
            * is 0. More to the point, they don't pass anything else.
            * Let's keep it that way at least until the namei interfaces
            * are fully sanitized.
            */
           KASSERT(flag == NOFOLLOW || flag == FOLLOW);
           sflags = (flag == FOLLOW) ?
                   NSM_FOLLOW_TRYEMULROOT : NSM_NOFOLLOW_TRYEMULROOT;
   
         VATTR_NULL(&vattr);  
         if (tptr == NULL) {          if (tptr == NULL) {
                 nanotime(&vattr.va_atime);                  vanull = true;
                 vattr.va_mtime = vattr.va_atime;                  nanotime(&ts[0]);
                 vattr.va_vaflags |= VA_UTIMES_NULL;                  ts[1] = ts[0];
         } else {          } else {
                 struct timeval tv[2];                  struct timeval tv[2];
   
                   vanull = false;
                 if (seg != UIO_SYSSPACE) {                  if (seg != UIO_SYSSPACE) {
                         error = copyin(tptr, &tv, sizeof (tv));                          error = copyin(tptr, tv, sizeof (tv));
                         if (error != 0)                          if (error != 0)
                                 return error;                                  return error;
                         tptr = tv;                          tptr = tv;
                 }                  }
                 TIMEVAL_TO_TIMESPEC(tptr, &vattr.va_atime);                  TIMEVAL_TO_TIMESPEC(&tptr[0], &ts[0]);
                 TIMEVAL_TO_TIMESPEC(tptr + 1, &vattr.va_mtime);                  TIMEVAL_TO_TIMESPEC(&tptr[1], &ts[1]);
         }          }
   
         if (vp == NULL) {          if (vp == NULL) {
                 NDINIT(&nd, LOOKUP, flag | TRYEMULROOT, UIO_USERSPACE, path);                  /* note: SEG describes TPTR, not PATH; PATH is always user */
                 if ((error = namei(&nd)) != 0)                  error = namei_simple_user(path, sflags, &vp);
                         return (error);                  if (error != 0)
                 vp = nd.ni_vp;                          return error;
         } else                  dorele = 1;
                 nd.ni_vp = NULL;          }
   
         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);          vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
           setbirthtime = (VOP_GETATTR(vp, &vattr, l->l_cred) == 0 &&
               timespeccmp(&ts[1], &vattr.va_birthtime, <));
           vattr_null(&vattr);
           vattr.va_atime = ts[0];
           vattr.va_mtime = ts[1];
           if (setbirthtime)
                   vattr.va_birthtime = ts[1];
           if (vanull)
                   vattr.va_vaflags |= VA_UTIMES_NULL;
         error = VOP_SETATTR(vp, &vattr, l->l_cred);          error = VOP_SETATTR(vp, &vattr, l->l_cred);
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp);
   
         if (nd.ni_vp != NULL)          if (dorele != 0)
                 vrele(nd.ni_vp);                  vrele(vp);
   
         return (error);          return error;
 }  }
   
 /*  /*
Line 3023  sys_truncate(struct lwp *l, const struct
Line 3091  sys_truncate(struct lwp *l, const struct
         struct vnode *vp;          struct vnode *vp;
         struct vattr vattr;          struct vattr vattr;
         int error;          int error;
         struct nameidata nd;  
   
         NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_FOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
         vp = nd.ni_vp;  
         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);          vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
         if (vp->v_type == VDIR)          if (vp->v_type == VDIR)
                 error = EISDIR;                  error = EISDIR;
         else if ((error = vn_writechk(vp)) == 0 &&          else if ((error = vn_writechk(vp)) == 0 &&
             (error = VOP_ACCESS(vp, VWRITE, l->l_cred)) == 0) {              (error = VOP_ACCESS(vp, VWRITE, l->l_cred)) == 0) {
                 VATTR_NULL(&vattr);                  vattr_null(&vattr);
                 vattr.va_size = SCARG(uap, length);                  vattr.va_size = SCARG(uap, length);
                 error = VOP_SETATTR(vp, &vattr, l->l_cred);                  error = VOP_SETATTR(vp, &vattr, l->l_cred);
         }          }
Line 3072  sys_ftruncate(struct lwp *l, const struc
Line 3138  sys_ftruncate(struct lwp *l, const struc
         if (vp->v_type == VDIR)          if (vp->v_type == VDIR)
                 error = EISDIR;                  error = EISDIR;
         else if ((error = vn_writechk(vp)) == 0) {          else if ((error = vn_writechk(vp)) == 0) {
                 VATTR_NULL(&vattr);                  vattr_null(&vattr);
                 vattr.va_size = SCARG(uap, length);                  vattr.va_size = SCARG(uap, length);
                 error = VOP_SETATTR(vp, &vattr, fp->f_cred);                  error = VOP_SETATTR(vp, &vattr, fp->f_cred);
         }          }
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp);
  out:   out:
         fd_putfile(SCARG(uap, fd));          fd_putfile(SCARG(uap, fd));
         return (error);          return (error);
Line 3102  sys_fsync(struct lwp *l, const struct sy
Line 3168  sys_fsync(struct lwp *l, const struct sy
         vp = fp->f_data;          vp = fp->f_data;
         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);          vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
         error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0);          error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0);
         if (error == 0 && bioopsp != NULL &&          VOP_UNLOCK(vp);
             vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))  
                 (*bioopsp->io_fsync)(vp, 0);  
         VOP_UNLOCK(vp, 0);  
         fd_putfile(SCARG(uap, fd));          fd_putfile(SCARG(uap, fd));
         return (error);          return (error);
 }  }
Line 3173  sys_fsync_range(struct lwp *l, const str
Line 3236  sys_fsync_range(struct lwp *l, const str
         vp = fp->f_data;          vp = fp->f_data;
         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);          vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
         error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e);          error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e);
           VOP_UNLOCK(vp);
         if (error == 0 && bioopsp != NULL &&  
             vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))  
                 (*bioopsp->io_fsync)(vp, nflags);  
   
         VOP_UNLOCK(vp, 0);  
 out:  out:
         fd_putfile(SCARG(uap, fd));          fd_putfile(SCARG(uap, fd));
         return (error);          return (error);
Line 3208  sys_fdatasync(struct lwp *l, const struc
Line 3266  sys_fdatasync(struct lwp *l, const struc
         vp = fp->f_data;          vp = fp->f_data;
         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);          vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
         error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0);          error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0);
         VOP_UNLOCK(vp, 0);          VOP_UNLOCK(vp);
         fd_putfile(SCARG(uap, fd));          fd_putfile(SCARG(uap, fd));
         return (error);          return (error);
 }  }
Line 3264  do_sys_rename(const char *from, const ch
Line 3322  do_sys_rename(const char *from, const ch
         uint32_t saveflag;          uint32_t saveflag;
         int error;          int error;
   
         NDINIT(&fromnd, DELETE, LOCKPARENT | SAVESTART | TRYEMULROOT,          NDINIT(&fromnd, DELETE, LOCKPARENT | SAVESTART | TRYEMULROOT | INRENAME,
             seg, from);              seg, from);
         if ((error = namei(&fromnd)) != 0)          if ((error = namei(&fromnd)) != 0)
                 return (error);                  return (error);
         if (fromnd.ni_dvp != fromnd.ni_vp)          if (fromnd.ni_dvp != fromnd.ni_vp)
                 VOP_UNLOCK(fromnd.ni_dvp, 0);                  VOP_UNLOCK(fromnd.ni_dvp);
         fvp = fromnd.ni_vp;          fvp = fromnd.ni_vp;
   
         fs = fvp->v_mount;          fs = fvp->v_mount;
Line 3316  do_sys_rename(const char *from, const ch
Line 3374  do_sys_rename(const char *from, const ch
         error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd);          error = relookup(fromnd.ni_dvp, &fromnd.ni_vp, &fromnd.ni_cnd);
         fromnd.ni_cnd.cn_flags |= saveflag;          fromnd.ni_cnd.cn_flags |= saveflag;
         if (error) {          if (error) {
                 VOP_UNLOCK(fromnd.ni_dvp, 0);                  VOP_UNLOCK(fromnd.ni_dvp);
                 VFS_RENAMELOCK_EXIT(fs);                  VFS_RENAMELOCK_EXIT(fs);
                 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);                  VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
                 vrele(fromnd.ni_dvp);                  vrele(fromnd.ni_dvp);
                 goto out1;                  goto out1;
         }          }
         VOP_UNLOCK(fromnd.ni_vp, 0);          VOP_UNLOCK(fromnd.ni_vp);
         if (fromnd.ni_dvp != fromnd.ni_vp)          if (fromnd.ni_dvp != fromnd.ni_vp)
                 VOP_UNLOCK(fromnd.ni_dvp, 0);                  VOP_UNLOCK(fromnd.ni_dvp);
         fvp = fromnd.ni_vp;          fvp = fromnd.ni_vp;
   
         NDINIT(&tond, RENAME,          NDINIT(&tond, RENAME,
             LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | TRYEMULROOT              LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | TRYEMULROOT
               | (fvp->v_type == VDIR ? CREATEDIR : 0),                | INRENAME | (fvp->v_type == VDIR ? CREATEDIR : 0),
             seg, to);              seg, to);
         if ((error = namei(&tond)) != 0) {          if ((error = namei(&tond)) != 0) {
                 VFS_RENAMELOCK_EXIT(fs);                  VFS_RENAMELOCK_EXIT(fs);
Line 3371  do_sys_rename(const char *from, const ch
Line 3429  do_sys_rename(const char *from, const ch
 #if NVERIEXEC > 0  #if NVERIEXEC > 0
         if (!error) {          if (!error) {
                 char *f1, *f2;                  char *f1, *f2;
                   size_t f1_len;
                   size_t f2_len;
   
                 f1 = malloc(fromnd.ni_cnd.cn_namelen + 1, M_TEMP, M_WAITOK);                  f1_len = fromnd.ni_cnd.cn_namelen + 1;
                 strlcpy(f1, fromnd.ni_cnd.cn_nameptr, fromnd.ni_cnd.cn_namelen);                  f1 = kmem_alloc(f1_len, KM_SLEEP);
                   strlcpy(f1, fromnd.ni_cnd.cn_nameptr, f1_len);
                 f2 = malloc(tond.ni_cnd.cn_namelen + 1, M_TEMP, M_WAITOK);  
                 strlcpy(f2, tond.ni_cnd.cn_nameptr, tond.ni_cnd.cn_namelen);                  f2_len = tond.ni_cnd.cn_namelen + 1;
                   f2 = kmem_alloc(f2_len, KM_SLEEP);
                   strlcpy(f2, tond.ni_cnd.cn_nameptr, f2_len);
   
                 error = veriexec_renamechk(l, fvp, f1, tvp, f2);                  error = veriexec_renamechk(l, fvp, f1, tvp, f2);
   
                 free(f1, M_TEMP);                  kmem_free(f1, f1_len);
                 free(f2, M_TEMP);                  kmem_free(f2, f2_len);
         }          }
 #endif /* NVERIEXEC > 0 */  #endif /* NVERIEXEC > 0 */
   
Line 3424  sys_mkdir(struct lwp *l, const struct sy
Line 3486  sys_mkdir(struct lwp *l, const struct sy
                 syscallarg(const char *) path;                  syscallarg(const char *) path;
                 syscallarg(int) mode;                  syscallarg(int) mode;
         } */          } */
         struct proc *p = l->l_proc;  
           return do_sys_mkdir(SCARG(uap, path), SCARG(uap, mode), UIO_USERSPACE);
   }
   
   int
   do_sys_mkdir(const char *path, mode_t mode, enum uio_seg seg)
   {
           struct proc *p = curlwp->l_proc;
         struct vnode *vp;          struct vnode *vp;
         struct vattr vattr;          struct vattr vattr;
         int error;          int error;
         struct nameidata nd;          struct nameidata nd;
   
         NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR | TRYEMULROOT, UIO_USERSPACE,          NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR | TRYEMULROOT,
             SCARG(uap, path));              seg, path);
         if ((error = namei(&nd)) != 0)          if ((error = namei(&nd)) != 0)
                 return (error);                  return (error);
         vp = nd.ni_vp;          vp = nd.ni_vp;
Line 3444  sys_mkdir(struct lwp *l, const struct sy
Line 3513  sys_mkdir(struct lwp *l, const struct sy
                 vrele(vp);                  vrele(vp);
                 return (EEXIST);                  return (EEXIST);
         }          }
         VATTR_NULL(&vattr);          vattr_null(&vattr);
         vattr.va_type = VDIR;          vattr.va_type = VDIR;
         /* We will read cwdi->cwdi_cmask unlocked. */          /* We will read cwdi->cwdi_cmask unlocked. */
         vattr.va_mode =          vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
             (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;  
         error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);          error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
         if (!error)          if (!error)
                 vput(nd.ni_vp);                  vput(nd.ni_vp);
Line 3569  dorevoke(struct vnode *vp, kauth_cred_t 
Line 3637  dorevoke(struct vnode *vp, kauth_cred_t 
         struct vattr vattr;          struct vattr vattr;
         int error;          int error;
   
         if ((error = VOP_GETATTR(vp, &vattr, cred)) != 0)          vn_lock(vp, LK_SHARED | LK_RETRY);
           error = VOP_GETATTR(vp, &vattr, cred);
           VOP_UNLOCK(vp);
           if (error != 0)
                 return error;                  return error;
         if (kauth_cred_geteuid(cred) != vattr.va_uid &&          if (kauth_cred_geteuid(cred) == vattr.va_uid ||
             (error = kauth_authorize_generic(cred,              (error = kauth_authorize_generic(cred,
             KAUTH_GENERIC_ISSUSER, NULL)) == 0)              KAUTH_GENERIC_ISSUSER, NULL)) == 0)
                 VOP_REVOKE(vp, REVOKEALL);                  VOP_REVOKE(vp, REVOKEALL);
Line 3591  sys_revoke(struct lwp *l, const struct s
Line 3662  sys_revoke(struct lwp *l, const struct s
         } */          } */
         struct vnode *vp;          struct vnode *vp;
         int error;          int error;
         struct nameidata nd;  
   
         NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE,          error = namei_simple_user(SCARG(uap, path),
             SCARG(uap, path));                                  NSM_FOLLOW_TRYEMULROOT, &vp);
         if ((error = namei(&nd)) != 0)          if (error != 0)
                 return (error);                  return (error);
         vp = nd.ni_vp;  
         error = dorevoke(vp, l->l_cred);          error = dorevoke(vp, l->l_cred);
         vrele(vp);          vrele(vp);
         return (error);          return (error);
 }  }
   
 /*  
  * Convert a user file descriptor to a kernel file entry.  
  */  
 int  
 getvnode(int fd, file_t **fpp)  
 {  
         struct vnode *vp;  
         file_t *fp;  
   
         if ((fp = fd_getfile(fd)) == NULL)  
                 return (EBADF);  
   
         if (fp->f_type != DTYPE_VNODE) {  
                 fd_putfile(fd);  
                 return (EINVAL);  
         }  
   
         vp = fp->f_data;  
         if (vp->v_type == VBAD) {  
                 fd_putfile(fd);  
                 return (EBADF);  
         }  
   
         *fpp = fp;  
         return (0);  
 }  

Legend:
Removed from v.1.350  
changed lines
  Added in v.1.350.2.9

CVSweb <webmaster@jp.NetBSD.org>