]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_descrip.c
xnu-344.21.73.tar.gz
[apple/xnu.git] / bsd / kern / kern_descrip.c
index 7ede17b05fefee92e80d9e6d0c8eda8590117759..b1f7469d476304896ab0ed617ea174cda9613105 100644 (file)
@@ -1,21 +1,24 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
  * 
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
  * SUCH DAMAGE.
  *
  *     @(#)kern_descrip.c      8.8 (Berkeley) 2/14/95
- *
- *     History:
- *             CHW     8/5/98    Added F_SETSIZE command to truncate without
- *                                     zero filling space 
- *             CHW     7/6/98    Updated Preallocate command to take a structure
- *                               and return output.
- *             CHW     6/25/98   Fixed a bug in the lock call in fcntl 
- *                               Preallocate command
  */
 
 #include <sys/param.h>
@@ -93,6 +88,8 @@
 struct filelist filehead;      /* head of list of open files */
 int nfiles;                    /* actual number of open files */
 
+static int frele_internal(struct file *);
+
 /*
  * System calls on descriptors.
  */
@@ -103,7 +100,6 @@ getdtablesize(p, uap, retval)
        void *uap;
        register_t *retval;
 {
-
        *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
        return (0);
 }
@@ -115,7 +111,6 @@ ogetdtablesize(p, uap, retval)
        void *uap;
        register_t *retval;
 {
-
        *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, NOFILE);
        return (0);
 }
@@ -200,8 +195,7 @@ dup2(p, uap, retval)
                        _fdrelse(fdp, i);
                        goto closeit;
                }
-       }
-       else {
+       } else {
                struct file **fpp;
                char flags;
 closeit:
@@ -214,7 +208,8 @@ closeit:
                if (*(fpp = &fdp->fd_ofiles[new])) {
                        struct file *fp = *fpp;
 
-                       *fpp = NULL; (void) closef(fp, p);
+                       *fpp = NULL;
+                       (void) closef(fp, p);
                }
        }
        return (finishdup(fdp, old, new, retval));
@@ -242,13 +237,13 @@ fcntl(p, uap, retval)
        struct vnode *vp, *devvp;
        int i, tmp, error, error2, flg = F_POSIX;
        struct flock fl;
-        fstore_t alloc_struct;    /* structure for allocate command */
+       fstore_t alloc_struct;    /* structure for allocate command */
        u_int32_t alloc_flags = 0;
        off_t offset;             /* used for F_SETSIZE */
        int newmin;
        struct radvisory ra_struct;
        fbootstraptransfer_t fbt_struct; /* for F_READBOOTSTRAP and F_WRITEBOOTSTRAP */
-        struct log2phys l2p_struct;    /* structure for allocate command */
+       struct log2phys l2p_struct;    /* structure for allocate command */
        daddr_t lbn, bn;
        int devBlockSize = 0;
 
@@ -285,16 +280,16 @@ fcntl(p, uap, retval)
                fp->f_flag &= ~FCNTLFLAGS;
                fp->f_flag |= FFLAGS((long)uap->arg) & FCNTLFLAGS;
                tmp = fp->f_flag & FNONBLOCK;
-               error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
+               error = fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p);
                if (error)
                        return (error);
                tmp = fp->f_flag & FASYNC;
-               error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
+               error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, p);
                if (!error)
                        return (0);
                fp->f_flag &= ~FNONBLOCK;
                tmp = 0;
-               (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
+               (void)fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p);
                return (error);
 
        case F_GETOWN:
@@ -302,8 +297,7 @@ fcntl(p, uap, retval)
                        *retval = ((struct socket *)fp->f_data)->so_pgid;
                        return (0);
                }
-               error = (*fp->f_ops->fo_ioctl)
-                       (fp, (int)TIOCGPGRP, (caddr_t)retval, p);
+               error = fo_ioctl(fp, (int)TIOCGPGRP, (caddr_t)retval, p);
                *retval = -*retval;
                return (error);
 
