update syscalls.master
[unix-history] / usr / src / sys / kern / vfs_syscalls.c
index 22d858c..015cede 100644 (file)
@@ -4,23 +4,25 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)vfs_syscalls.c      7.99 (Berkeley) %G%
+ *     @(#)vfs_syscalls.c      7.108 (Berkeley) %G%
  */
 
  */
 
-#include "param.h"
-#include "systm.h"
-#include "namei.h"
-#include "filedesc.h"
-#include "kernel.h"
-#include "file.h"
-#include "stat.h"
-#include "vnode.h"
-#include "mount.h"
-#include "proc.h"
-#include "uio.h"
-#include "malloc.h"
-#include "dirent.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/filedesc.h>
+#include <sys/kernel.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/proc.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+
 #include <vm/vm.h>
 #include <vm/vm.h>
+#include <sys/sysctl.h>
 
 #ifdef REF_DIAGNOSTIC
 #define CURCOUNT (curproc ? curproc->p_spare[0] : 0)
 
 #ifdef REF_DIAGNOSTIC
 #define CURCOUNT (curproc ? curproc->p_spare[0] : 0)
@@ -74,17 +76,18 @@ mount(p, uap, retval)
                        return (EINVAL);
                }
                mp = vp->v_mount;
                        return (EINVAL);
                }
                mp = vp->v_mount;
+               flag = mp->mnt_flag;
                /*
                /*
-                * We allow going from read-only to read-write,
-                * but not from read-write to read-only.
+                * We only allow the filesystem to be reloaded if it
+                * is currently mounted read-only.
                 */
                 */
-               if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
-                   (uap->flags & MNT_RDONLY) != 0) {
+               if ((uap->flags & MNT_RELOAD) &&
+                   ((mp->mnt_flag & MNT_RDONLY) == 0)) {
                        vput(vp);
                        return (EOPNOTSUPP);    /* Needs translation */
                }
                        vput(vp);
                        return (EOPNOTSUPP);    /* Needs translation */
                }
-               flag = mp->mnt_flag;
-               mp->mnt_flag |= MNT_UPDATE;
+               mp->mnt_flag |=
+                   uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
                VOP_UNLOCK(vp);
                goto update;
        }
                VOP_UNLOCK(vp);
                goto update;
        }
@@ -92,7 +95,7 @@ mount(p, uap, retval)
                vput(vp);
                return (EBUSY);
        }
                vput(vp);
                return (EBUSY);
        }
