svn commit: r202058 - user/kmacy/releng_8_rump/lib/libunet
Kip Macy
kmacy at FreeBSD.org
Mon Jan 11 00:51:25 UTC 2010
Author: kmacy
Date: Mon Jan 11 00:51:25 2010
New Revision: 202058
URL: http://svn.freebsd.org/changeset/base/202058
Log:
integrate bulk of kern_descrip.c - excluding procstat and vnode bits
Modified:
user/kmacy/releng_8_rump/lib/libunet/unet_kern_descrip.c
Modified: user/kmacy/releng_8_rump/lib/libunet/unet_kern_descrip.c
==============================================================================
--- user/kmacy/releng_8_rump/lib/libunet/unet_kern_descrip.c Mon Jan 11 00:41:14 2010 (r202057)
+++ user/kmacy/releng_8_rump/lib/libunet/unet_kern_descrip.c Mon Jan 11 00:51:25 2010 (r202058)
@@ -1,5 +1,3 @@
-
-
/*-
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
@@ -75,16 +73,751 @@ __FBSDID("$FreeBSD$");
#include <sys/tty.h>
#include <sys/unistd.h>
#include <sys/user.h>
+#ifdef KTRACE
+#include <sys/ktrace.h>
+#endif
+
+#include <security/audit/audit.h>
+
+#include <vm/uma.h>
+
+#include <ddb/ddb.h>
static MALLOC_DEFINE(M_FILEDESC, "filedesc", "Open file descriptor table");
+static MALLOC_DEFINE(M_FILEDESC_TO_LEADER, "filedesc_to_leader",
+ "file desc to leader structures");
+static MALLOC_DEFINE(M_SIGIO, "sigio", "sigio structures");
static uma_zone_t file_zone;
+#define vref(v)
+#define VREF(x) vref((x))
+#define knote_fdclose(x, y)
+
+
+/* Flags for do_dup() */
+#define DUP_FIXED 0x1 /* Force fixed allocation */
+#define DUP_FCNTL 0x2 /* fcntl()-style errors */
+
+static int do_dup(struct thread *td, int flags, int old, int new,
+ register_t *retval);
+static int fd_first_free(struct filedesc *, int, int);
+static int fd_last_used(struct filedesc *, int, int);
+static void fdgrowtable(struct filedesc *, int);
+static void fdunused(struct filedesc *fdp, int fd);
+static void fdused(struct filedesc *fdp, int fd);
+
+/*
+ * A process is initially started out with NDFILE descriptors stored within
+ * this structure, selected to be enough for typical applications based on
+ * the historical limit of 20 open files (and the usage of descriptors by
+ * shells). If these descriptors are exhausted, a larger descriptor table
+ * may be allocated, up to a process' resource limit; the internal arrays
+ * are then unused.
+ */
+#define NDFILE 20
+#define NDSLOTSIZE sizeof(NDSLOTTYPE)
+#define NDENTRIES (NDSLOTSIZE * __CHAR_BIT)
+#define NDSLOT(x) ((x) / NDENTRIES)
+#define NDBIT(x) ((NDSLOTTYPE)1 << ((x) % NDENTRIES))
+#define NDSLOTS(x) (((x) + NDENTRIES - 1) / NDENTRIES)
+
+/*
+ * Storage required per open file descriptor.
+ */
+#define OFILESIZE (sizeof(struct file *) + sizeof(char))
+
+/*
+ * Storage to hold unused ofiles that need to be reclaimed.
+ */
+struct freetable {
+ struct file **ft_table;
+ SLIST_ENTRY(freetable) ft_next;
+};
+
+/*
+ * Basic allocation of descriptors:
+ * one of the above, plus arrays for NDFILE descriptors.
+ */
+struct filedesc0 {
+ struct filedesc fd_fd;
+ /*
+ * ofiles which need to be reclaimed on free.
+ */
+ SLIST_HEAD(,freetable) fd_free;
+ /*
+ * These arrays are used when the number of open files is
+ * <= NDFILE, and are then pointed to by the pointers above.
+ */
+ struct file *fd_dfiles[NDFILE];
+ char fd_dfileflags[NDFILE];
+ NDSLOTTYPE fd_dmap[NDSLOTS(NDFILE)];
+};
+
+/*
+ * Descriptor management.
+ */
volatile int openfiles; /* actual number of open files */
+struct mtx sigio_lock; /* mtx to protect pointers to sigio */
+void (*mq_fdclose)(struct thread *td, int fd, struct file *fp);
/* A mutex to protect the association between a proc and filedesc. */
static struct mtx fdesc_mtx;
+/*
+ * Find the first zero bit in the given bitmap, starting at low and not
+ * exceeding size - 1.
+ */
+static int
+fd_first_free(struct filedesc *fdp, int low, int size)
+{
+ NDSLOTTYPE *map = fdp->fd_map;
+ NDSLOTTYPE mask;
+ int off, maxoff;
+
+ if (low >= size)
+ return (low);
+
+ off = NDSLOT(low);
+ if (low % NDENTRIES) {
+ mask = ~(~(NDSLOTTYPE)0 >> (NDENTRIES - (low % NDENTRIES)));
+ if ((mask &= ~map[off]) != 0UL)
+ return (off * NDENTRIES + ffsl(mask) - 1);
+ ++off;
+ }
+ for (maxoff = NDSLOTS(size); off < maxoff; ++off)
+ if (map[off] != ~0UL)
+ return (off * NDENTRIES + ffsl(~map[off]) - 1);
+ return (size);
+}
+
+/*
+ * Find the highest non-zero bit in the given bitmap, starting at low and
+ * not exceeding size - 1.
+ */
+static int
+fd_last_used(struct filedesc *fdp, int low, int size)
+{
+ NDSLOTTYPE *map = fdp->fd_map;
+ NDSLOTTYPE mask;
+ int off, minoff;
+
+ if (low >= size)
+ return (-1);
+
+ off = NDSLOT(size);
+ if (size % NDENTRIES) {
+ mask = ~(~(NDSLOTTYPE)0 << (size % NDENTRIES));
+ if ((mask &= map[off]) != 0)
+ return (off * NDENTRIES + flsl(mask) - 1);
+ --off;
+ }
+ for (minoff = NDSLOT(low); off >= minoff; --off)
+ if (map[off] != 0)
+ return (off * NDENTRIES + flsl(map[off]) - 1);
+ return (low - 1);
+}
+
+static int
+fdisused(struct filedesc *fdp, int fd)
+{
+ KASSERT(fd >= 0 && fd < fdp->fd_nfiles,
+ ("file descriptor %d out of range (0, %d)", fd, fdp->fd_nfiles));
+ return ((fdp->fd_map[NDSLOT(fd)] & NDBIT(fd)) != 0);
+}
+
+/*
+ * Mark a file descriptor as used.
+ */
+static void
+fdused(struct filedesc *fdp, int fd)
+{
+
+ FILEDESC_XLOCK_ASSERT(fdp);
+ KASSERT(!fdisused(fdp, fd),
+ ("fd already used"));
+
+ fdp->fd_map[NDSLOT(fd)] |= NDBIT(fd);
+ if (fd > fdp->fd_lastfile)
+ fdp->fd_lastfile = fd;
+ if (fd == fdp->fd_freefile)
+ fdp->fd_freefile = fd_first_free(fdp, fd, fdp->fd_nfiles);
+}
+
+/*
+ * Mark a file descriptor as unused.
+ */
+static void
+fdunused(struct filedesc *fdp, int fd)
+{
+
+ FILEDESC_XLOCK_ASSERT(fdp);
+ KASSERT(fdisused(fdp, fd),
+ ("fd is already unused"));
+ KASSERT(fdp->fd_ofiles[fd] == NULL,
+ ("fd is still in use"));
+
+ fdp->fd_map[NDSLOT(fd)] &= ~NDBIT(fd);
+ if (fd < fdp->fd_freefile)
+ fdp->fd_freefile = fd;
+ if (fd == fdp->fd_lastfile)
+ fdp->fd_lastfile = fd_last_used(fdp, 0, fd);
+}
+
+/*
+ * System calls on descriptors.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct getdtablesize_args {
+ int dummy;
+};
+#endif
+/* ARGSUSED */
+int
+getdtablesize(struct thread *td, struct getdtablesize_args *uap)
+{
+ struct proc *p = td->td_proc;
+
+ PROC_LOCK(p);
+ td->td_retval[0] =
+ min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc);
+ PROC_UNLOCK(p);
+ return (0);
+}
+
+/*
+ * Duplicate a file descriptor to a particular value.
+ *
+ * Note: keep in mind that a potential race condition exists when closing
+ * descriptors from a shared descriptor table (via rfork).
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct dup2_args {
+ u_int from;
+ u_int to;
+};
+#endif
+/* ARGSUSED */
+int
+dup2(struct thread *td, struct dup2_args *uap)
+{
+
+ return (do_dup(td, DUP_FIXED, (int)uap->from, (int)uap->to,
+ td->td_retval));
+}
+
+/*
+ * Duplicate a file descriptor.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct dup_args {
+ u_int fd;
+};
+#endif
+/* ARGSUSED */
+int
+dup(struct thread *td, struct dup_args *uap)
+{
+
+ return (do_dup(td, 0, (int)uap->fd, 0, td->td_retval));
+}
+
+/*
+ * The file control system call.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct fcntl_args {
+ int fd;
+ int cmd;
+ long arg;
+};
+#endif
+/* ARGSUSED */
+int
+fcntl(struct thread *td, struct fcntl_args *uap)
+{
+ struct flock fl;
+ struct oflock ofl;
+ intptr_t arg;
+ int error;
+ int cmd;
+
+ error = 0;
+ cmd = uap->cmd;
+ switch (uap->cmd) {
+ case F_OGETLK:
+ case F_OSETLK:
+ case F_OSETLKW:
+ /*
+ * Convert old flock structure to new.
+ */
+ error = copyin((void *)(intptr_t)uap->arg, &ofl, sizeof(ofl));
+ fl.l_start = ofl.l_start;
+ fl.l_len = ofl.l_len;
+ fl.l_pid = ofl.l_pid;
+ fl.l_type = ofl.l_type;
+ fl.l_whence = ofl.l_whence;
+ fl.l_sysid = 0;
+
+ switch (uap->cmd) {
+ case F_OGETLK:
+ cmd = F_GETLK;
+ break;
+ case F_OSETLK:
+ cmd = F_SETLK;
+ break;
+ case F_OSETLKW:
+ cmd = F_SETLKW;
+ break;
+ }
+ arg = (intptr_t)&fl;
+ break;
+ case F_GETLK:
+ case F_SETLK:
+ case F_SETLKW:
+ case F_SETLK_REMOTE:
+ error = copyin((void *)(intptr_t)uap->arg, &fl, sizeof(fl));
+ arg = (intptr_t)&fl;
+ break;
+ default:
+ arg = uap->arg;
+ break;
+ }
+ if (error)
+ return (error);
+ error = kern_fcntl(td, uap->fd, cmd, arg);
+ if (error)
+ return (error);
+ if (uap->cmd == F_OGETLK) {
+ ofl.l_start = fl.l_start;
+ ofl.l_len = fl.l_len;
+ ofl.l_pid = fl.l_pid;
+ ofl.l_type = fl.l_type;
+ ofl.l_whence = fl.l_whence;
+ error = copyout(&ofl, (void *)(intptr_t)uap->arg, sizeof(ofl));
+ } else if (uap->cmd == F_GETLK) {
+ error = copyout(&fl, (void *)(intptr_t)uap->arg, sizeof(fl));
+ }
+ return (error);
+}
+
+static inline struct file *
+fdtofp(int fd, struct filedesc *fdp)
+{
+ struct file *fp;
+
+ FILEDESC_LOCK_ASSERT(fdp);
+ if ((unsigned)fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL)
+ return (NULL);
+ return (fp);
+}
+
+int
+kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
+{
+ struct filedesc *fdp;
+ struct flock *flp;
+ struct file *fp;
+ struct proc *p;
+ char *pop;
+ struct vnode *vp;
+ int error, flg, tmp;
+ int vfslocked;
+ u_int old, new;
+ uint64_t bsize;
+
+ vfslocked = 0;
+ error = 0;
+ flg = F_POSIX;
+ p = td->td_proc;
+ fdp = p->p_fd;
+
+ switch (cmd) {
+ case F_DUPFD:
+ tmp = arg;
+ error = do_dup(td, DUP_FCNTL, fd, tmp, td->td_retval);
+ break;
+
+ case F_DUP2FD:
+ tmp = arg;
+ error = do_dup(td, DUP_FIXED, fd, tmp, td->td_retval);
+ break;
+
+ case F_GETFD:
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ pop = &fdp->fd_ofileflags[fd];
+ td->td_retval[0] = (*pop & UF_EXCLOSE) ? FD_CLOEXEC : 0;
+ FILEDESC_SUNLOCK(fdp);
+ break;
+
+ case F_SETFD:
+ FILEDESC_XLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_XUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ pop = &fdp->fd_ofileflags[fd];
+ *pop = (*pop &~ UF_EXCLOSE) |
+ (arg & FD_CLOEXEC ? UF_EXCLOSE : 0);
+ FILEDESC_XUNLOCK(fdp);
+ break;
+
+ case F_GETFL:
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ td->td_retval[0] = OFLAGS(fp->f_flag);
+ FILEDESC_SUNLOCK(fdp);
+ break;
+
+ case F_SETFL:
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ fhold(fp);
+ FILEDESC_SUNLOCK(fdp);
+ do {
+ tmp = flg = fp->f_flag;
+ tmp &= ~FCNTLFLAGS;
+ tmp |= FFLAGS(arg & ~O_ACCMODE) & FCNTLFLAGS;
+ } while(atomic_cmpset_int(&fp->f_flag, flg, tmp) == 0);
+ tmp = fp->f_flag & FNONBLOCK;
+ error = fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td);
+ if (error) {
+ fdrop(fp, td);
+ break;
+ }
+ tmp = fp->f_flag & FASYNC;
+ error = fo_ioctl(fp, FIOASYNC, &tmp, td->td_ucred, td);
+ if (error == 0) {
+ fdrop(fp, td);
+ break;
+ }
+ atomic_clear_int(&fp->f_flag, FNONBLOCK);
+ tmp = 0;
+ (void)fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td);
+ fdrop(fp, td);
+ break;
+
+ case F_GETOWN:
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ fhold(fp);
+ FILEDESC_SUNLOCK(fdp);
+ error = fo_ioctl(fp, FIOGETOWN, &tmp, td->td_ucred, td);
+ if (error == 0)
+ td->td_retval[0] = tmp;
+ fdrop(fp, td);
+ break;
+
+ case F_SETOWN:
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ fhold(fp);
+ FILEDESC_SUNLOCK(fdp);
+ tmp = arg;
+ error = fo_ioctl(fp, FIOSETOWN, &tmp, td->td_ucred, td);
+ fdrop(fp, td);
+ break;
+
+ case F_SETLK_REMOTE:
+ error = priv_check(td, PRIV_NFS_LOCKD);
+ if (error)
+ return (error);
+ flg = F_REMOTE;
+ goto do_setlk;
+
+ case F_SETLKW:
+ flg |= F_WAIT;
+ /* FALLTHROUGH F_SETLK */
+
+ case F_SETLK:
+ do_setlk:
+ FILEDESC_SLOCK(fdp);
+ if ((fp = fdtofp(fd, fdp)) == NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ if (fp->f_type != DTYPE_VNODE) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EBADF;
+ break;
+ }
+ flp = (struct flock *)arg;
+ if (flp->l_whence == SEEK_CUR) {
+ if (fp->f_offset < 0 ||
+ (flp->l_start > 0 &&
+ fp->f_offset > OFF_MAX - flp->l_start)) {
+ FILEDESC_SUNLOCK(fdp);
+ error = EOVERFLOW;
+ break;
+ }
+ flp->l_start += fp->f_offset;
+ }
+
+ FILEDESC_SUNLOCK(fdp);
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+/*
+ * Common code for dup, dup2, fcntl(F_DUPFD) and fcntl(F_DUP2FD).
+ */
+static int
+do_dup(struct thread *td, int flags, int old, int new,
+ register_t *retval)
+{
+ struct filedesc *fdp;
+ struct proc *p;
+ struct file *fp;
+ struct file *delfp;
+ int error, holdleaders, maxfd;
+
+ p = td->td_proc;
+ fdp = p->p_fd;
+
+ /*
+ * Verify we have a valid descriptor to dup from and possibly to
+ * dup to. Unlike dup() and dup2(), fcntl()'s F_DUPFD should
+ * return EINVAL when the new descriptor is out of bounds.
+ */
+ if (old < 0)
+ return (EBADF);
+ if (new < 0)
+ return (flags & DUP_FCNTL ? EINVAL : EBADF);
+ PROC_LOCK(p);
+ maxfd = min((int)lim_cur(p, RLIMIT_NOFILE), maxfilesperproc);
+ PROC_UNLOCK(p);
+ if (new >= maxfd)
+ return (flags & DUP_FCNTL ? EINVAL : EMFILE);
+
+ FILEDESC_XLOCK(fdp);
+ if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL) {
+ FILEDESC_XUNLOCK(fdp);
+ return (EBADF);
+ }
+ if (flags & DUP_FIXED && old == new) {
+ *retval = new;
+ FILEDESC_XUNLOCK(fdp);
+ return (0);
+ }
+ fp = fdp->fd_ofiles[old];
+ fhold(fp);
+
+ /*
+ * If the caller specified a file descriptor, make sure the file
+ * table is large enough to hold it, and grab it. Otherwise, just
+ * allocate a new descriptor the usual way. Since the filedesc
+ * lock may be temporarily dropped in the process, we have to look
+ * out for a race.
+ */
+ if (flags & DUP_FIXED) {
+ if (new >= fdp->fd_nfiles)
+ fdgrowtable(fdp, new + 1);
+ if (fdp->fd_ofiles[new] == NULL)
+ fdused(fdp, new);
+ } else {
+ if ((error = fdalloc(td, new, &new)) != 0) {
+ FILEDESC_XUNLOCK(fdp);
+ fdrop(fp, td);
+ return (error);
+ }
+ }
+
+ /*
+ * If the old file changed out from under us then treat it as a
+ * bad file descriptor. Userland should do its own locking to
+ * avoid this case.
+ */
+ if (fdp->fd_ofiles[old] != fp) {
+ /* we've allocated a descriptor which we won't use */
+ if (fdp->fd_ofiles[new] == NULL)
+ fdunused(fdp, new);
+ FILEDESC_XUNLOCK(fdp);
+ fdrop(fp, td);
+ return (EBADF);
+ }
+ KASSERT(old != new,
+ ("new fd is same as old"));
+
+ /*
+ * Save info on the descriptor being overwritten. We cannot close
+ * it without introducing an ownership race for the slot, since we
+ * need to drop the filedesc lock to call closef().
+ *
+ * XXX this duplicates parts of close().
+ */
+ delfp = fdp->fd_ofiles[new];
+ holdleaders = 0;
+ if (delfp != NULL) {
+ if (td->td_proc->p_fdtol != NULL) {
+ /*
+ * Ask fdfree() to sleep to ensure that all relevant
+ * process leaders can be traversed in closef().
+ */
+ fdp->fd_holdleaderscount++;
+ holdleaders = 1;
+ }
+ }
+
+ /*
+ * Duplicate the source descriptor
+ */
+ fdp->fd_ofiles[new] = fp;
+ fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
+ if (new > fdp->fd_lastfile)
+ fdp->fd_lastfile = new;
+ *retval = new;
+
+ /*
+ * If we dup'd over a valid file, we now own the reference to it
+ * and must dispose of it using closef() semantics (as if a
+ * close() were performed on it).
+ *
+ * XXX this duplicates parts of close().
+ */
+ if (delfp != NULL) {
+ knote_fdclose(td, new);
+ if (delfp->f_type == DTYPE_MQUEUE)
+ mq_fdclose(td, new, delfp);
+ FILEDESC_XUNLOCK(fdp);
+ (void) closef(delfp, td);
+ if (holdleaders) {
+ FILEDESC_XLOCK(fdp);
+ fdp->fd_holdleaderscount--;
+ if (fdp->fd_holdleaderscount == 0 &&
+ fdp->fd_holdleaderswakeup != 0) {
+ fdp->fd_holdleaderswakeup = 0;
+ wakeup(&fdp->fd_holdleaderscount);
+ }
+ FILEDESC_XUNLOCK(fdp);
+ }
+ } else {
+ FILEDESC_XUNLOCK(fdp);
+ }
+ return (0);
+}
+
+/*
+ * If sigio is on the list associated with a process or process group,
+ * disable signalling from the device, remove sigio from the list and
+ * free sigio.
+ */
+void
+funsetown(struct sigio **sigiop)
+{
+ struct sigio *sigio;
+
+ SIGIO_LOCK();
+ sigio = *sigiop;
+ if (sigio == NULL) {
+ SIGIO_UNLOCK();
+ return;
+ }
+ *(sigio->sio_myref) = NULL;
+ if ((sigio)->sio_pgid < 0) {
+ struct pgrp *pg = (sigio)->sio_pgrp;
+ PGRP_LOCK(pg);
+ SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio,
+ sigio, sio_pgsigio);
+ PGRP_UNLOCK(pg);
+ } else {
+ struct proc *p = (sigio)->sio_proc;
+ PROC_LOCK(p);
+ SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio,
+ sigio, sio_pgsigio);
+ PROC_UNLOCK(p);
+ }
+ SIGIO_UNLOCK();
+ crfree(sigio->sio_ucred);
+ free(sigio, M_SIGIO);
+}
+
+/*
+ * Free a list of sigio structures.
+ * We only need to lock the SIGIO_LOCK because we have made ourselves
+ * inaccessible to callers of fsetown and therefore do not need to lock
+ * the proc or pgrp struct for the list manipulation.
+ */
+void
+funsetownlst(struct sigiolst *sigiolst)
+{
+ struct proc *p;
+ struct pgrp *pg;
+ struct sigio *sigio;
+
+ sigio = SLIST_FIRST(sigiolst);
+ if (sigio == NULL)
+ return;
+ p = NULL;
+ pg = NULL;
+
+ /*
+ * Every entry of the list should belong
+ * to a single proc or pgrp.
+ */
+ if (sigio->sio_pgid < 0) {
+ pg = sigio->sio_pgrp;
+ PGRP_LOCK_ASSERT(pg, MA_NOTOWNED);
+ } else /* if (sigio->sio_pgid > 0) */ {
+ p = sigio->sio_proc;
+ PROC_LOCK_ASSERT(p, MA_NOTOWNED);
+ }
+
+ SIGIO_LOCK();
+ while ((sigio = SLIST_FIRST(sigiolst)) != NULL) {
+ *(sigio->sio_myref) = NULL;
+ if (pg != NULL) {
+ KASSERT(sigio->sio_pgid < 0,
+ ("Proc sigio in pgrp sigio list"));
+ KASSERT(sigio->sio_pgrp == pg,
+ ("Bogus pgrp in sigio list"));
+ PGRP_LOCK(pg);
+ SLIST_REMOVE(&pg->pg_sigiolst, sigio, sigio,
+ sio_pgsigio);
+ PGRP_UNLOCK(pg);
+ } else /* if (p != NULL) */ {
+ KASSERT(sigio->sio_pgid > 0,
+ ("Pgrp sigio in proc sigio list"));
+ KASSERT(sigio->sio_proc == p,
+ ("Bogus proc in sigio list"));
+ PROC_LOCK(p);
+ SLIST_REMOVE(&p->p_sigiolst, sigio, sigio,
+ sio_pgsigio);
+ PROC_UNLOCK(p);
+ }
+ SIGIO_UNLOCK();
+ crfree(sigio->sio_ucred);
+ free(sigio, M_SIGIO);
+ SIGIO_LOCK();
+ }
+ SIGIO_UNLOCK();
+}
/*
* This is common code for FIOSETOWN ioctl called by fcntl(fd, F_SETOWN, arg).
@@ -95,25 +828,388 @@ static struct mtx fdesc_mtx;
int
fsetown(pid_t pgid, struct sigio **sigiop)
{
+ struct proc *proc;
+ struct pgrp *pgrp;
+ struct sigio *sigio;
+ int ret;
+
+ if (pgid == 0) {
+ funsetown(sigiop);
+ return (0);
+ }
+ ret = 0;
+
+ /* Allocate and fill in the new sigio out of locks. */
+ sigio = malloc(sizeof(struct sigio), M_SIGIO, M_WAITOK);
+ sigio->sio_pgid = pgid;
+ sigio->sio_ucred = crhold(curthread->td_ucred);
+ sigio->sio_myref = sigiop;
+
+ SIGIO_LOCK();
+ *sigiop = sigio;
+ SIGIO_UNLOCK();
return (0);
+
+fail:
+ sx_sunlock(&proctree_lock);
+ crfree(sigio->sio_ucred);
+ free(sigio, M_SIGIO);
+ return (ret);
}
-
+
+/*
+ * This is common code for FIOGETOWN ioctl called by fcntl(fd, F_GETOWN, arg).
+ */
pid_t
-fgetown(struct sigio **sigiop)
+fgetown(sigiop)
+ struct sigio **sigiop;
+{
+ pid_t pgid;
+
+ SIGIO_LOCK();
+ pgid = (*sigiop != NULL) ? (*sigiop)->sio_pgid : 0;
+ SIGIO_UNLOCK();
+ return (pgid);
+}
+
+/*
+ * Close a file descriptor.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct close_args {
+ int fd;
+};
+#endif
+/* ARGSUSED */
+int
+close(td, uap)
+ struct thread *td;
+ struct close_args *uap;
+{
+
+ return (kern_close(td, uap->fd));
+}
+
+int
+kern_close(td, fd)
+ struct thread *td;
+ int fd;
+{
+ struct filedesc *fdp;
+ struct file *fp;
+ int error;
+ int holdleaders;
+
+ error = 0;
+ holdleaders = 0;
+ fdp = td->td_proc->p_fd;
+
+ AUDIT_SYSCLOSE(td, fd);
+
+ FILEDESC_XLOCK(fdp);
+ if ((unsigned)fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL) {
+ FILEDESC_XUNLOCK(fdp);
+ return (EBADF);
+ }
+ fdp->fd_ofiles[fd] = NULL;
+ fdp->fd_ofileflags[fd] = 0;
+ fdunused(fdp, fd);
+ if (td->td_proc->p_fdtol != NULL) {
+ /*
+ * Ask fdfree() to sleep to ensure that all relevant
+ * process leaders can be traversed in closef().
+ */
+ fdp->fd_holdleaderscount++;
+ holdleaders = 1;
+ }
+
+ /*
+ * We now hold the fp reference that used to be owned by the
+ * descriptor array. We have to unlock the FILEDESC *AFTER*
+ * knote_fdclose to prevent a race of the fd getting opened, a knote
+ * added, and deleteing a knote for the new fd.
+ */
+ knote_fdclose(td, fd);
+ if (fp->f_type == DTYPE_MQUEUE)
+ mq_fdclose(td, fd, fp);
+ FILEDESC_XUNLOCK(fdp);
+
+ error = closef(fp, td);
+ if (holdleaders) {
+ FILEDESC_XLOCK(fdp);
+ fdp->fd_holdleaderscount--;
+ if (fdp->fd_holdleaderscount == 0 &&
+ fdp->fd_holdleaderswakeup != 0) {
+ fdp->fd_holdleaderswakeup = 0;
+ wakeup(&fdp->fd_holdleaderscount);
+ }
+ FILEDESC_XUNLOCK(fdp);
+ }
+ return (error);
+}
+
+/*
+ * Close open file descriptors.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct closefrom_args {
+ int lowfd;
+};
+#endif
+/* ARGSUSED */
+int
+closefrom(struct thread *td, struct closefrom_args *uap)
+{
+ struct filedesc *fdp;
+ int fd;
+
+ fdp = td->td_proc->p_fd;
+ AUDIT_ARG_FD(uap->lowfd);
+
+ /*
+ * Treat negative starting file descriptor values identical to
+ * closefrom(0) which closes all files.
+ */
+ if (uap->lowfd < 0)
+ uap->lowfd = 0;
+ FILEDESC_SLOCK(fdp);
+ for (fd = uap->lowfd; fd < fdp->fd_nfiles; fd++) {
+ if (fdp->fd_ofiles[fd] != NULL) {
+ FILEDESC_SUNLOCK(fdp);
+ (void)kern_close(td, fd);
+ FILEDESC_SLOCK(fdp);
+ }
+ }
+ FILEDESC_SUNLOCK(fdp);
+ return (0);
+}
+
+#if defined(COMPAT_43)
+/*
+ * Return status information about a file descriptor.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct ofstat_args {
+ int fd;
+ struct ostat *sb;
+};
+#endif
+/* ARGSUSED */
+int
+ofstat(struct thread *td, struct ofstat_args *uap)
{
+ struct ostat oub;
+ struct stat ub;
+ int error;
+
+ error = kern_fstat(td, uap->fd, &ub);
+ if (error == 0) {
+ cvtstat(&ub, &oub);
+ error = copyout(&oub, uap->sb, sizeof(oub));
+ }
+ return (error);
+}
+#endif /* COMPAT_43 */
+
+/*
+ * Return status information about a file descriptor.
+ */
+#ifndef _SYS_SYSPROTO_H_
+struct fstat_args {
+ int fd;
+ struct stat *sb;
+};
+#endif
+/* ARGSUSED */
+int
+fstat(struct thread *td, struct fstat_args *uap)
+{
+ struct stat ub;
+ int error;
+
+ error = kern_fstat(td, uap->fd, &ub);
+ if (error == 0)
+ error = copyout(&ub, uap->sb, sizeof(ub));
+ return (error);
+}
+
+int
+kern_fstat(struct thread *td, int fd, struct stat *sbp)
+{
+ struct file *fp;
+ int error;
+
+ AUDIT_ARG_FD(fd);
+
+ if ((error = fget(td, fd, &fp)) != 0)
+ return (error);
+
+ AUDIT_ARG_FILE(td->td_proc, fp);
+
+ error = fo_stat(fp, sbp, td->td_ucred, td);
+ fdrop(fp, td);
+#ifdef KTRACE
+ if (error == 0 && KTRPOINT(td, KTR_STRUCT))
+ ktrstat(sbp);
+#endif
+ return (error);
+}
+
+/*
+ * Grow the file table to accomodate (at least) nfd descriptors. This may
+ * block and drop the filedesc lock, but it will reacquire it before
+ * returning.
+ */
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-user
mailing list