Date: Mon, 11 Jan 2010 00:51:25 +0000 (UTC) From: Kip Macy <kmacy@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r202058 - user/kmacy/releng_8_rump/lib/libunet Message-ID: <201001110051.o0B0pPs8094395@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201001110051.o0B0pPs8094395>