-       if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p))
+       if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
                return (error);
        if (vp->v_type != VDIR) {
                vput(vp);
                return (error);
        if (vp->v_type != VDIR) {
                vput(vp);
@@ -130,35 +133,22 @@ update:
         */
        if (uap->flags & MNT_RDONLY)
                mp->mnt_flag |= MNT_RDONLY;
         */
        if (uap->flags & MNT_RDONLY)
                mp->mnt_flag |= MNT_RDONLY;
-       else
-               mp->mnt_flag &= ~MNT_RDONLY;
-       if (uap->flags & MNT_NOSUID)
-               mp->mnt_flag |= MNT_NOSUID;
-       else
-               mp->mnt_flag &= ~MNT_NOSUID;
-       if (uap->flags & MNT_NOEXEC)
-               mp->mnt_flag |= MNT_NOEXEC;
-       else
-               mp->mnt_flag &= ~MNT_NOEXEC;
-       if (uap->flags & MNT_NODEV)
-               mp->mnt_flag |= MNT_NODEV;
-       else
-               mp->mnt_flag &= ~MNT_NODEV;
-       if (uap->flags & MNT_SYNCHRONOUS)
-               mp->mnt_flag |= MNT_SYNCHRONOUS;
-       else
-               mp->mnt_flag &= ~MNT_SYNCHRONOUS;
-       if (uap->flags & MNT_UNION)
-               mp->mnt_flag |= MNT_UNION;
-       else
-               mp->mnt_flag &= ~MNT_UNION;
+       else if (mp->mnt_flag & MNT_RDONLY)
+               mp->mnt_flag |= MNT_WANTRDWR;
+       mp->mnt_flag &=~
+           (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION);
+       mp->mnt_flag |= uap->flags &
+           (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION);
        /*
         * Mount the filesystem.
         */
        error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p);
        if (mp->mnt_flag & MNT_UPDATE) {
        /*
         * Mount the filesystem.
         */
        error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p);
        if (mp->mnt_flag & MNT_UPDATE) {
-               mp->mnt_flag &= ~MNT_UPDATE;
                vrele(vp);
                vrele(vp);
+               if (mp->mnt_flag & MNT_WANTRDWR)
+                       mp->mnt_flag &= ~MNT_RDONLY;
+               mp->mnt_flag &=~
+                   (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
                if (error)
                        mp->mnt_flag = flag;
                return (error);
                if (error)
                        mp->mnt_flag = flag;
                return (error);
@@ -269,6 +259,7 @@ dounmount(mp, flags, p)
  */
 #ifdef DIAGNOSTIC
 int syncprt = 0;
  */
 #ifdef DIAGNOSTIC
 int syncprt = 0;
+struct ctldebug debug0 = { "syncprt", &syncprt };
 #endif
 
 struct sync_args {
 #endif
 
 struct sync_args {
@@ -871,10 +862,12 @@ unlink(p, uap, retval)
        struct nameidata nd;
 
        CHECKPOINTREF;
        struct nameidata nd;
 
        CHECKPOINTREF;
-       NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
+       NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
+       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
+       VOP_LOCK(vp);
        if (vp->v_type == VDIR &&
            (error = suser(p->p_ucred, &p->p_acflag)))
                goto out;
        if (vp->v_type == VDIR &&
            (error = suser(p->p_ucred, &p->p_acflag)))
                goto out;
@@ -889,7 +882,6 @@ unlink(p, uap, retval)
 out:
        if (!error) {
                LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
 out:
        if (!error) {
                LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
-               LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
                error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
        } else {
                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
                error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
        } else {
                VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
@@ -1162,17 +1154,47 @@ lstat(p, uap, retval)
        register struct lstat_args *uap;
        int *retval;
 {
        register struct lstat_args *uap;
        int *retval;
 {
-       struct stat sb;
        int error;
        int error;
+       struct vnode *vp, *dvp;
+       struct stat sb, sb1;
        struct nameidata nd;
 
        struct nameidata nd;
 
-       NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
+       NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
+           uap->fname, p);
        if (error = namei(&nd))
                return (error);
        if (error = namei(&nd))
                return (error);
-       error = vn_stat(nd.ni_vp, &sb, p);
-       vput(nd.ni_vp);
-       if (error)
-               return (error);
+       /*
+        * For symbolic links, always return the attributes of its
+        * containing directory, except for mode, size, and links.
+        */
+       vp = nd.ni_vp;
+       dvp = nd.ni_dvp;
+       if (vp->v_type != VLNK) {
+               if (dvp == vp)
+                       vrele(dvp);
+               else
+                       vput(dvp);
+               error = vn_stat(vp, &sb, p);
+               vput(vp);
+               if (error)
+                       return (error);
+       } else {
+               error = vn_stat(dvp, &sb, p);
+               vput(dvp);
+               if (error) {
+                       vput(vp);
+                       return (error);
+               }
+               error = vn_stat(vp, &sb1, p);
+               vput(vp);
+               if (error)
+                       return (error);
+               sb.st_mode &= ~S_IFDIR;
+               sb.st_mode |= S_IFLNK;
+               sb.st_nlink = sb1.st_nlink;
+               sb.st_size = sb1.st_size;
+               sb.st_blocks = sb1.st_blocks;
+       }
        error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
        return (error);
 }
        error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
        return (error);
 }
@@ -1241,17 +1263,18 @@ chflags(p, uap, retval)
        int error;
        struct nameidata nd;
 
        int error;
        struct nameidata nd;
 
-       NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
+       NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
+       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
+       VOP_LOCK(vp);
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
                goto out;
        }
        VATTR_NULL(&vattr);
        vattr.va_flags = uap->flags;
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
                goto out;
        }
        VATTR_NULL(&vattr);
        vattr.va_flags = uap->flags;
-       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        vput(vp);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        vput(vp);
@@ -1279,6 +1302,7 @@ fchflags(p, uap, retval)
        if (error = getvnode(p->p_fd, uap->fd, &fp))
                return (error);
        vp = (struct vnode *)fp->f_data;
        if (error = getvnode(p->p_fd, uap->fd, &fp))
                return (error);
        vp = (struct vnode *)fp->f_data;
+       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        VOP_LOCK(vp);
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
        VOP_LOCK(vp);
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
@@ -1286,7 +1310,6 @@ fchflags(p, uap, retval)
        }
        VATTR_NULL(&vattr);
        vattr.va_flags = uap->flags;
        }
        VATTR_NULL(&vattr);
        vattr.va_flags = uap->flags;
-       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        VOP_UNLOCK(vp);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        VOP_UNLOCK(vp);
@@ -1311,17 +1334,18 @@ chmod(p, uap, retval)
        int error;
        struct nameidata nd;
 
        int error;
        struct nameidata nd;
 
-       NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
+       NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
+       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
+       VOP_LOCK(vp);
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
                goto out;
        }
        VATTR_NULL(&vattr);
        vattr.va_mode = uap->fmode & 07777;
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
                goto out;
        }
        VATTR_NULL(&vattr);
        vattr.va_mode = uap->fmode & 07777;
-       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        vput(vp);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        vput(vp);
@@ -1349,6 +1373,7 @@ fchmod(p, uap, retval)
        if (error = getvnode(p->p_fd, uap->fd, &fp))
                return (error);
        vp = (struct vnode *)fp->f_data;
        if (error = getvnode(p->p_fd, uap->fd, &fp))
                return (error);
        vp = (struct vnode *)fp->f_data;
