/*
- * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
+ * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
* All rights reserved.
*
* %sccs.include.redist.c%
*
- * @(#)kern_descrip.c 7.19 (Berkeley) %G%
+ * @(#)kern_descrip.c 7.37 (Berkeley) %G%
*/
#include "param.h"
#include "systm.h"
-#include "user.h"
#include "filedesc.h"
#include "kernel.h"
#include "vnode.h"
#include "fcntl.h"
#include "malloc.h"
#include "syslog.h"
+#include "resourcevar.h"
/*
* Descriptor management.
*/
-int nofile = NOFILE; /* per-process maximum open files */
+struct file *filehead; /* head of list of open files */
+int nfiles; /* actual number of open files */
/*
* System calls on descriptors.
*/
+struct getdtablesize_args {
+ int dummy;
+};
/* ARGSUSED */
getdtablesize(p, uap, retval)
struct proc *p;
- struct args *uap;
+ struct getdtablesize_args *uap;
int *retval;
{
- *retval = nofile;
+ *retval = p->p_rlimit[RLIMIT_OFILE].rlim_cur;
return (0);
}
/*
* Duplicate a file descriptor.
*/
+struct dup_args {
+ int i;
+};
/* ARGSUSED */
dup(p, uap, retval)
struct proc *p;
- struct args {
- int i;
- } *uap;
+ struct dup_args *uap;
int *retval;
{
register struct filedesc *fdp = p->p_fd;
*/
if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); }
- if ((unsigned)uap->i >= fdp->fd_maxfiles ||
- (fp = OFILE(fdp, uap->i)) == NULL)
+ if ((unsigned)uap->i >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[uap->i]) == NULL)
return (EBADF);
- if (error = ufalloc(fdp, 0, &fd))
+ if (error = fdalloc(p, 0, &fd))
return (error);
- OFILE(fdp, fd) = fp;
- OFILEFLAGS(fdp, fd) = OFILEFLAGS(fdp, uap->i) &~ UF_EXCLOSE;
+ fdp->fd_ofiles[fd] = fp;
+ fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE;
fp->f_count++;
if (fd > fdp->fd_lastfile)
fdp->fd_lastfile = fd;
/*
* Duplicate a file descriptor to a particular value.
*/
+struct dup2_args {
+ u_int from;
+ u_int to;
+};
/* ARGSUSED */
dup2(p, uap, retval)
struct proc *p;
- register struct args {
- int i;
- int j;
- } *uap;
+ struct dup2_args *uap;
int *retval;
{
register struct filedesc *fdp = p->p_fd;
register struct file *fp;
+ register u_int old = uap->from, new = uap->to;
int i, error;
- if ((unsigned)uap->i >= fdp->fd_maxfiles ||
- (fp = OFILE(fdp, uap->i)) == NULL ||
- (unsigned)uap->j >= nofile)
+ if (old >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[old]) == NULL ||
+ new >= p->p_rlimit[RLIMIT_OFILE].rlim_cur)
return (EBADF);
- *retval = uap->j;
- if (uap->i == uap->j)
+ *retval = new;
+ if (old == new)
return (0);
- if ((unsigned)uap->j >= fdp->fd_maxfiles) {
- if (error = ufalloc(fdp, uap->j, &i))
+ if (new >= fdp->fd_nfiles) {
+ if (error = fdalloc(p, new, &i))
return (error);
- if (uap->j != i)
- panic("dup2: ufalloc");
- } else if (OFILE(fdp, uap->j)) {
- if (OFILEFLAGS(fdp, uap->j) & UF_MAPPED)
- (void) munmapfd(p, uap->j);
- error = closef(OFILE(fdp, uap->j));
+ if (new != i)
+ panic("dup2: fdalloc");
+ } else if (fdp->fd_ofiles[new]) {
+ if (fdp->fd_ofileflags[new] & UF_MAPPED)
+ (void) munmapfd(p, new);
+ /*
+ * dup2() must succeed even if the close has an error.
+ */
+ (void) closef(fdp->fd_ofiles[new], p);
}
- OFILE(fdp, uap->j) = fp;
- OFILEFLAGS(fdp, uap->j) = OFILEFLAGS(fdp, uap->i) &~ UF_EXCLOSE;
+ fdp->fd_ofiles[new] = fp;
+ fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
fp->f_count++;
- if (uap->j > fdp->fd_lastfile)
- fdp->fd_lastfile = uap->j;
- /*
- * dup2() must succeed even though the close had an error.
- */
- error = 0; /* XXX */
- return (error);
+ if (new > fdp->fd_lastfile)
+ fdp->fd_lastfile = new;
+ return (0);
}
/*
* The file control system call.
*/
+struct fcntl_args {
+ int fd;
+ int cmd;
+ int arg;
+};
/* ARGSUSED */
fcntl(p, uap, retval)
struct proc *p;
- register struct args {
- int fdes;
- int cmd;
- int arg;
- } *uap;
+ register struct fcntl_args *uap;
int *retval;
{
register struct filedesc *fdp = p->p_fd;
register struct file *fp;
register char *pop;
struct vnode *vp;
- int i, error, flags = F_POSIX;
+ int i, tmp, error, flg = F_POSIX;
struct flock fl;
- if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
- (fp = OFILE(fdp, uap->fdes)) == NULL)
+ if ((unsigned)uap->fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[uap->fd]) == NULL)
return (EBADF);
- pop = &OFILEFLAGS(fdp, uap->fdes);
+ pop = &fdp->fd_ofileflags[uap->fd];
switch(uap->cmd) {
case F_DUPFD:
- if ((unsigned)uap->arg >= nofile)
+ if ((unsigned)uap->arg >= p->p_rlimit[RLIMIT_OFILE].rlim_cur)
return (EINVAL);
- if (error = ufalloc(fdp, uap->arg, &i))
+ if (error = fdalloc(p, uap->arg, &i))
return (error);
- OFILE(fdp, i) = fp;
- OFILEFLAGS(fdp, i) = *pop &~ UF_EXCLOSE;
+ fdp->fd_ofiles[i] = fp;
+ fdp->fd_ofileflags[i] = *pop &~ UF_EXCLOSE;
fp->f_count++;
if (i > fdp->fd_lastfile)
fdp->fd_lastfile = i;
case F_SETFL:
fp->f_flag &= ~FCNTLFLAGS;
fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS;
- if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY))
+ tmp = fp->f_flag & FNONBLOCK;
+ error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
+ if (error)
return (error);
- if (error = fset(fp, FASYNC, fp->f_flag & FASYNC))
- (void) fset(fp, FNDELAY, 0);
+ tmp = fp->f_flag & FASYNC;
+ error = (*fp->f_ops->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);
return (error);
case F_GETOWN:
- return (fgetown(fp, retval));
+ if (fp->f_type == DTYPE_SOCKET) {
+ *retval = ((struct socket *)fp->f_data)->so_pgid;
+ return (0);
+ }
+ error = (*fp->f_ops->fo_ioctl)
+ (fp, (int)TIOCGPGRP, (caddr_t)retval, p);
+ *retval = -*retval;
+ return (error);
case F_SETOWN:
- return (fsetown(fp, uap->arg));
+ if (fp->f_type == DTYPE_SOCKET) {
+ ((struct socket *)fp->f_data)->so_pgid = uap->arg;
+ return (0);
+ }
+ if (uap->arg <= 0) {
+ uap->arg = -uap->arg;
+ } else {
+ struct proc *p1 = pfind(uap->arg);
+ if (p1 == 0)
+ return (ESRCH);
+ uap->arg = p1->p_pgrp->pg_id;
+ }
+ return ((*fp->f_ops->fo_ioctl)
+ (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p));
case F_SETLKW:
- flags |= F_WAIT;
+ flg |= F_WAIT;
/* Fall into F_SETLK */
case F_SETLK:
case F_RDLCK:
if ((fp->f_flag & FREAD) == 0)
return (EBADF);
- return (VOP_ADVLOCK(vp, p, F_SETLK, &fl, flags));
+ p->p_flag |= SADVLCK;
+ return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
case F_WRLCK:
if ((fp->f_flag & FWRITE) == 0)
return (EBADF);
- return (VOP_ADVLOCK(vp, p, F_SETLK, &fl, flags));
+ p->p_flag |= SADVLCK;
+ return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
case F_UNLCK:
- return (VOP_ADVLOCK(vp, p, F_UNLCK, &fl, F_POSIX));
+ return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl,
+ F_POSIX));
default:
return (EINVAL);
error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
if (error)
return (error);
- if (error = VOP_ADVLOCK(vp, p, F_GETLK, &fl, F_POSIX))
+ if (fl.l_whence == SEEK_CUR)
+ fl.l_start += fp->f_offset;
+ if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX))
return (error);
return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl)));
/* NOTREACHED */
}
-fset(fp, bit, value)
- struct file *fp;
- int bit, value;
-{
-
- if (value)
- fp->f_flag |= bit;
- else
- fp->f_flag &= ~bit;
- return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
- (caddr_t)&value));
-}
-
-fgetown(fp, valuep)
- struct file *fp;
- int *valuep;
-{
- int error;
-
- switch (fp->f_type) {
-
- case DTYPE_SOCKET:
- *valuep = ((struct socket *)fp->f_data)->so_pgid;
- return (0);
-
- default:
- error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
- *valuep = -*valuep;
- return (error);
- }
-}
-
-fsetown(fp, value)
- struct file *fp;
- int value;
-{
-
- if (fp->f_type == DTYPE_SOCKET) {
- ((struct socket *)fp->f_data)->so_pgid = value;
- return (0);
- }
- if (value > 0) {
- struct proc *p = pfind(value);
- if (p == 0)
- return (ESRCH);
- value = p->p_pgrp->pg_id;
- } else
- value = -value;
- return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
-}
-
-fioctl(fp, cmd, value)
- struct file *fp;
- int cmd;
- caddr_t value;
-{
-
- return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
-}
-
/*
* Close a file descriptor.
*/
+struct close_args {
+ int fd;
+};
/* ARGSUSED */
close(p, uap, retval)
struct proc *p;
- struct args {
- int fdes;
- } *uap;
+ struct close_args *uap;
int *retval;
{
register struct filedesc *fdp = p->p_fd;
register struct file *fp;
+ register int fd = uap->fd;
register u_char *pf;
- if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
- (fp = OFILE(fdp, uap->fdes)) == NULL)
+ if ((unsigned)fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL)
return (EBADF);
- pf = (u_char *)&OFILEFLAGS(fdp, uap->fdes);
+ pf = (u_char *)&fdp->fd_ofileflags[fd];
if (*pf & UF_MAPPED)
- (void) munmapfd(p, uap->fdes);
- OFILE(fdp, uap->fdes) = NULL;
- while (fdp->fd_lastfile >= 0 && OFILE(fdp, fdp->fd_lastfile) == NULL)
+ (void) munmapfd(p, fd);
+ fdp->fd_ofiles[fd] = NULL;
+ while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
fdp->fd_lastfile--;
+ if (fd < fdp->fd_freefile)
+ fdp->fd_freefile = fd;
*pf = 0;
- return (closef(fp));
+ return (closef(fp, p));
}
+#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
/*
* Return status information about a file descriptor.
*/
+struct ofstat_args {
+ int fd;
+ struct ostat *sb;
+};
+/* ARGSUSED */
+ofstat(p, uap, retval)
+ struct proc *p;
+ register struct ofstat_args *uap;
+ int *retval;
+{
+ register struct filedesc *fdp = p->p_fd;
+ register struct file *fp;
+ struct stat ub;
+ struct ostat oub;
+ int error;
+
+ if ((unsigned)uap->fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[uap->fd]) == NULL)
+ return (EBADF);
+ switch (fp->f_type) {
+
+ case DTYPE_VNODE:
+ error = vn_stat((struct vnode *)fp->f_data, &ub, p);
+ break;
+
+ case DTYPE_SOCKET:
+ error = soo_stat((struct socket *)fp->f_data, &ub);
+ break;
+
+ default:
+ panic("ofstat");
+ /*NOTREACHED*/
+ }
+ cvtstat(&ub, &oub);
+ if (error == 0)
+ error = copyout((caddr_t)&oub, (caddr_t)uap->sb, sizeof (oub));
+ return (error);
+}
+#endif /* COMPAT_43 || COMPAT_SUNOS */
+
+/*
+ * Return status information about a file descriptor.
+ */
+struct fstat_args {
+ int fd;
+ struct stat *sb;
+};
/* ARGSUSED */
fstat(p, uap, retval)
struct proc *p;
- register struct args {
- int fdes;
- struct stat *sb;
- } *uap;
+ register struct fstat_args *uap;
int *retval;
{
register struct filedesc *fdp = p->p_fd;
struct stat ub;
int error;
- if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
- (fp = OFILE(fdp, uap->fdes)) == NULL)
+ if ((unsigned)uap->fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[uap->fd]) == NULL)
return (EBADF);
switch (fp->f_type) {
case DTYPE_VNODE:
- error = vn_stat((struct vnode *)fp->f_data, &ub);
+ error = vn_stat((struct vnode *)fp->f_data, &ub, p);
break;
case DTYPE_SOCKET:
}
/*
- * Allocate a user file descriptor.
+ * Allocate a file descriptor for the process.
*/
-int fdexpand, fdreexpand;
+int fdexpand;
-ufalloc(fdp, want, result)
- register struct filedesc *fdp;
- register int want;
+fdalloc(p, want, result)
+ struct proc *p;
+ int want;
int *result;
{
- int last, osize, ofiles, nfiles;
+ register struct filedesc *fdp = p->p_fd;
+ register int i;
+ int lim, last, nfiles;
struct file **newofile;
char *newofileflags;
+ /*
+ * Search for a free descriptor starting at the higher
+ * of want or fd_freefile. If that fails, consider
+ * expanding the ofile array.
+ */
+ lim = p->p_rlimit[RLIMIT_OFILE].rlim_cur;
for (;;) {
- last = (fdp->fd_maxfiles < nofile) ? fdp->fd_maxfiles : nofile;
- for (; want < last; want++) {
- if (OFILE(fdp, want) == NULL) {
- OFILEFLAGS(fdp, want) = 0;
- if (want > fdp->fd_lastfile)
- fdp->fd_lastfile = want;
- *result = want;
+ last = min(fdp->fd_nfiles, lim);
+ if ((i = want) < fdp->fd_freefile)
+ i = fdp->fd_freefile;
+ for (; i < last; i++) {
+ if (fdp->fd_ofiles[i] == NULL) {
+ fdp->fd_ofileflags[i] = 0;
+ if (i > fdp->fd_lastfile)
+ fdp->fd_lastfile = i;
+ if (want <= fdp->fd_freefile)
+ fdp->fd_freefile = i;
+ *result = i;
return (0);
}
}
- if (fdp->fd_maxfiles >= nofile)
+
+ /*
+ * No space in current array. Expand?
+ */
+ if (fdp->fd_nfiles >= lim)
return (EMFILE);
- if (fdp->fd_maxfiles == NDFILE) {
- fdp->fd_moreofiles = (struct file **)
- malloc(NDEXTENT * OFILESIZE, M_FILE, M_WAITOK);
- fdp->fd_moreofileflags =
- (char *)&fdp->fd_moreofiles[NDEXTENT];
- bzero((char *)fdp->fd_moreofiles, NDEXTENT * OFILESIZE);
- fdp->fd_maxfiles = NDFILE + NDEXTENT;
- fdexpand++;
- continue;
- }
- ofiles = fdp->fd_maxfiles - NDFILE;
- osize = ofiles * OFILESIZE;
- nfiles = (2 * osize) / OFILESIZE;
- newofile = (struct file **) malloc(2 * osize, M_FILE, M_WAITOK);
- newofileflags = (char *)&newofile[nfiles];
- bzero((char *)newofile, 2 * osize);
- bcopy((char *)fdp->fd_moreofiles, (char *)newofile,
- sizeof(struct file *) * ofiles);
- bcopy((char *)fdp->fd_moreofileflags, (char *)newofileflags,
- sizeof(char) * ofiles);
- free(fdp->fd_moreofiles, M_FILE);
- fdp->fd_moreofiles = newofile;
- fdp->fd_moreofileflags = newofileflags;
- fdp->fd_maxfiles = NDFILE + nfiles;
- fdreexpand++;
+ if (fdp->fd_nfiles < NDEXTENT)
+ nfiles = NDEXTENT;
+ else
+ nfiles = 2 * fdp->fd_nfiles;
+ MALLOC(newofile, struct file **, nfiles * OFILESIZE,
+ M_FILEDESC, M_WAITOK);
+ newofileflags = (char *) &newofile[nfiles];
+ /*
+ * Copy the existing ofile and ofileflags arrays
+ * and zero the new portion of each array.
+ */
+ bcopy(fdp->fd_ofiles, newofile,
+ (i = sizeof(struct file *) * fdp->fd_nfiles));
+ bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i);
+ bcopy(fdp->fd_ofileflags, newofileflags,
+ (i = sizeof(char) * fdp->fd_nfiles));
+ bzero(newofileflags + i, nfiles * sizeof(char) - i);
+ if (fdp->fd_nfiles > NDFILE)
+ FREE(fdp->fd_ofiles, M_FILEDESC);
+ fdp->fd_ofiles = newofile;
+ fdp->fd_ofileflags = newofileflags;
+ fdp->fd_nfiles = nfiles;
+ fdexpand++;
}
}
/*
- * Check to see if any user file descriptors are available.
+ * Check to see whether n user file descriptors
+ * are available to the process p.
*/
-ufavail(fdp)
- register struct filedesc *fdp;
+fdavail(p, n)
+ struct proc *p;
+ register int n;
{
- register int i, avail;
+ register struct filedesc *fdp = p->p_fd;
+ register struct file **fpp;
+ register int i;
- avail = nofile - fdp->fd_maxfiles;
- for (i = 0; i < fdp->fd_maxfiles; i++)
- if (OFILE(fdp, i) == NULL)
- avail++;
- return (avail);
+ if ((i = p->p_rlimit[RLIMIT_OFILE].rlim_cur - fdp->fd_nfiles) > 0 &&
+ (n -= i) <= 0)
+ return (1);
+ fpp = &fdp->fd_ofiles[fdp->fd_freefile];
+ for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++)
+ if (*fpp == NULL && --n <= 0)
+ return (1);
+ return (0);
}
-struct file *lastf;
/*
- * Allocate a user file descriptor
- * and a file structure.
- * Initialize the descriptor
- * to point at the file structure.
+ * Create a new open file structure and allocate
+ * a file decriptor for the process that refers to it.
*/
falloc(p, resultfp, resultfd)
register struct proc *p;
struct file **resultfp;
int *resultfd;
{
- register struct file *fp;
+ register struct file *fp, *fq, **fpp;
int error, i;
- if (error = ufalloc(p->p_fd, 0, &i))
+ if (error = fdalloc(p, 0, &i))
return (error);
- if (lastf == 0)
- lastf = file;
- for (fp = lastf; fp < fileNFILE; fp++)
- if (fp->f_count == 0)
- goto slot;
- for (fp = file; fp < lastf; fp++)
- if (fp->f_count == 0)
- goto slot;
- tablefull("file");
- return (ENFILE);
-slot:
- OFILE(p->p_fd, i) = fp;
+ if (nfiles >= maxfiles) {
+ tablefull("file");
+ return (ENFILE);
+ }
+ /*
+ * Allocate a new file descriptor.
+ * If the process has file descriptor zero open, add to the list
+ * of open files at that point, otherwise put it at the front of
+ * the list of open files.
+ */
+ nfiles++;
+ MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK);
+ if (fq = p->p_fd->fd_ofiles[0])
+ fpp = &fq->f_filef;
+ else
+ fpp = &filehead;
+ p->p_fd->fd_ofiles[i] = fp;
+ if (fq = *fpp)
+ fq->f_fileb = &fp->f_filef;
+ fp->f_filef = fq;
+ fp->f_fileb = fpp;
+ *fpp = fp;
fp->f_count = 1;
- fp->f_data = 0;
+ fp->f_msgcount = 0;
fp->f_offset = 0;
- fp->f_cred = u.u_cred;
+ fp->f_cred = p->p_ucred;
crhold(fp->f_cred);
- lastf = fp + 1;
if (resultfp)
*resultfp = fp;
if (resultfd)
}
/*
- * Duplicate a filedesc structure.
+ * Free a file descriptor.
+ */
+ffree(fp)
+ register struct file *fp;
+{
+ register struct file *fq;
+
+ if (fq = fp->f_filef)
+ fq->f_fileb = fp->f_fileb;
+ *fp->f_fileb = fq;
+ crfree(fp->f_cred);
+#ifdef DIAGNOSTIC
+ fp->f_filef = NULL;
+ fp->f_fileb = NULL;
+ fp->f_count = 0;
+#endif
+ nfiles--;
+ FREE(fp, M_FILE);
+}
+
+/*
+ * Copy a filedesc structure.
*/
struct filedesc *
-fddup(fdp, justref)
- register struct filedesc *fdp;
- int justref;
+fdcopy(p)
+ struct proc *p;
{
- register struct filedesc *newfdp;
- register struct file *fp;
+ register struct filedesc *newfdp, *fdp = p->p_fd;
+ register struct file **fpp;
register int i;
- int j, last;
- if (justref) {
- fdp->fd_refcnt++;
- return (fdp);
- }
- MALLOC(newfdp, struct filedesc *, sizeof(*fdp), M_FILE, M_WAITOK);
- bcopy((char *)fdp, (char *)newfdp, sizeof(*fdp));
+ MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0),
+ M_FILEDESC, M_WAITOK);
+ bcopy(fdp, newfdp, sizeof(struct filedesc));
VREF(newfdp->fd_cdir);
if (newfdp->fd_rdir)
VREF(newfdp->fd_rdir);
newfdp->fd_refcnt = 1;
- newfdp->fd_maxfiles = NDFILE;
- if (fdp->fd_lastfile > NDFILE &&
- ufalloc(newfdp, fdp->fd_lastfile, &j)) {
- log(LOG_ERR, "fddup: lost file descriptor(s)");
- last = newfdp->fd_maxfiles;
- } else
- last = fdp->fd_lastfile;
- for (i = 0; i <= last; i++) {
- fp = OFILE(fdp, i);
- if (fp == NULL)
- continue;
- fp->f_count++;
- OFILE(newfdp, i) = fp;
- OFILEFLAGS(newfdp, i) = OFILEFLAGS(fdp, i);
+
+ /*
+ * If the number of open files fits in the internal arrays
+ * of the open file structure, use them, otherwise allocate
+ * additional memory for the number of descriptors currently
+ * in use.
+ */
+ if (newfdp->fd_lastfile < NDFILE) {
+ newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
+ newfdp->fd_ofileflags =
+ ((struct filedesc0 *) newfdp)->fd_dfileflags;
+ i = NDFILE;
+ } else {
+ /*
+ * Compute the smallest multiple of NDEXTENT needed
+ * for the file descriptors currently in use,
+ * allowing the table to shrink.
+ */
+ i = newfdp->fd_nfiles;
+ while (i > 2 * NDEXTENT && i >= newfdp->fd_lastfile * 2)
+ i /= 2;
+ MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE,
+ M_FILEDESC, M_WAITOK);
+ newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
}
+ newfdp->fd_nfiles = i;
+ bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
+ bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
+ fpp = newfdp->fd_ofiles;
+ for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
+ if (*fpp != NULL)
+ (*fpp)->f_count++;
return (newfdp);
}
/*
* Release a filedesc structure.
*/
-fdrele(fdp)
- register struct filedesc *fdp;
+void
+fdfree(p)
+ struct proc *p;
{
- struct file *f;
+ register struct filedesc *fdp = p->p_fd;
+ struct file **fpp;
register int i;
- if (fdp->fd_refcnt > 1) {
- fdp->fd_refcnt--;
+ if (--fdp->fd_refcnt > 0)
return;
- }
- for (i = 0; i <= fdp->fd_lastfile; i++) {
- if (f = OFILE(fdp, i)) {
- OFILE(fdp, i) = NULL;
- OFILEFLAGS(fdp, i) = 0;
- (void) closef(f);
- }
- }
- if (fdp->fd_maxfiles > NDFILE)
- FREE(fdp->fd_moreofiles, M_FILE);
+ fpp = fdp->fd_ofiles;
+ for (i = fdp->fd_lastfile; i-- >= 0; fpp++)
+ if (*fpp)
+ (void) closef(*fpp, p);
+ if (fdp->fd_nfiles > NDFILE)
+ FREE(fdp->fd_ofiles, M_FILEDESC);
vrele(fdp->fd_cdir);
if (fdp->fd_rdir)
vrele(fdp->fd_rdir);
- FREE(fdp, M_FILE);
+ FREE(fdp, M_FILEDESC);
}
/*
* Internal form of close.
* Decrement reference count on file structure.
+ * Note: p may be NULL when closing a file
+ * that was being passed in a message.
*/
-closef(fp)
+closef(fp, p)
register struct file *fp;
+ register struct proc *p;
{
- struct proc *p = u.u_procp; /* XXX */
struct vnode *vp;
struct flock lf;
int error;
* locks owned by this process. This is handled by setting
* a flag in the unlock to free ONLY locks obeying POSIX
* semantics, and not to free BSD-style file locks.
+ * If the descriptor was in a message, POSIX-style locks
+ * aren't passed with the descriptor.
*/
- if (fp->f_type == DTYPE_VNODE) {
+ if (p && (p->p_flag & SADVLCK) && 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, p, F_UNLCK, &lf, F_POSIX);
+ (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
}
- if (fp->f_count > 1) {
- fp->f_count--;
+ if (--fp->f_count > 0)
return (0);
+ if (fp->f_count < 0)
+ panic("closef: count < 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_count < 1)
- panic("closef: count < 1");
- if (fp->f_type == DTYPE_VNODE)
- (void) VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK);
- error = (*fp->f_ops->fo_close)(fp);
- crfree(fp->f_cred);
- fp->f_count = 0;
+ error = (*fp->f_ops->fo_close)(fp, p);
+ ffree(fp);
return (error);
}
* Just attempt to get a record lock of the requested type on
* the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
*/
-
+struct flock_args {
+ int fd;
+ int how;
+};
/* ARGSUSED */
flock(p, uap, retval)
struct proc *p;
- register struct args {
- int fdes;
- int how;
- } *uap;
+ register struct flock_args *uap;
int *retval;
{
register struct filedesc *fdp = p->p_fd;
struct flock lf;
int error;
- if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
- (fp = OFILE(fdp, uap->fdes)) == NULL)
+ if ((unsigned)uap->fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[uap->fd]) == NULL)
return (EBADF);
if (fp->f_type != DTYPE_VNODE)
return (EOPNOTSUPP);
lf.l_len = 0;
if (uap->how & LOCK_UN) {
lf.l_type = F_UNLCK;
- return (VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK));
+ fp->f_flag &= ~FHASLOCK;
+ return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
}
if (uap->how & LOCK_EX)
lf.l_type = F_WRLCK;
lf.l_type = F_RDLCK;
else
return (EBADF);
+ fp->f_flag |= FHASLOCK;
if (uap->how & LOCK_NB)
- return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK));
- return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
+ return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
+ return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
}
/*
* references to this file will be direct to the other driver.
*/
/* ARGSUSED */
-fdopen(dev, mode, type)
+fdopen(dev, mode, type, p)
dev_t dev;
int mode, type;
+ struct proc *p;
{
- struct proc *p = u.u_procp; /* XXX */
/*
- * XXX Kludge: set p->p_dupfd to contain the value of the
+ * XXX Kludge: set curproc->p_dupfd to contain the value of the
* the file descriptor being sought for duplication. The error
* return ensures that the vnode for this device will be released
* by vn_open. Open will detect this special error and take the
/*
* Duplicate the specified descriptor to a free descriptor.
*/
-dupfdopen(fdp, indx, dfd, mode)
+dupfdopen(fdp, indx, dfd, mode, error)
register struct filedesc *fdp;
register int indx, dfd;
int mode;
+ int error;
{
register struct file *wfp;
struct file *fp;
* falloc could allocate an already closed to-be-dup'd descriptor
* as the new descriptor.
*/
- fp = OFILE(fdp, indx);
- if ((u_int)dfd >= fdp->fd_maxfiles || (wfp = OFILE(fdp, dfd)) == NULL ||
- fp == wfp)
+ fp = fdp->fd_ofiles[indx];
+ if ((u_int)dfd >= fdp->fd_nfiles ||
+ (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp)
return (EBADF);
/*
- * Check that the mode the file is being opened for is a subset
- * of the mode of the existing descriptor.
+ * There are two cases of interest here.
+ *
+ * For ENODEV simply dup (dfd) to file descriptor
+ * (indx) and return.
+ *
+ * For ENXIO steal away the file structure from (dfd) and
+ * store it in (indx). (dfd) is effectively closed by
+ * this operation.
+ *
+ * Any other error code is just returned.
*/
- if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
- return (EACCES);
- OFILE(fdp, indx) = wfp;
- OFILEFLAGS(fdp, indx) = OFILEFLAGS(fdp, dfd);
- wfp->f_count++;
- if (indx > fdp->fd_lastfile)
- fdp->fd_lastfile = indx;
- return (0);
-}
-
-#if defined(vax) || defined(tahoe)
-/*
- * Brain dead routines to compensate for limitations in PCC
- */
-struct file **
-ofilefunc(fdp, indx)
- struct filedesc *fdp;
- int indx;
-{
-
- if (indx < NDFILE)
- return (&fdp->fd_ofile[indx]);
- return (&fdp->fd_moreofiles[indx - NDFILE]);
-}
+ switch (error) {
+ case ENODEV:
+ /*
+ * Check that the mode the file is being opened for is a
+ * subset of the mode of the existing descriptor.
+ */
+ if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
+ return (EACCES);
+ fdp->fd_ofiles[indx] = wfp;
+ fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
+ wfp->f_count++;
+ if (indx > fdp->fd_lastfile)
+ fdp->fd_lastfile = indx;
+ return (0);
-char *
-ofileflagsfunc(fdp, indx)
- struct filedesc *fdp;
- int indx;
-{
+ case ENXIO:
+ /*
+ * Steal away the file pointer from dfd, and stuff it into indx.
+ */
+ fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
+ fdp->fd_ofiles[dfd] = NULL;
+ fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
+ fdp->fd_ofileflags[dfd] = 0;
+ /*
+ * Complete the clean up of the filedesc structure by
+ * recomputing the various hints.
+ */
+ if (indx > fdp->fd_lastfile)
+ fdp->fd_lastfile = indx;
+ else
+ while (fdp->fd_lastfile > 0 &&
+ fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
+ fdp->fd_lastfile--;
+ if (dfd < fdp->fd_freefile)
+ fdp->fd_freefile = dfd;
+ return (0);
- if (indx < NDFILE)
- return (&fdp->fd_ofileflags[indx]);
- return (&fdp->fd_moreofileflags[indx - NDFILE]);
+ default:
+ return (error);
+ }
+ /* NOTREACHED */
}
-#endif