/*
- * 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>
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.
*/
void *uap;
register_t *retval;
{
-
*retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
return (0);
}
void *uap;
register_t *retval;
{
-
*retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, NOFILE);
return (0);
}
_fdrelse(fdp, i);
goto closeit;
}
- }
- else {
+ } else {
struct file **fpp;
char flags;
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));
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;
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:
*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);
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;
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);
break;
case F_VOLPOSMODE:
-
if (alloc_struct.fst_offset <= 0)
return (EINVAL);
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))
}
return (error);
-
default:
return (EINVAL);
}
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);
}
*fpp = NULL;
*flags = 0;
}
- }
- else
+ } else
(void) memset(newfdp->fd_ofiles, 0, i * OFILESIZE);
return (newfdp);
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;
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.
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));
}
/*
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);
}