@@ -314,15 +308,14 @@ fcntl(p, uap, retval)
                        return (0);
                }
                if ((long)uap->arg <= 0) {
-                       uap->arg = (void *)(-(long)(uap->arg));
+                       uap->arg = (int)(-(long)(uap->arg));
                } else {
                        struct proc *p1 = pfind((long)uap->arg);
                        if (p1 == 0)
                                return (ESRCH);
-                       uap->arg = (void *)(long)p1->p_pgrp->pg_id;
+                       uap->arg = (int)p1->p_pgrp->pg_id;
                }
-               return ((*fp->f_ops->fo_ioctl)
-                       (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p));
+               return (fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p));
 
        case F_SETLKW:
                flg |= F_WAIT;
@@ -377,55 +370,44 @@ fcntl(p, uap, retval)
                return (copyout((caddr_t)&fl, (caddr_t)uap->arg,
                    sizeof (fl)));
 
-        case F_PREALLOCATE:
-               
-               /* Copy in the structure */
+       case F_PREALLOCATE:
+               if (fp->f_type != DTYPE_VNODE)
+                       return (EBADF);
+
+               /* make sure that we have write permission */
+               if ((fp->f_flag & FWRITE) == 0)
+                       return (EBADF);
 
                error = copyin((caddr_t)uap->arg, (caddr_t)&alloc_struct,
                    sizeof (alloc_struct));
-
                if (error)
                        return (error);
 
-               /* now set the space allocated to 0 and pass it out in
-                  case we get a parameter checking error */
-               
+               /* now set the space allocated to 0 */
                alloc_struct.fst_bytesalloc = 0;
                
-               error = copyout((caddr_t)&alloc_struct, (caddr_t)uap->arg,
-                   sizeof (alloc_struct));
-
-                       if (error)
-                               return(error);
-
-               /* First make sure that we have write permission */
-
-               if ((fp->f_flag & FWRITE) == 0)
-                       return (EBADF);
-
-
-               /* Do some simple parameter checking */
-
+               /*
+                * Do some simple parameter checking
+                */
 
                /* set up the flags */
 
                alloc_flags |= PREALLOCATE;
                
-               if (alloc_struct.fst_flags & F_ALLOCATECONTIG) {
+               if (alloc_struct.fst_flags & F_ALLOCATECONTIG)
                        alloc_flags |= ALLOCATECONTIG;
-               }
 
-                if (alloc_struct.fst_flags & F_ALLOCATEALL) {
-                       alloc_flags |= ALLOCATEALL;
-                       }
+               if (alloc_struct.fst_flags & F_ALLOCATEALL)
+                       alloc_flags |= ALLOCATEALL;
 
-               /* Do any position mode specific stuff.  The only   */
-               /* position mode  supported now is PEOFPOSMODE      */
+               /*
+                * Do any position mode specific stuff.  The only
+                * position mode  supported now is PEOFPOSMODE
+                */
 
                switch (alloc_struct.fst_posmode) {
        
                case F_PEOFPOSMODE:
-
                        if (alloc_struct.fst_offset != 0)
                                return (EINVAL);
 
@@ -433,7 +415,6 @@ fcntl(p, uap, retval)
                        break;
 
                case F_VOLPOSMODE:
-
                        if (alloc_struct.fst_offset <= 0)
                                return (EINVAL);
 
@@ -441,131 +422,134 @@ fcntl(p, uap, retval)
                        break;
 
                default:
-
                        return(EINVAL);
-
                }
 
-               /* Now lock the vnode and call allocate to get the space */
-
-               vp = (struct vnode *)fp->f_data;
+               vp = (struct vnode *)fp->f_data;
 
-               VOP_LOCK(vp,LK_EXCLUSIVE,p);
+               /* lock the vnode and call allocate to get the space */
+               error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p);
+               if (error)
+                       return (error);
                error = VOP_ALLOCATE(vp,alloc_struct.fst_length,alloc_flags,
                                     &alloc_struct.fst_bytesalloc, alloc_struct.fst_offset,
                                     fp->f_cred, p);