+       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        VOP_LOCK(vp);
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
        VOP_LOCK(vp);
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
@@ -1356,7 +1381,6 @@ fchmod(p, uap, retval)
        }
        VATTR_NULL(&vattr);
        vattr.va_mode = uap->fmode & 07777;
        }
        VATTR_NULL(&vattr);
        vattr.va_mode = uap->fmode & 07777;
-       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        VOP_UNLOCK(vp);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        VOP_UNLOCK(vp);
@@ -1382,10 +1406,12 @@ chown(p, uap, retval)
        int error;
        struct nameidata nd;
 
        int error;
        struct nameidata nd;
 
-       NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
+       NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, p);
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
+       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
+       VOP_LOCK(vp);
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
                goto out;
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
                goto out;
@@ -1393,7 +1419,6 @@ chown(p, uap, retval)
        VATTR_NULL(&vattr);
        vattr.va_uid = uap->uid;
        vattr.va_gid = uap->gid;
        VATTR_NULL(&vattr);
        vattr.va_uid = uap->uid;
        vattr.va_gid = uap->gid;
-       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        vput(vp);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        vput(vp);
@@ -1422,6 +1447,7 @@ fchown(p, uap, retval)
        if (error = getvnode(p->p_fd, uap->fd, &fp))
                return (error);
        vp = (struct vnode *)fp->f_data;
        if (error = getvnode(p->p_fd, uap->fd, &fp))
                return (error);
        vp = (struct vnode *)fp->f_data;
+       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        VOP_LOCK(vp);
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
        VOP_LOCK(vp);
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
@@ -1430,7 +1456,6 @@ fchown(p, uap, retval)
        VATTR_NULL(&vattr);
        vattr.va_uid = uap->uid;
        vattr.va_gid = uap->gid;
        VATTR_NULL(&vattr);
        vattr.va_uid = uap->uid;
        vattr.va_gid = uap->gid;
-       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        VOP_UNLOCK(vp);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        VOP_UNLOCK(vp);
@@ -1456,22 +1481,27 @@ utimes(p, uap, retval)
        int error;
        struct nameidata nd;
 
        int error;
        struct nameidata nd;
 
-       if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
-               return (error);
-       NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
+       VATTR_NULL(&vattr);
+       if (uap->tptr == NULL) {
+               microtime(&tv[0]);
+               tv[1] = tv[0];
+               vattr.va_vaflags |= VA_UTIMES_NULL;
+       } else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
+               return (error);
+       NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
+       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
+       VOP_LOCK(vp);
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
                goto out;
        }
        if (vp->v_mount->mnt_flag & MNT_RDONLY) {
                error = EROFS;
                goto out;
        }
-       VATTR_NULL(&vattr);
        vattr.va_atime.ts_sec = tv[0].tv_sec;
        vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
        vattr.va_mtime.ts_sec = tv[1].tv_sec;
        vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
        vattr.va_atime.ts_sec = tv[0].tv_sec;
        vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
        vattr.va_mtime.ts_sec = tv[1].tv_sec;
        vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
-       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        vput(vp);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        vput(vp);
@@ -1498,10 +1528,12 @@ __truncate(p, uap, retval)
        int error;
        struct nameidata nd;
 
        int error;
        struct nameidata nd;
 
-       NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
+       NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
        if (error = namei(&nd))
                return (error);
        vp = nd.ni_vp;
+       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
+       VOP_LOCK(vp);
        if (vp->v_type == VDIR) {
                error = EISDIR;
                goto out;
        if (vp->v_type == VDIR) {
                error = EISDIR;
                goto out;
@@ -1511,7 +1543,6 @@ __truncate(p, uap, retval)
                goto out;
        VATTR_NULL(&vattr);
        vattr.va_size = uap->length;
                goto out;
        VATTR_NULL(&vattr);
        vattr.va_size = uap->length;
-       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        vput(vp);
        error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
 out:
        vput(vp);
@@ -1543,6 +1574,7 @@ __ftruncate(p, uap, retval)
        if ((fp->f_flag & FWRITE) == 0)
                return (EINVAL);
        vp = (struct vnode *)fp->f_data;
        if ((fp->f_flag & FWRITE) == 0)
                return (EINVAL);
        vp = (struct vnode *)fp->f_data;
+       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        VOP_LOCK(vp);
        if (vp->v_type == VDIR) {
                error = EISDIR;
        VOP_LOCK(vp);
        if (vp->v_type == VDIR) {
                error = EISDIR;
@@ -1552,7 +1584,6 @@ __ftruncate(p, uap, retval)
                goto out;
        VATTR_NULL(&vattr);
        vattr.va_size = uap->length;
                goto out;
        VATTR_NULL(&vattr);
        vattr.va_size = uap->length;
-       LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
        error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
 out:
        VOP_UNLOCK(vp);
        error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
 out:
        VOP_UNLOCK(vp);