-               VOP_UNLOCK(vp,0,p);
+               VOP_UNLOCK(vp, 0, p);
 
-               if (error2 = (copyout((caddr_t)&alloc_struct, (caddr_t)uap->arg,
-                   sizeof (alloc_struct)))) {
-                       if (error) {
+               if (error2 = copyout((caddr_t)&alloc_struct,
+                                               (caddr_t)uap->arg,
+                                               sizeof (alloc_struct))) {
+                       if (error)
                                return(error);
-                       } else {
+                       else
                                return(error2);
-                       }
                }
-
                return(error);
                
-        case F_SETSIZE:
+       case F_SETSIZE:
+               if (fp->f_type != DTYPE_VNODE)
+                       return (EBADF);
                
-               /* Copy in the structure */
-
                error = copyin((caddr_t)uap->arg, (caddr_t)&offset,
-                   sizeof (off_t));
-
+                                       sizeof (off_t));
                if (error)
                        return (error);
 
+               /*
+                * Make sure that we are root.  Growing a file
+                * without zero filling the data is a security hole 
+                * root would have access anyway so we'll allow it
+                */
 
-               /* First make sure that we are root.  Growing a file */
-               /* without zero filling the data is a security hole  */
-               /* root would have access anyway so we'll allow it   */
-
-               if (!is_suser()) {
+               if (!is_suser())
                        return (EACCES);
-                       }
 
-               /* Now lock the vnode and call allocate to get the space */
-
-               vp = (struct vnode *)fp->f_data;
+               vp = (struct vnode *)fp->f_data;
 
-               VOP_LOCK(vp,LK_EXCLUSIVE,p);
+               /* lock the vnode and call allocate to get the space */
+               error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p);
+               if (error)
+                       return (error);
                error = VOP_TRUNCATE(vp,offset,IO_NOZEROFILL,fp->f_cred,p);
                VOP_UNLOCK(vp,0,p);
-
                return(error);
-               
-        case F_RDAHEAD:
-               vp = (struct vnode *)fp->f_data;
-         
+
+       case F_RDAHEAD:
+               if (fp->f_type != DTYPE_VNODE)
+                       return (EBADF);
+               vp = (struct vnode *)fp->f_data;
+
                simple_lock(&vp->v_interlock);
                if (uap->arg)
-                     vp->v_flag &= ~VRAOFF;
+                       vp->v_flag &= ~VRAOFF;
                else
-                     vp->v_flag |= VRAOFF;
+                       vp->v_flag |= VRAOFF;
                simple_unlock(&vp->v_interlock);
-
                return (0);
 
-        case F_NOCACHE:
-               vp = (struct vnode *)fp->f_data;
-         
+       case F_NOCACHE:
+               if (fp->f_type != DTYPE_VNODE)
+                       return (EBADF);
+               vp = (struct vnode *)fp->f_data;
+
                simple_lock(&vp->v_interlock);
                if (uap->arg)
-                       vp->v_flag |= VNOCACHE_DATA;
+                       vp->v_flag |= VNOCACHE_DATA;
                else
-                       vp->v_flag &= ~VNOCACHE_DATA;
+                       vp->v_flag &= ~VNOCACHE_DATA;
                simple_unlock(&vp->v_interlock);
-
                return (0);
 
        case F_RDADVISE:
-               vp = (struct vnode *)fp->f_data;
+               if (fp->f_type != DTYPE_VNODE)
+                       return (EBADF);
+               vp = (struct vnode *)fp->f_data;
+
+               if (error = copyin((caddr_t)uap->arg,
+                                       (caddr_t)&ra_struct, sizeof (ra_struct)))
+                       return(error);
+               return (VOP_IOCTL(vp, 1, (caddr_t)&ra_struct, 0, fp->f_cred, p));
 
-               if (error = copyin((caddr_t)uap->arg, (caddr_t)&ra_struct, sizeof (ra_struct)))
-                       return(error);
-               return (VOP_IOCTL(vp, 1, &ra_struct, 0, fp->f_cred, p));
-               
        case F_READBOOTSTRAP:
        case F_WRITEBOOTSTRAP:
-               
-               /* Copy in the structure */
+               if (fp->f_type != DTYPE_VNODE)
+                       return (EBADF);
 
                error = copyin((caddr_t)uap->arg, (caddr_t)&fbt_struct,
-                   sizeof (fbt_struct));
-
+                               sizeof (fbt_struct));
                if (error)
                        return (error);
 
-
                if (uap->cmd == F_WRITEBOOTSTRAP) {
-                 /* First make sure that we are root.  Updating the */
-                 /* bootstrap on a disk could be a security hole */
-
-                 if (!is_suser()) {
-                   return (EACCES);
-                 }
-               };
-
-               /* Now lock the vnode and call VOP_IOCTL to handle the I/O: */
-
-               vp = (struct vnode *)fp->f_data;
-               if (vp->v_tag != VT_HFS) {
-                 error = EINVAL;
-               } else {
-                 VOP_LOCK(vp,LK_EXCLUSIVE,p);
-                 error = VOP_IOCTL(vp, (uap->cmd == F_WRITEBOOTSTRAP) ? 3 : 2, &fbt_struct, 0, fp->f_cred, p);
-                 VOP_UNLOCK(vp,0,p);
-               };
+                 /*
+                  * Make sure that we are root.  Updating the
+                  * bootstrap on a disk could be a security hole
+                  */
+                       if (!is_suser())
+                               return (EACCES);
+               }
 
+               vp = (struct vnode *)fp->f_data;
+               if (vp->v_tag != VT_HFS)        /* XXX */
+                       error = EINVAL;
+               else {
+                       /* lock the vnode and call VOP_IOCTL to handle the I/O */
+                       error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p);
+                       if (error)
+                               return (error);
+                       error = VOP_IOCTL(vp, (uap->cmd == F_WRITEBOOTSTRAP) ? 3 : 2,
+                                       (caddr_t)&fbt_struct, 0, fp->f_cred, p);
+                       VOP_UNLOCK(vp,0,p);
+               }
                return(error);
-               
-        case F_LOG2PHYS:
+
+       case F_LOG2PHYS:
                if (fp->f_type != DTYPE_VNODE)
                        return (EBADF);
                vp = (struct vnode *)fp->f_data;
-               VOP_LOCK(vp, LK_EXCLUSIVE, p);
+               error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p);
+               if (error)
+                       return (error);
                if (VOP_OFFTOBLK(vp, fp->f_offset, &lbn))
                        panic("fcntl LOG2PHYS OFFTOBLK");
                if (VOP_BLKTOOFF(vp, lbn, &offset))
@@ -584,7 +568,6 @@ fcntl(p, uap, retval)
                }
                return (error);
 
-
        default:
                return (EINVAL);
        }
@@ -972,10 +955,11 @@ ffree(fp)
                fp->f_cred = NOCRED;
                crfree(cred);
        }
-#if 1 || DIAGNOSTIC
-       fp->f_count = 0;
-#endif
+
        nfiles--;
+       memset(fp, 0xff, sizeof *fp);
+       fp->f_count = (short)0xffff;
+
        FREE_ZONE(fp, sizeof *fp, M_FILE);
 }
 
@@ -1062,8 +1046,7 @@ fdcopy(p)
                                *fpp = NULL;
                                *flags = 0;
                        }
-       }
-       else
+       } else
                (void) memset(newfdp->fd_ofiles, 0, i * OFILESIZE);
 
        return (newfdp);
@@ -1076,9 +1059,10 @@ void
 fdfree(p)
        struct proc *p;
 {
-       register struct filedesc *fdp;
-       register struct file **fpp;
-       register int i;
+       struct filedesc *fdp;
+       struct file **fpp;
+       int i;
+       struct vnode *tvp;
 
        if ((fdp = p->p_fd) == NULL)
                return;
@@ -1093,12 +1077,42 @@ fdfree(p)
                FREE_ZONE(fdp->fd_ofiles,
                                fdp->fd_nfiles * OFILESIZE, M_OFILETABL);
        }
-       vrele(fdp->fd_cdir);
-       if (fdp->fd_rdir)
-               vrele(fdp->fd_rdir);
+       tvp = fdp->fd_cdir;
+       fdp->fd_cdir = NULL;
+       vrele(tvp);
+       if (fdp->fd_rdir) {
+               tvp = fdp->fd_rdir;
+               fdp->fd_rdir = NULL;
+               vrele(tvp);
+       }
        FREE_ZONE(fdp, sizeof *fdp, M_FILEDESC);
 }
 
+static int
+closef_finish(fp, p)
+       register struct file *fp;
+       register struct proc *p;
+{
+       struct vnode *vp;
+       struct flock lf;
+       int error;
+
+       if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
+               lf.l_whence = SEEK_SET;
+               lf.l_start = 0;
+               lf.l_len = 0;
+               lf.l_type = F_UNLCK;
+               vp = (struct vnode *)fp->f_data;
+               (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
+       }
+       if (fp->f_ops)
+               error = fo_close(fp, p);
+       else
+               error = 0;
+       ffree(fp);
+       return (error);
+}
+
 /*
  * Internal form of close.
  * Decrement reference count on file structure.
@@ -1132,22 +1146,9 @@ closef(fp, p)
                vp = (struct vnode *)fp->f_data;
                (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
        }
-       if (frele(fp) > 0)
+       if (frele_internal(fp) > 0)
                return (0);
-       if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
-               lf.l_whence = SEEK_SET;
-               lf.l_start = 0;
-               lf.l_len = 0;
-               lf.l_type = F_UNLCK;
-               vp = (struct vnode *)fp->f_data;
-               (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
-       }
-       if (fp->f_ops)
-               error = (*fp->f_ops->fo_close)(fp, p);
-       else
-               error = 0;
-       ffree(fp);
-       return (error);
+       return(closef_finish(fp, p));
 }
 
 /*
@@ -1304,22 +1305,55 @@ dupfdopen(fdp, indx, dfd, mode, error)
 int
 fref(struct file *fp)
 {
+       if (fp->f_count == (short)0xffff)
+               return (-1);
        if (++fp->f_count <= 0)
                panic("fref: f_count");
        return ((int)fp->f_count);
 }
 
-int
-frele(struct file *fp)
+static int 
+frele_internal(struct file *fp)
 {
+       if (fp->f_count == (short)0xffff)
+               panic("frele: stale");
        if (--fp->f_count < 0)
                panic("frele: count < 0");
        return ((int)fp->f_count);
 }
 
+
+int
+frele(struct file *fp)
+{
+       int count;
+       funnel_t * fnl;
+       extern int disable_funnel;
+
+       fnl = thread_funnel_get();
+       /*
+        * If the funnels are merged then atleast a funnel should be held
+        * else frele should come in with kernel funnel only
+        */
+       if (!disable_funnel && (fnl != kernel_flock)) {
+               panic("frele: kernel funnel not held");
+
+       } else if  (fnl == THR_FUNNEL_NULL) {
+               panic("frele: no funnel held");
+       }
+
+       if ((count = frele_internal(fp)) == 0) {
+               /* some one closed the fd while we were blocked */
+               (void)closef_finish(fp, current_proc());
+       }
+       return(count);
+}
+
 int
 fcount(struct file *fp)
 {
+       if (fp->f_count == (short)0xffff)
+               panic("fcount: stale");
        return ((int)fp->f_count);
 }