2009-12-20 12:36:05 +03:00
|
|
|
/* $NetBSD: kern_descrip.c,v 1.202 2009/12/20 09:36:05 dsl Exp $ */
|
2008-03-22 00:53:35 +03:00
|
|
|
|
|
|
|
/*-
|
2009-04-04 14:12:51 +04:00
|
|
|
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
|
2008-03-22 00:53:35 +03:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
2009-04-04 14:12:51 +04:00
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
|
|
* by Andrew Doran.
|
|
|
|
*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1994-05-17 08:21:49 +04:00
|
|
|
/*
|
1994-05-19 12:13:09 +04:00
|
|
|
* Copyright (c) 1982, 1986, 1989, 1991, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
1994-05-17 08:21:49 +04:00
|
|
|
* (c) UNIX System Laboratories, Inc.
|
|
|
|
* All or some portions of this file are derived from material licensed
|
|
|
|
* to the University of California by American Telephone and Telegraph
|
|
|
|
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
|
|
|
* the permission of UNIX System Laboratories, Inc.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2003-08-07 20:26:28 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1994-05-17 08:21:49 +04:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1998-03-01 05:20:01 +03:00
|
|
|
* @(#)kern_descrip.c 8.8 (Berkeley) 2/14/95
|
1994-05-17 08:21:49 +04:00
|
|
|
*/
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* File descriptor management.
|
|
|
|
*/
|
|
|
|
|
2001-11-12 18:25:01 +03:00
|
|
|
#include <sys/cdefs.h>
|
2009-12-20 12:36:05 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: kern_descrip.c,v 1.202 2009/12/20 09:36:05 dsl Exp $");
|
2001-11-12 18:25:01 +03:00
|
|
|
|
1994-05-17 08:21:49 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/filedesc.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/socketvar.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/fcntl.h>
|
1998-09-01 03:55:37 +04:00
|
|
|
#include <sys/pool.h>
|
1994-05-19 12:13:09 +04:00
|
|
|
#include <sys/unistd.h>
|
1994-05-17 08:21:49 +04:00
|
|
|
#include <sys/resourcevar.h>
|
1996-03-31 01:24:38 +03:00
|
|
|
#include <sys/conf.h>
|
2002-10-23 13:10:23 +04:00
|
|
|
#include <sys/event.h>
|
2006-05-15 01:15:11 +04:00
|
|
|
#include <sys/kauth.h>
|
2007-11-29 21:15:14 +03:00
|
|
|
#include <sys/atomic.h>
|
1994-10-20 07:22:35 +03:00
|
|
|
#include <sys/syscallargs.h>
|
2008-04-24 19:35:27 +04:00
|
|
|
#include <sys/cpu.h>
|
2008-11-18 16:01:41 +03:00
|
|
|
#include <sys/kmem.h>
|
|
|
|
#include <sys/vnode.h>
|
1994-10-20 07:22:35 +03:00
|
|
|
|
2007-12-26 19:01:34 +03:00
|
|
|
static int file_ctor(void *, void *, int);
|
|
|
|
static void file_dtor(void *, void *);
|
2008-03-22 00:53:35 +03:00
|
|
|
static int fdfile_ctor(void *, void *, int);
|
|
|
|
static void fdfile_dtor(void *, void *);
|
|
|
|
static int filedesc_ctor(void *, void *, int);
|
|
|
|
static void filedesc_dtor(void *, void *);
|
|
|
|
static int filedescopen(dev_t, int, int, lwp_t *);
|
2007-11-07 03:23:13 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
kmutex_t filelist_lock; /* lock on filehead */
|
2001-02-26 23:24:30 +03:00
|
|
|
struct filelist filehead; /* head of list of open files */
|
2007-12-26 19:01:34 +03:00
|
|
|
u_int nfiles; /* actual number of open files */
|
2007-10-08 19:12:05 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
static pool_cache_t filedesc_cache;
|
2007-11-07 03:23:13 +03:00
|
|
|
static pool_cache_t file_cache;
|
2008-03-22 00:53:35 +03:00
|
|
|
static pool_cache_t fdfile_cache;
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
const struct cdevsw filedesc_cdevsw = {
|
|
|
|
filedescopen, noclose, noread, nowrite, noioctl,
|
|
|
|
nostop, notty, nopoll, nommap, nokqfilter, D_OTHER | D_MPSAFE,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* For ease of reading. */
|
|
|
|
__strong_alias(fd_putvnode,fd_putfile)
|
|
|
|
__strong_alias(fd_putsock,fd_putfile)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the descriptor system.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
fd_sys_init(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
mutex_init(&filelist_lock, MUTEX_DEFAULT, IPL_NONE);
|
|
|
|
|
2008-03-27 21:30:15 +03:00
|
|
|
file_cache = pool_cache_init(sizeof(file_t), coherency_unit, 0,
|
2008-03-22 00:53:35 +03:00
|
|
|
0, "file", NULL, IPL_NONE, file_ctor, file_dtor, NULL);
|
|
|
|
KASSERT(file_cache != NULL);
|
|
|
|
|
2008-03-27 21:30:15 +03:00
|
|
|
fdfile_cache = pool_cache_init(sizeof(fdfile_t), coherency_unit, 0,
|
2008-03-22 00:53:35 +03:00
|
|
|
PR_LARGECACHE, "fdfile", NULL, IPL_NONE, fdfile_ctor, fdfile_dtor,
|
|
|
|
NULL);
|
|
|
|
KASSERT(fdfile_cache != NULL);
|
|
|
|
|
2008-03-27 21:30:15 +03:00
|
|
|
filedesc_cache = pool_cache_init(sizeof(filedesc_t), coherency_unit,
|
2008-03-22 00:53:35 +03:00
|
|
|
0, 0, "filedesc", NULL, IPL_NONE, filedesc_ctor, filedesc_dtor,
|
|
|
|
NULL);
|
|
|
|
KASSERT(filedesc_cache != NULL);
|
|
|
|
}
|
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
static bool
|
|
|
|
fd_isused(filedesc_t *fdp, unsigned fd)
|
|
|
|
{
|
|
|
|
u_int off = fd >> NDENTRYSHIFT;
|
|
|
|
|
|
|
|
KASSERT(fd < fdp->fd_dt->dt_nfiles);
|
|
|
|
|
|
|
|
return (fdp->fd_lomap[off] & (1 << (fd & NDENTRYMASK))) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify that the bitmaps match the descriptor table.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
fd_checkmaps(filedesc_t *fdp)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
fdtab_t *dt;
|
|
|
|
u_int fd;
|
|
|
|
|
|
|
|
dt = fdp->fd_dt;
|
2009-06-07 13:39:02 +04:00
|
|
|
if (fdp->fd_refcnt == -1) {
|
|
|
|
/*
|
|
|
|
* fd_free tears down the table without maintaining its bitmap.
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
for (fd = 0; fd < dt->dt_nfiles; fd++) {
|
|
|
|
if (fd < NDFDFILE) {
|
|
|
|
KASSERT(dt->dt_ff[fd] ==
|
|
|
|
(fdfile_t *)fdp->fd_dfdfile[fd]);
|
|
|
|
}
|
|
|
|
if (dt->dt_ff[fd] == NULL) {
|
|
|
|
KASSERT(!fd_isused(fdp, fd));
|
|
|
|
} else if (dt->dt_ff[fd]->ff_file != NULL) {
|
|
|
|
KASSERT(fd_isused(fdp, fd));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else /* DEBUG */
|
|
|
|
/* nothing */
|
|
|
|
#endif /* DEBUG */
|
|
|
|
}
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
static int
|
|
|
|
fd_next_zero(filedesc_t *fdp, uint32_t *bitmap, int want, u_int bits)
|
2003-10-30 10:27:02 +03:00
|
|
|
{
|
|
|
|
int i, off, maxoff;
|
|
|
|
uint32_t sub;
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(mutex_owned(&fdp->fd_lock));
|
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_checkmaps(fdp);
|
|
|
|
|
2003-10-30 10:27:02 +03:00
|
|
|
if (want > bits)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
off = want >> NDENTRYSHIFT;
|
|
|
|
i = want & NDENTRYMASK;
|
|
|
|
if (i) {
|
|
|
|
sub = bitmap[off] | ((u_int)~0 >> (NDENTRIES - i));
|
|
|
|
if (sub != ~0)
|
|
|
|
goto found;
|
|
|
|
off++;
|
|
|
|
}
|
|
|
|
|
|
|
|
maxoff = NDLOSLOTS(bits);
|
|
|
|
while (off < maxoff) {
|
|
|
|
if ((sub = bitmap[off]) != ~0)
|
|
|
|
goto found;
|
|
|
|
off++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (-1);
|
|
|
|
|
|
|
|
found:
|
|
|
|
return (off << NDENTRYSHIFT) + ffs(~sub) - 1;
|
|
|
|
}
|
|
|
|
|
2005-06-24 03:15:12 +04:00
|
|
|
static int
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_last_set(filedesc_t *fd, int last)
|
2003-10-30 10:27:02 +03:00
|
|
|
{
|
|
|
|
int off, i;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdfile_t **ff = fd->fd_dt->dt_ff;
|
2003-10-30 10:27:02 +03:00
|
|
|
uint32_t *bitmap = fd->fd_lomap;
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(mutex_owned(&fd->fd_lock));
|
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_checkmaps(fd);
|
|
|
|
|
2003-10-30 10:27:02 +03:00
|
|
|
off = (last - 1) >> NDENTRYSHIFT;
|
|
|
|
|
2003-11-30 21:16:45 +03:00
|
|
|
while (off >= 0 && !bitmap[off])
|
2003-10-30 10:27:02 +03:00
|
|
|
off--;
|
|
|
|
|
|
|
|
if (off < 0)
|
2005-01-12 23:41:45 +03:00
|
|
|
return (-1);
|
2005-02-27 00:34:55 +03:00
|
|
|
|
2003-10-30 10:27:02 +03:00
|
|
|
i = ((off + 1) << NDENTRYSHIFT) - 1;
|
|
|
|
if (i >= last)
|
|
|
|
i = last - 1;
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/* XXX should use bitmap */
|
2009-05-25 01:41:25 +04:00
|
|
|
while (i > 0 && (ff[i] == NULL || !ff[i]->ff_allocated))
|
2003-10-30 10:27:02 +03:00
|
|
|
i--;
|
|
|
|
|
|
|
|
return (i);
|
|
|
|
}
|
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
static inline void
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_used(filedesc_t *fdp, unsigned fd)
|
1994-12-04 06:09:50 +03:00
|
|
|
{
|
2003-10-30 10:27:02 +03:00
|
|
|
u_int off = fd >> NDENTRYSHIFT;
|
2008-03-22 00:53:35 +03:00
|
|
|
fdfile_t *ff;
|
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
ff = fdp->fd_dt->dt_ff[fd];
|
2003-10-30 10:27:02 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(mutex_owned(&fdp->fd_lock));
|
|
|
|
KASSERT((fdp->fd_lomap[off] & (1 << (fd & NDENTRYMASK))) == 0);
|
|
|
|
KASSERT(ff != NULL);
|
|
|
|
KASSERT(ff->ff_file == NULL);
|
|
|
|
KASSERT(!ff->ff_allocated);
|
2004-04-05 14:10:29 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
ff->ff_allocated = 1;
|
2003-10-30 10:27:02 +03:00
|
|
|
fdp->fd_lomap[off] |= 1 << (fd & NDENTRYMASK);
|
2009-05-25 01:41:25 +04:00
|
|
|
if (__predict_false(fdp->fd_lomap[off] == ~0)) {
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT((fdp->fd_himap[off >> NDENTRYSHIFT] &
|
2004-04-05 14:10:29 +04:00
|
|
|
(1 << (off & NDENTRYMASK))) == 0);
|
2003-10-30 10:27:02 +03:00
|
|
|
fdp->fd_himap[off >> NDENTRYSHIFT] |= 1 << (off & NDENTRYMASK);
|
2004-04-05 14:10:29 +04:00
|
|
|
}
|
1994-12-04 06:09:50 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
if ((int)fd > fdp->fd_lastfile) {
|
1994-12-04 06:09:50 +03:00
|
|
|
fdp->fd_lastfile = fd;
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_checkmaps(fdp);
|
1994-12-04 06:09:50 +03:00
|
|
|
}
|
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
static inline void
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_unused(filedesc_t *fdp, unsigned fd)
|
1994-12-04 06:09:50 +03:00
|
|
|
{
|
2003-10-30 10:27:02 +03:00
|
|
|
u_int off = fd >> NDENTRYSHIFT;
|
2008-03-22 00:53:35 +03:00
|
|
|
fdfile_t *ff;
|
1994-12-04 06:09:50 +03:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
ff = fdp->fd_dt->dt_ff[fd];
|
2008-03-22 00:53:35 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't assert the lock is held here, as we may be copying
|
|
|
|
* the table during exec() and it is not needed there.
|
|
|
|
* procfs and sysctl are locked out by proc::p_reflock.
|
|
|
|
*
|
|
|
|
* KASSERT(mutex_owned(&fdp->fd_lock));
|
|
|
|
*/
|
|
|
|
KASSERT(ff != NULL);
|
|
|
|
KASSERT(ff->ff_file == NULL);
|
|
|
|
KASSERT(ff->ff_allocated);
|
|
|
|
|
|
|
|
if (fd < fdp->fd_freefile) {
|
1994-12-04 06:09:50 +03:00
|
|
|
fdp->fd_freefile = fd;
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
2003-10-30 10:27:02 +03:00
|
|
|
|
2004-04-05 14:10:29 +04:00
|
|
|
if (fdp->fd_lomap[off] == ~0) {
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT((fdp->fd_himap[off >> NDENTRYSHIFT] &
|
2004-04-05 14:10:29 +04:00
|
|
|
(1 << (off & NDENTRYMASK))) != 0);
|
|
|
|
fdp->fd_himap[off >> NDENTRYSHIFT] &=
|
|
|
|
~(1 << (off & NDENTRYMASK));
|
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT((fdp->fd_lomap[off] & (1 << (fd & NDENTRYMASK))) != 0);
|
2003-10-30 10:27:02 +03:00
|
|
|
fdp->fd_lomap[off] &= ~(1 << (fd & NDENTRYMASK));
|
2008-03-22 00:53:35 +03:00
|
|
|
ff->ff_allocated = 0;
|
2003-10-30 10:27:02 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(fd <= fdp->fd_lastfile);
|
|
|
|
if (fd == fdp->fd_lastfile) {
|
|
|
|
fdp->fd_lastfile = fd_last_set(fdp, fd);
|
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_checkmaps(fdp);
|
2005-06-24 03:15:12 +04:00
|
|
|
}
|
|
|
|
|
2007-10-08 19:12:05 +04:00
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Look up the file structure corresponding to a file descriptor
|
|
|
|
* and return the file, holding a reference on the descriptor.
|
2007-10-08 19:12:05 +04:00
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
inline file_t *
|
|
|
|
fd_getfile(unsigned fd)
|
2007-10-08 19:12:05 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *fdp;
|
|
|
|
fdfile_t *ff;
|
|
|
|
file_t *fp;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdtab_t *dt;
|
2007-10-08 19:12:05 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Look up the fdfile structure representing this descriptor.
|
2009-05-25 01:41:25 +04:00
|
|
|
* We are doing this unlocked. See fd_tryexpand().
|
2008-03-22 00:53:35 +03:00
|
|
|
*/
|
2009-05-25 01:41:25 +04:00
|
|
|
fdp = curlwp->l_fd;
|
|
|
|
dt = fdp->fd_dt;
|
|
|
|
if (__predict_false(fd >= dt->dt_nfiles)) {
|
2008-03-22 00:53:35 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
ff = dt->dt_ff[fd];
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(fd >= NDFDFILE || ff == (fdfile_t *)fdp->fd_dfdfile[fd]);
|
|
|
|
if (__predict_false(ff == NULL)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-10-08 19:12:05 +04:00
|
|
|
|
2009-05-23 22:28:05 +04:00
|
|
|
/* Now get a reference to the descriptor. */
|
|
|
|
if (fdp->fd_refcnt == 1) {
|
|
|
|
/*
|
|
|
|
* Single threaded: don't need to worry about concurrent
|
|
|
|
* access (other than earlier calls to kqueue, which may
|
|
|
|
* hold a reference to the descriptor).
|
|
|
|
*/
|
|
|
|
ff->ff_refcnt++;
|
|
|
|
} else {
|
|
|
|
/*
|
2009-05-25 01:41:25 +04:00
|
|
|
* Multi threaded: issue a memory barrier to ensure that we
|
|
|
|
* acquire the file pointer _after_ adding a reference. If
|
|
|
|
* no memory barrier, we could fetch a stale pointer.
|
2009-05-23 22:28:05 +04:00
|
|
|
*/
|
|
|
|
atomic_inc_uint(&ff->ff_refcnt);
|
2008-03-22 00:53:35 +03:00
|
|
|
#ifndef __HAVE_ATOMIC_AS_MEMBAR
|
2009-05-23 22:28:05 +04:00
|
|
|
membar_enter();
|
2008-03-22 00:53:35 +03:00
|
|
|
#endif
|
2009-05-23 22:28:05 +04:00
|
|
|
}
|
2007-10-08 19:12:05 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* If the file is not open or is being closed then put the
|
|
|
|
* reference back.
|
|
|
|
*/
|
|
|
|
fp = ff->ff_file;
|
|
|
|
if (__predict_true(fp != NULL)) {
|
|
|
|
return fp;
|
|
|
|
}
|
|
|
|
fd_putfile(fd);
|
|
|
|
return NULL;
|
2007-10-08 19:12:05 +04:00
|
|
|
}
|
|
|
|
|
1994-05-17 08:21:49 +04:00
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Release a reference to a file descriptor acquired with fd_getfile().
|
1994-05-17 08:21:49 +04:00
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
void
|
|
|
|
fd_putfile(unsigned fd)
|
1994-05-17 08:21:49 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *fdp;
|
|
|
|
fdfile_t *ff;
|
|
|
|
u_int u, v;
|
2001-02-26 23:24:30 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp = curlwp->l_fd;
|
2009-05-25 01:41:25 +04:00
|
|
|
ff = fdp->fd_dt->dt_ff[fd];
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(fd < fdp->fd_dt->dt_nfiles);
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(ff != NULL);
|
|
|
|
KASSERT((ff->ff_refcnt & FR_MASK) > 0);
|
|
|
|
KASSERT(fd >= NDFDFILE || ff == (fdfile_t *)fdp->fd_dfdfile[fd]);
|
1999-05-06 00:01:01 +04:00
|
|
|
|
2009-05-23 22:28:05 +04:00
|
|
|
if (fdp->fd_refcnt == 1) {
|
|
|
|
/*
|
|
|
|
* Single threaded: don't need to worry about concurrent
|
|
|
|
* access (other than earlier calls to kqueue, which may
|
|
|
|
* hold a reference to the descriptor).
|
|
|
|
*/
|
|
|
|
if (__predict_false((ff->ff_refcnt & FR_CLOSING) != 0)) {
|
|
|
|
fd_close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ff->ff_refcnt--;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Ensure that any use of the file is complete and globally
|
|
|
|
* visible before dropping the final reference. If no membar,
|
|
|
|
* the current CPU could still access memory associated with
|
|
|
|
* the file after it has been freed or recycled by another
|
|
|
|
* CPU.
|
|
|
|
*/
|
|
|
|
#ifndef __HAVE_ATOMIC_AS_MEMBAR
|
|
|
|
membar_exit();
|
|
|
|
#endif
|
1999-05-06 00:01:01 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Be optimistic and start out with the assumption that no other
|
|
|
|
* threads are trying to close the descriptor. If the CAS fails,
|
|
|
|
* we lost a race and/or it's being closed.
|
|
|
|
*/
|
|
|
|
for (u = ff->ff_refcnt & FR_MASK;; u = v) {
|
|
|
|
v = atomic_cas_uint(&ff->ff_refcnt, u, u - 1);
|
|
|
|
if (__predict_true(u == v)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (__predict_false((v & FR_CLOSING) != 0)) {
|
|
|
|
break;
|
Rework fdalloc() even further: split fdalloc() into fdalloc() and
fdexpand(). The former will return ENOSPC if there is not space
in the current filedesc table. The latter performs the expansion
of the filedesc table. This means that fdalloc() won't ever block,
and it gives callers an opportunity to clean up before the
potentially-blocking fdexpand() call.
Update all fdalloc() callers to deal with the need-to-fdexpand() case.
Rewrite unp_externalize() to use fdalloc() and fdexpand() in a
safe way, using an algorithm suggested by Bill Sommerfeld:
- Use a temporary array of integers to hold the new filedesc table
indexes. This allows us to repeat the loop if necessary.
- Loop through the array of file *'s, assigning them to filedesc table
slots. If fdalloc() indicates expansion is necessary, undo the
assignments we've done so far, expand, and retry the whole process.
- Once all file *'s have been assigned to slots, update the f_msgcount
and unp_rights counters.
- Right before we return, copy the temporary integer array to the message
buffer, and trim the length as before.
Note that once locking is added to the filedesc array, this entire
operation will be `atomic', in that the lock will be held while
file *'s are assigned to embryonic table slots, thus preventing anything
else from using them.
2001-06-07 05:29:16 +04:00
|
|
|
}
|
1999-05-06 00:01:01 +04:00
|
|
|
}
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/* Another thread is waiting to close the file: join it. */
|
|
|
|
(void)fd_close(fd);
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Convenience wrapper around fd_getfile() that returns reference
|
|
|
|
* to a vnode.
|
1994-05-17 08:21:49 +04:00
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_getvnode(unsigned fd, file_t **fpp)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
vnode_t *vp;
|
|
|
|
file_t *fp;
|
2001-06-15 00:32:41 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
fp = fd_getfile(fd);
|
|
|
|
if (__predict_false(fp == NULL)) {
|
|
|
|
return EBADF;
|
2003-02-23 17:37:32 +03:00
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
if (__predict_false(fp->f_type != DTYPE_VNODE)) {
|
|
|
|
fd_putfile(fd);
|
|
|
|
return EINVAL;
|
1994-05-19 12:13:09 +04:00
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
vp = fp->f_data;
|
|
|
|
if (__predict_false(vp->v_type == VBAD)) {
|
|
|
|
/* XXX Is this case really necessary? */
|
|
|
|
fd_putfile(fd);
|
|
|
|
return EBADF;
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
*fpp = fp;
|
|
|
|
return 0;
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
|
|
|
|
2005-06-24 03:15:12 +04:00
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Convenience wrapper around fd_getfile() that returns reference
|
|
|
|
* to a socket.
|
2005-06-24 03:15:12 +04:00
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
int
|
|
|
|
fd_getsock(unsigned fd, struct socket **sop)
|
2005-06-24 03:15:12 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
file_t *fp;
|
2005-06-24 03:15:12 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
fp = fd_getfile(fd);
|
|
|
|
if (__predict_false(fp == NULL)) {
|
|
|
|
return EBADF;
|
|
|
|
}
|
|
|
|
if (__predict_false(fp->f_type != DTYPE_SOCKET)) {
|
|
|
|
fd_putfile(fd);
|
|
|
|
return ENOTSOCK;
|
|
|
|
}
|
|
|
|
*sop = fp->f_data;
|
|
|
|
return 0;
|
2005-06-24 03:15:12 +04:00
|
|
|
}
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Look up the file structure corresponding to a file descriptor
|
|
|
|
* and return it with a reference held on the file, not the
|
|
|
|
* descriptor.
|
|
|
|
*
|
|
|
|
* This is heavyweight and only used when accessing descriptors
|
|
|
|
* from a foreign process. The caller must ensure that `p' does
|
|
|
|
* not exit or fork across this call.
|
|
|
|
*
|
|
|
|
* To release the file (not descriptor) reference, use closef().
|
|
|
|
*/
|
|
|
|
file_t *
|
|
|
|
fd_getfile2(proc_t *p, unsigned fd)
|
2007-05-13 03:02:49 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *fdp;
|
|
|
|
fdfile_t *ff;
|
|
|
|
file_t *fp;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdtab_t *dt;
|
2007-05-13 03:02:49 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp = p->p_fd;
|
|
|
|
mutex_enter(&fdp->fd_lock);
|
2009-05-25 01:41:25 +04:00
|
|
|
dt = fdp->fd_dt;
|
|
|
|
if (fd >= dt->dt_nfiles) {
|
2008-03-22 00:53:35 +03:00
|
|
|
mutex_exit(&fdp->fd_lock);
|
|
|
|
return NULL;
|
2007-05-13 03:02:49 +04:00
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
if ((ff = dt->dt_ff[fd]) == NULL) {
|
2008-03-22 00:53:35 +03:00
|
|
|
mutex_exit(&fdp->fd_lock);
|
|
|
|
return NULL;
|
2007-05-13 03:02:49 +04:00
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
if ((fp = ff->ff_file) == NULL) {
|
|
|
|
mutex_exit(&fdp->fd_lock);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
mutex_enter(&fp->f_lock);
|
|
|
|
fp->f_count++;
|
|
|
|
mutex_exit(&fp->f_lock);
|
|
|
|
mutex_exit(&fdp->fd_lock);
|
2007-05-13 03:02:49 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
return fp;
|
2007-05-13 03:02:49 +04:00
|
|
|
}
|
|
|
|
|
1994-05-17 08:21:49 +04:00
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Internal form of close. Must be called with a reference to the
|
|
|
|
* descriptor, and will drop the reference. When all descriptor
|
|
|
|
* references are dropped, releases the descriptor slot and a single
|
|
|
|
* reference to the file structure.
|
1994-05-17 08:21:49 +04:00
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_close(unsigned fd)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
struct flock lf;
|
|
|
|
filedesc_t *fdp;
|
|
|
|
fdfile_t *ff;
|
|
|
|
file_t *fp;
|
|
|
|
proc_t *p;
|
|
|
|
lwp_t *l;
|
2009-05-25 01:41:25 +04:00
|
|
|
u_int refcnt;
|
2008-03-22 00:53:35 +03:00
|
|
|
|
|
|
|
l = curlwp;
|
2003-01-18 13:06:22 +03:00
|
|
|
p = l->l_proc;
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp = l->l_fd;
|
2009-05-25 01:41:25 +04:00
|
|
|
ff = fdp->fd_dt->dt_ff[fd];
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(fd >= NDFDFILE || ff == (fdfile_t *)fdp->fd_dfdfile[fd]);
|
2004-01-05 03:36:49 +03:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
mutex_enter(&fdp->fd_lock);
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT((ff->ff_refcnt & FR_MASK) > 0);
|
2009-05-25 01:41:25 +04:00
|
|
|
if (__predict_false(ff->ff_file == NULL)) {
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Another user of the file is already closing, and is
|
|
|
|
* waiting for other users of the file to drain. Release
|
|
|
|
* our reference, and wake up the closer.
|
|
|
|
*/
|
|
|
|
atomic_dec_uint(&ff->ff_refcnt);
|
|
|
|
cv_broadcast(&ff->ff_closing);
|
2009-05-25 01:41:25 +04:00
|
|
|
mutex_exit(&fdp->fd_lock);
|
2004-01-05 03:36:49 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* An application error, so pretend that the descriptor
|
|
|
|
* was already closed. We can't safely wait for it to
|
|
|
|
* be closed without potentially deadlocking.
|
|
|
|
*/
|
1994-05-17 08:21:49 +04:00
|
|
|
return (EBADF);
|
1999-08-04 00:19:16 +04:00
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT((ff->ff_refcnt & FR_CLOSING) == 0);
|
1999-08-04 00:19:16 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* There may be multiple users of this file within the process.
|
|
|
|
* Notify existing and new users that the file is closing. This
|
|
|
|
* will prevent them from adding additional uses to this file
|
|
|
|
* while we are closing it.
|
|
|
|
*/
|
|
|
|
fp = ff->ff_file;
|
|
|
|
ff->ff_file = NULL;
|
2008-07-02 20:45:19 +04:00
|
|
|
ff->ff_exclose = false;
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* We expect the caller to hold a descriptor reference - drop it.
|
|
|
|
* The reference count may increase beyond zero at this point due
|
|
|
|
* to an erroneous descriptor reference by an application, but
|
|
|
|
* fd_getfile() will notice that the file is being closed and drop
|
|
|
|
* the reference again.
|
|
|
|
*/
|
2009-05-25 01:41:25 +04:00
|
|
|
if (fdp->fd_refcnt == 1) {
|
|
|
|
/* Single threaded. */
|
|
|
|
refcnt = --(ff->ff_refcnt);
|
|
|
|
} else {
|
|
|
|
/* Multi threaded. */
|
2008-03-22 00:53:35 +03:00
|
|
|
#ifndef __HAVE_ATOMIC_AS_MEMBAR
|
2009-05-25 01:41:25 +04:00
|
|
|
membar_producer();
|
2008-03-22 00:53:35 +03:00
|
|
|
#endif
|
2009-05-25 01:41:25 +04:00
|
|
|
refcnt = atomic_dec_uint_nv(&ff->ff_refcnt);
|
|
|
|
}
|
|
|
|
if (__predict_false(refcnt != 0)) {
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Wait for other references to drain. This is typically
|
|
|
|
* an application error - the descriptor is being closed
|
|
|
|
* while still in use.
|
2009-12-20 12:36:05 +03:00
|
|
|
* (Or just a threaded application trying to unblock its
|
|
|
|
* thread that sleeps in (say) accept()).
|
2008-03-22 00:53:35 +03:00
|
|
|
*/
|
|
|
|
atomic_or_uint(&ff->ff_refcnt, FR_CLOSING);
|
2009-04-04 14:12:51 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Remove any knotes attached to the file. A knote
|
|
|
|
* attached to the descriptor can hold references on it.
|
|
|
|
*/
|
2009-05-25 01:41:25 +04:00
|
|
|
mutex_exit(&fdp->fd_lock);
|
2008-03-22 00:53:35 +03:00
|
|
|
if (!SLIST_EMPTY(&ff->ff_knlist)) {
|
|
|
|
knote_fdclose(fd);
|
2003-03-22 13:39:47 +03:00
|
|
|
}
|
2009-04-04 14:12:51 +04:00
|
|
|
|
2009-12-20 12:36:05 +03:00
|
|
|
/*
|
|
|
|
* Since the file system code doesn't know which fd
|
|
|
|
* each request came from (think dup()), we have to
|
|
|
|
* ask it to return ERESTART for any long-term blocks.
|
|
|
|
* The re-entry through read/write/etc will detect the
|
|
|
|
* closed fd and return EBAFD.
|
|
|
|
* Blocked partial writes may return a short length.
|
|
|
|
*/
|
|
|
|
(*fp->f_ops->fo_restart)(fp);
|
2009-05-25 01:41:25 +04:00
|
|
|
mutex_enter(&fdp->fd_lock);
|
2009-04-04 14:12:51 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* We need to see the count drop to zero at least once,
|
|
|
|
* in order to ensure that all pre-existing references
|
|
|
|
* have been drained. New references past this point are
|
|
|
|
* of no interest.
|
2009-12-20 12:36:05 +03:00
|
|
|
* XXX (dsl) this may need to call fo_restart() after a
|
|
|
|
* timeout to guarantee that all the system calls exit.
|
2008-03-22 00:53:35 +03:00
|
|
|
*/
|
|
|
|
while ((ff->ff_refcnt & FR_MASK) != 0) {
|
2009-05-25 01:41:25 +04:00
|
|
|
cv_wait(&ff->ff_closing, &fdp->fd_lock);
|
2003-03-22 13:39:47 +03:00
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
atomic_and_uint(&ff->ff_refcnt, ~FR_CLOSING);
|
|
|
|
} else {
|
|
|
|
/* If no references, there must be no knotes. */
|
|
|
|
KASSERT(SLIST_EMPTY(&ff->ff_knlist));
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
1999-05-06 00:01:01 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* POSIX record locking dictates that any close releases ALL
|
|
|
|
* 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.
|
|
|
|
*/
|
2009-05-25 01:41:25 +04:00
|
|
|
if (__predict_false((p->p_flag & PK_ADVLOCK) != 0 &&
|
|
|
|
fp->f_type == DTYPE_VNODE)) {
|
2008-03-22 00:53:35 +03:00
|
|
|
lf.l_whence = SEEK_SET;
|
|
|
|
lf.l_start = 0;
|
|
|
|
lf.l_len = 0;
|
|
|
|
lf.l_type = F_UNLCK;
|
2009-05-25 01:41:25 +04:00
|
|
|
mutex_exit(&fdp->fd_lock);
|
2008-03-22 00:53:35 +03:00
|
|
|
(void)VOP_ADVLOCK(fp->f_data, p, F_UNLCK, &lf, F_POSIX);
|
2009-05-25 01:41:25 +04:00
|
|
|
mutex_enter(&fdp->fd_lock);
|
2003-02-23 17:37:32 +03:00
|
|
|
}
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/* Free descriptor slot. */
|
2004-05-31 19:30:55 +04:00
|
|
|
fd_unused(fdp, fd);
|
2008-03-22 00:53:35 +03:00
|
|
|
mutex_exit(&fdp->fd_lock);
|
1994-12-04 06:09:50 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/* Now drop reference to the file itself. */
|
|
|
|
return closef(fp);
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
|
|
|
|
2007-03-10 19:50:01 +03:00
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Duplicate a file descriptor.
|
2007-03-10 19:50:01 +03:00
|
|
|
*/
|
|
|
|
int
|
2008-07-02 20:45:19 +04:00
|
|
|
fd_dup(file_t *fp, int minfd, int *newp, bool exclose)
|
2007-03-10 19:50:01 +03:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
proc_t *p;
|
|
|
|
int error;
|
2007-03-10 19:50:01 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
p = curproc;
|
2007-03-10 19:50:01 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
while ((error = fd_alloc(p, minfd, newp)) != 0) {
|
|
|
|
if (error != ENOSPC) {
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
fd_tryexpand(p);
|
|
|
|
}
|
2007-03-10 19:50:01 +03:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
curlwp->l_fd->fd_dt->dt_ff[*newp]->ff_exclose = exclose;
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_affix(p, fp, *newp);
|
|
|
|
return 0;
|
2007-03-10 19:50:01 +03:00
|
|
|
}
|
|
|
|
|
1994-05-19 12:13:09 +04:00
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* dup2 operation.
|
1994-05-19 12:13:09 +04:00
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_dup2(file_t *fp, unsigned new)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *fdp;
|
|
|
|
fdfile_t *ff;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdtab_t *dt;
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp = curlwp->l_fd;
|
1999-05-06 00:01:01 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Ensure there are enough slots in the descriptor table,
|
|
|
|
* and allocate an fdfile_t up front in case we need it.
|
|
|
|
*/
|
2009-05-25 01:41:25 +04:00
|
|
|
while (new >= fdp->fd_dt->dt_nfiles) {
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_tryexpand(curproc);
|
|
|
|
}
|
|
|
|
ff = pool_cache_get(fdfile_cache, PR_WAITOK);
|
2001-04-07 13:00:57 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* If there is already a file open, close it. If the file is
|
|
|
|
* half open, wait for it to be constructed before closing it.
|
|
|
|
* XXX Potential for deadlock here?
|
|
|
|
*/
|
|
|
|
mutex_enter(&fdp->fd_lock);
|
|
|
|
while (fd_isused(fdp, new)) {
|
|
|
|
mutex_exit(&fdp->fd_lock);
|
|
|
|
if (fd_getfile(new) != NULL) {
|
|
|
|
(void)fd_close(new);
|
|
|
|
} else {
|
2009-05-25 01:41:25 +04:00
|
|
|
/*
|
|
|
|
* Crummy, but unlikely to happen.
|
|
|
|
* Can occur if we interrupt another
|
|
|
|
* thread while it is opening a file.
|
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
kpause("dup2", false, 1, NULL);
|
|
|
|
}
|
|
|
|
mutex_enter(&fdp->fd_lock);
|
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
dt = fdp->fd_dt;
|
|
|
|
if (dt->dt_ff[new] == NULL) {
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(new >= NDFDFILE);
|
2009-05-25 01:41:25 +04:00
|
|
|
dt->dt_ff[new] = ff;
|
2008-03-22 00:53:35 +03:00
|
|
|
ff = NULL;
|
|
|
|
}
|
|
|
|
fd_used(fdp, new);
|
|
|
|
mutex_exit(&fdp->fd_lock);
|
|
|
|
|
|
|
|
/* Slot is now allocated. Insert copy of the file. */
|
|
|
|
fd_affix(curproc, fp, new);
|
|
|
|
if (ff != NULL) {
|
|
|
|
pool_cache_put(fdfile_cache, ff);
|
|
|
|
}
|
|
|
|
return 0;
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Drop reference to a file structure.
|
1994-05-17 08:21:49 +04:00
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
closef(file_t *fp)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
struct flock lf;
|
|
|
|
int error;
|
1994-05-19 12:13:09 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Drop reference. If referenced elsewhere it's still open
|
|
|
|
* and we have nothing more to do.
|
|
|
|
*/
|
|
|
|
mutex_enter(&fp->f_lock);
|
|
|
|
KASSERT(fp->f_count > 0);
|
|
|
|
if (--fp->f_count > 0) {
|
|
|
|
mutex_exit(&fp->f_lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
KASSERT(fp->f_count == 0);
|
|
|
|
mutex_exit(&fp->f_lock);
|
2002-10-23 13:10:23 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/* We held the last reference - release locks, close and free. */
|
|
|
|
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;
|
|
|
|
(void)VOP_ADVLOCK(fp->f_data, fp, F_UNLCK, &lf, F_FLOCK);
|
1994-05-19 12:13:09 +04:00
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
if (fp->f_ops != NULL) {
|
|
|
|
error = (*fp->f_ops->fo_close)(fp);
|
|
|
|
} else {
|
|
|
|
error = 0;
|
|
|
|
}
|
2009-05-23 22:28:05 +04:00
|
|
|
KASSERT(fp->f_count == 0);
|
|
|
|
KASSERT(fp->f_cred != NULL);
|
|
|
|
pool_cache_put(file_cache, fp);
|
1999-05-06 00:01:01 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
return error;
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a file descriptor for the process.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_alloc(proc_t *p, int want, int *result)
|
1994-05-17 08:21:49 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *fdp;
|
2004-05-31 19:30:55 +04:00
|
|
|
int i, lim, last, error;
|
2003-10-30 10:27:02 +03:00
|
|
|
u_int off, new;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdtab_t *dt;
|
2008-03-22 00:53:35 +03:00
|
|
|
|
|
|
|
KASSERT(p == curproc || p == &proc0);
|
2001-02-26 23:24:30 +03:00
|
|
|
|
|
|
|
fdp = p->p_fd;
|
1994-05-17 08:21:49 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Search for a free descriptor starting at the higher
|
2008-03-22 00:53:35 +03:00
|
|
|
* of want or fd_freefile.
|
1994-05-17 08:21:49 +04:00
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
mutex_enter(&fdp->fd_lock);
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_checkmaps(fdp);
|
|
|
|
dt = fdp->fd_dt;
|
|
|
|
KASSERT(dt->dt_ff[0] == (fdfile_t *)fdp->fd_dfdfile[0]);
|
1994-05-19 12:13:09 +04:00
|
|
|
lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
|
2009-05-25 01:41:25 +04:00
|
|
|
last = min(dt->dt_nfiles, lim);
|
2008-03-22 00:53:35 +03:00
|
|
|
for (;;) {
|
|
|
|
if ((i = want) < fdp->fd_freefile)
|
|
|
|
i = fdp->fd_freefile;
|
|
|
|
off = i >> NDENTRYSHIFT;
|
|
|
|
new = fd_next_zero(fdp, fdp->fd_himap, off,
|
|
|
|
(last + NDENTRIES - 1) >> NDENTRYSHIFT);
|
|
|
|
if (new == -1)
|
|
|
|
break;
|
|
|
|
i = fd_next_zero(fdp, &fdp->fd_lomap[new],
|
2003-10-30 10:27:02 +03:00
|
|
|
new > off ? 0 : i & NDENTRYMASK, NDENTRIES);
|
|
|
|
if (i == -1) {
|
2005-02-27 00:34:55 +03:00
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Free file descriptor in this block was
|
2003-10-30 10:27:02 +03:00
|
|
|
* below want, try again with higher want.
|
|
|
|
*/
|
|
|
|
want = (new + 1) << NDENTRYSHIFT;
|
2008-03-22 00:53:35 +03:00
|
|
|
continue;
|
2003-10-30 10:27:02 +03:00
|
|
|
}
|
|
|
|
i += (new << NDENTRYSHIFT);
|
2008-03-22 00:53:35 +03:00
|
|
|
if (i >= last) {
|
|
|
|
break;
|
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
if (dt->dt_ff[i] == NULL) {
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(i >= NDFDFILE);
|
2009-05-25 01:41:25 +04:00
|
|
|
dt->dt_ff[i] = pool_cache_get(fdfile_cache, PR_WAITOK);
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(dt->dt_ff[i]->ff_refcnt == 0);
|
|
|
|
KASSERT(dt->dt_ff[i]->ff_file == NULL);
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_used(fdp, i);
|
|
|
|
if (want <= fdp->fd_freefile) {
|
|
|
|
fdp->fd_freefile = i;
|
|
|
|
}
|
|
|
|
*result = i;
|
|
|
|
KASSERT(i >= NDFDFILE ||
|
2009-05-25 01:41:25 +04:00
|
|
|
dt->dt_ff[i] == (fdfile_t *)fdp->fd_dfdfile[i]);
|
|
|
|
fd_checkmaps(fdp);
|
|
|
|
mutex_exit(&fdp->fd_lock);
|
2008-03-22 00:53:35 +03:00
|
|
|
return 0;
|
2002-04-28 01:36:50 +04:00
|
|
|
}
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/* No space in current array. Let the caller expand and retry. */
|
2009-05-25 01:41:25 +04:00
|
|
|
error = (dt->dt_nfiles >= lim) ? EMFILE : ENOSPC;
|
2008-03-22 00:53:35 +03:00
|
|
|
mutex_exit(&fdp->fd_lock);
|
|
|
|
return error;
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
|
|
|
|
2008-12-21 12:58:22 +03:00
|
|
|
/*
|
2009-05-25 01:41:25 +04:00
|
|
|
* Allocate memory for a descriptor table.
|
2008-12-21 12:58:22 +03:00
|
|
|
*/
|
2009-05-25 01:41:25 +04:00
|
|
|
static fdtab_t *
|
|
|
|
fd_dtab_alloc(int n)
|
2008-12-21 12:58:22 +03:00
|
|
|
{
|
2009-05-25 01:41:25 +04:00
|
|
|
fdtab_t *dt;
|
|
|
|
size_t sz;
|
2008-12-21 12:58:22 +03:00
|
|
|
|
|
|
|
KASSERT(n > NDFILE);
|
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
sz = sizeof(*dt) + (n - NDFILE) * sizeof(dt->dt_ff[0]);
|
|
|
|
dt = kmem_alloc(sz, KM_SLEEP);
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
memset(dt, 0xff, sz);
|
|
|
|
#endif
|
|
|
|
dt->dt_nfiles = n;
|
|
|
|
dt->dt_link = NULL;
|
|
|
|
return dt;
|
2008-12-21 12:58:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2009-05-25 01:41:25 +04:00
|
|
|
* Free a descriptor table, and all tables linked for deferred free.
|
2008-12-21 12:58:22 +03:00
|
|
|
*/
|
|
|
|
static void
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_dtab_free(fdtab_t *dt)
|
2008-12-21 12:58:22 +03:00
|
|
|
{
|
2009-05-25 01:41:25 +04:00
|
|
|
fdtab_t *next;
|
|
|
|
size_t sz;
|
|
|
|
|
|
|
|
do {
|
|
|
|
next = dt->dt_link;
|
|
|
|
KASSERT(dt->dt_nfiles > NDFILE);
|
|
|
|
sz = sizeof(*dt) +
|
|
|
|
(dt->dt_nfiles - NDFILE) * sizeof(dt->dt_ff[0]);
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
memset(dt, 0xff, sz);
|
|
|
|
#endif
|
|
|
|
kmem_free(dt, sz);
|
|
|
|
dt = next;
|
|
|
|
} while (dt != NULL);
|
2008-12-21 12:58:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate descriptor bitmap.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
fd_map_alloc(int n, uint32_t **lo, uint32_t **hi)
|
|
|
|
{
|
|
|
|
uint8_t *ptr;
|
|
|
|
size_t szlo, szhi;
|
|
|
|
|
|
|
|
KASSERT(n > NDENTRIES);
|
|
|
|
|
|
|
|
szlo = NDLOSLOTS(n) * sizeof(uint32_t);
|
|
|
|
szhi = NDHISLOTS(n) * sizeof(uint32_t);
|
|
|
|
ptr = kmem_alloc(szlo + szhi, KM_SLEEP);
|
|
|
|
*lo = (uint32_t *)ptr;
|
|
|
|
*hi = (uint32_t *)(ptr + szlo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free descriptor bitmap.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
fd_map_free(int n, uint32_t *lo, uint32_t *hi)
|
|
|
|
{
|
|
|
|
size_t szlo, szhi;
|
|
|
|
|
|
|
|
KASSERT(n > NDENTRIES);
|
|
|
|
|
|
|
|
szlo = NDLOSLOTS(n) * sizeof(uint32_t);
|
|
|
|
szhi = NDHISLOTS(n) * sizeof(uint32_t);
|
|
|
|
KASSERT(hi == (uint32_t *)((uint8_t *)lo + szlo));
|
|
|
|
kmem_free(lo, szlo + szhi);
|
|
|
|
}
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Expand a process' descriptor table.
|
|
|
|
*/
|
Rework fdalloc() even further: split fdalloc() into fdalloc() and
fdexpand(). The former will return ENOSPC if there is not space
in the current filedesc table. The latter performs the expansion
of the filedesc table. This means that fdalloc() won't ever block,
and it gives callers an opportunity to clean up before the
potentially-blocking fdexpand() call.
Update all fdalloc() callers to deal with the need-to-fdexpand() case.
Rewrite unp_externalize() to use fdalloc() and fdexpand() in a
safe way, using an algorithm suggested by Bill Sommerfeld:
- Use a temporary array of integers to hold the new filedesc table
indexes. This allows us to repeat the loop if necessary.
- Loop through the array of file *'s, assigning them to filedesc table
slots. If fdalloc() indicates expansion is necessary, undo the
assignments we've done so far, expand, and retry the whole process.
- Once all file *'s have been assigned to slots, update the f_msgcount
and unp_rights counters.
- Right before we return, copy the temporary integer array to the message
buffer, and trim the length as before.
Note that once locking is added to the filedesc array, this entire
operation will be `atomic', in that the lock will be held while
file *'s are assigned to embryonic table slots, thus preventing anything
else from using them.
2001-06-07 05:29:16 +04:00
|
|
|
void
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_tryexpand(proc_t *p)
|
Rework fdalloc() even further: split fdalloc() into fdalloc() and
fdexpand(). The former will return ENOSPC if there is not space
in the current filedesc table. The latter performs the expansion
of the filedesc table. This means that fdalloc() won't ever block,
and it gives callers an opportunity to clean up before the
potentially-blocking fdexpand() call.
Update all fdalloc() callers to deal with the need-to-fdexpand() case.
Rewrite unp_externalize() to use fdalloc() and fdexpand() in a
safe way, using an algorithm suggested by Bill Sommerfeld:
- Use a temporary array of integers to hold the new filedesc table
indexes. This allows us to repeat the loop if necessary.
- Loop through the array of file *'s, assigning them to filedesc table
slots. If fdalloc() indicates expansion is necessary, undo the
assignments we've done so far, expand, and retry the whole process.
- Once all file *'s have been assigned to slots, update the f_msgcount
and unp_rights counters.
- Right before we return, copy the temporary integer array to the message
buffer, and trim the length as before.
Note that once locking is added to the filedesc array, this entire
operation will be `atomic', in that the lock will be held while
file *'s are assigned to embryonic table slots, thus preventing anything
else from using them.
2001-06-07 05:29:16 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *fdp;
|
|
|
|
int i, numfiles, oldnfiles;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdtab_t *newdt, *dt;
|
2008-03-22 00:53:35 +03:00
|
|
|
uint32_t *newhimap, *newlomap;
|
Rework fdalloc() even further: split fdalloc() into fdalloc() and
fdexpand(). The former will return ENOSPC if there is not space
in the current filedesc table. The latter performs the expansion
of the filedesc table. This means that fdalloc() won't ever block,
and it gives callers an opportunity to clean up before the
potentially-blocking fdexpand() call.
Update all fdalloc() callers to deal with the need-to-fdexpand() case.
Rewrite unp_externalize() to use fdalloc() and fdexpand() in a
safe way, using an algorithm suggested by Bill Sommerfeld:
- Use a temporary array of integers to hold the new filedesc table
indexes. This allows us to repeat the loop if necessary.
- Loop through the array of file *'s, assigning them to filedesc table
slots. If fdalloc() indicates expansion is necessary, undo the
assignments we've done so far, expand, and retry the whole process.
- Once all file *'s have been assigned to slots, update the f_msgcount
and unp_rights counters.
- Right before we return, copy the temporary integer array to the message
buffer, and trim the length as before.
Note that once locking is added to the filedesc array, this entire
operation will be `atomic', in that the lock will be held while
file *'s are assigned to embryonic table slots, thus preventing anything
else from using them.
2001-06-07 05:29:16 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(p == curproc || p == &proc0);
|
Rework fdalloc() even further: split fdalloc() into fdalloc() and
fdexpand(). The former will return ENOSPC if there is not space
in the current filedesc table. The latter performs the expansion
of the filedesc table. This means that fdalloc() won't ever block,
and it gives callers an opportunity to clean up before the
potentially-blocking fdexpand() call.
Update all fdalloc() callers to deal with the need-to-fdexpand() case.
Rewrite unp_externalize() to use fdalloc() and fdexpand() in a
safe way, using an algorithm suggested by Bill Sommerfeld:
- Use a temporary array of integers to hold the new filedesc table
indexes. This allows us to repeat the loop if necessary.
- Loop through the array of file *'s, assigning them to filedesc table
slots. If fdalloc() indicates expansion is necessary, undo the
assignments we've done so far, expand, and retry the whole process.
- Once all file *'s have been assigned to slots, update the f_msgcount
and unp_rights counters.
- Right before we return, copy the temporary integer array to the message
buffer, and trim the length as before.
Note that once locking is added to the filedesc array, this entire
operation will be `atomic', in that the lock will be held while
file *'s are assigned to embryonic table slots, thus preventing anything
else from using them.
2001-06-07 05:29:16 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp = p->p_fd;
|
|
|
|
newhimap = NULL;
|
|
|
|
newlomap = NULL;
|
2009-05-25 01:41:25 +04:00
|
|
|
oldnfiles = fdp->fd_dt->dt_nfiles;
|
2004-05-31 19:30:55 +04:00
|
|
|
|
|
|
|
if (oldnfiles < NDEXTENT)
|
2005-05-30 02:24:14 +04:00
|
|
|
numfiles = NDEXTENT;
|
Rework fdalloc() even further: split fdalloc() into fdalloc() and
fdexpand(). The former will return ENOSPC if there is not space
in the current filedesc table. The latter performs the expansion
of the filedesc table. This means that fdalloc() won't ever block,
and it gives callers an opportunity to clean up before the
potentially-blocking fdexpand() call.
Update all fdalloc() callers to deal with the need-to-fdexpand() case.
Rewrite unp_externalize() to use fdalloc() and fdexpand() in a
safe way, using an algorithm suggested by Bill Sommerfeld:
- Use a temporary array of integers to hold the new filedesc table
indexes. This allows us to repeat the loop if necessary.
- Loop through the array of file *'s, assigning them to filedesc table
slots. If fdalloc() indicates expansion is necessary, undo the
assignments we've done so far, expand, and retry the whole process.
- Once all file *'s have been assigned to slots, update the f_msgcount
and unp_rights counters.
- Right before we return, copy the temporary integer array to the message
buffer, and trim the length as before.
Note that once locking is added to the filedesc array, this entire
operation will be `atomic', in that the lock will be held while
file *'s are assigned to embryonic table slots, thus preventing anything
else from using them.
2001-06-07 05:29:16 +04:00
|
|
|
else
|
2005-05-30 02:24:14 +04:00
|
|
|
numfiles = 2 * oldnfiles;
|
2004-05-31 19:30:55 +04:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
newdt = fd_dtab_alloc(numfiles);
|
2005-05-30 02:24:14 +04:00
|
|
|
if (NDHISLOTS(numfiles) > NDHISLOTS(oldnfiles)) {
|
2008-12-21 12:58:22 +03:00
|
|
|
fd_map_alloc(numfiles, &newlomap, &newhimap);
|
2004-05-31 19:30:55 +04:00
|
|
|
}
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
mutex_enter(&fdp->fd_lock);
|
2009-05-25 01:41:25 +04:00
|
|
|
dt = fdp->fd_dt;
|
|
|
|
KASSERT(dt->dt_ff[0] == (fdfile_t *)fdp->fd_dfdfile[0]);
|
|
|
|
if (dt->dt_nfiles != oldnfiles) {
|
2008-03-22 00:53:35 +03:00
|
|
|
/* fdp changed; caller must retry */
|
|
|
|
mutex_exit(&fdp->fd_lock);
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_dtab_free(newdt);
|
2008-12-21 12:58:22 +03:00
|
|
|
if (NDHISLOTS(numfiles) > NDHISLOTS(oldnfiles)) {
|
|
|
|
fd_map_free(numfiles, newlomap, newhimap);
|
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
return;
|
2004-05-31 19:30:55 +04:00
|
|
|
}
|
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
/* Copy the existing descriptor table and zero the new portion. */
|
|
|
|
i = sizeof(fdfile_t *) * oldnfiles;
|
|
|
|
memcpy(newdt->dt_ff, dt->dt_ff, i);
|
2009-05-29 02:17:04 +04:00
|
|
|
memset((uint8_t *)newdt->dt_ff + i, 0,
|
|
|
|
numfiles * sizeof(fdfile_t *) - i);
|
2008-03-22 00:53:35 +03:00
|
|
|
|
Rework fdalloc() even further: split fdalloc() into fdalloc() and
fdexpand(). The former will return ENOSPC if there is not space
in the current filedesc table. The latter performs the expansion
of the filedesc table. This means that fdalloc() won't ever block,
and it gives callers an opportunity to clean up before the
potentially-blocking fdexpand() call.
Update all fdalloc() callers to deal with the need-to-fdexpand() case.
Rewrite unp_externalize() to use fdalloc() and fdexpand() in a
safe way, using an algorithm suggested by Bill Sommerfeld:
- Use a temporary array of integers to hold the new filedesc table
indexes. This allows us to repeat the loop if necessary.
- Loop through the array of file *'s, assigning them to filedesc table
slots. If fdalloc() indicates expansion is necessary, undo the
assignments we've done so far, expand, and retry the whole process.
- Once all file *'s have been assigned to slots, update the f_msgcount
and unp_rights counters.
- Right before we return, copy the temporary integer array to the message
buffer, and trim the length as before.
Note that once locking is added to the filedesc array, this entire
operation will be `atomic', in that the lock will be held while
file *'s are assigned to embryonic table slots, thus preventing anything
else from using them.
2001-06-07 05:29:16 +04:00
|
|
|
/*
|
2009-05-25 01:41:25 +04:00
|
|
|
* Link old descriptor array into list to be discarded. We defer
|
|
|
|
* freeing until the last reference to the descriptor table goes
|
|
|
|
* away (usually process exit). This allows us to do lockless
|
|
|
|
* lookups in fd_getfile().
|
Rework fdalloc() even further: split fdalloc() into fdalloc() and
fdexpand(). The former will return ENOSPC if there is not space
in the current filedesc table. The latter performs the expansion
of the filedesc table. This means that fdalloc() won't ever block,
and it gives callers an opportunity to clean up before the
potentially-blocking fdexpand() call.
Update all fdalloc() callers to deal with the need-to-fdexpand() case.
Rewrite unp_externalize() to use fdalloc() and fdexpand() in a
safe way, using an algorithm suggested by Bill Sommerfeld:
- Use a temporary array of integers to hold the new filedesc table
indexes. This allows us to repeat the loop if necessary.
- Loop through the array of file *'s, assigning them to filedesc table
slots. If fdalloc() indicates expansion is necessary, undo the
assignments we've done so far, expand, and retry the whole process.
- Once all file *'s have been assigned to slots, update the f_msgcount
and unp_rights counters.
- Right before we return, copy the temporary integer array to the message
buffer, and trim the length as before.
Note that once locking is added to the filedesc array, this entire
operation will be `atomic', in that the lock will be held while
file *'s are assigned to embryonic table slots, thus preventing anything
else from using them.
2001-06-07 05:29:16 +04:00
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
if (oldnfiles > NDFILE) {
|
2009-05-23 22:28:05 +04:00
|
|
|
if (fdp->fd_refcnt > 1) {
|
2009-05-25 01:41:25 +04:00
|
|
|
newdt->dt_link = dt;
|
2008-03-22 00:53:35 +03:00
|
|
|
} else {
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_dtab_free(dt);
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
|
|
|
}
|
2003-10-30 10:27:02 +03:00
|
|
|
|
2005-05-30 02:24:14 +04:00
|
|
|
if (NDHISLOTS(numfiles) > NDHISLOTS(oldnfiles)) {
|
2008-03-22 00:53:35 +03:00
|
|
|
i = NDHISLOTS(oldnfiles) * sizeof(uint32_t);
|
|
|
|
memcpy(newhimap, fdp->fd_himap, i);
|
|
|
|
memset((uint8_t *)newhimap + i, 0,
|
2005-05-30 02:24:14 +04:00
|
|
|
NDHISLOTS(numfiles) * sizeof(uint32_t) - i);
|
2003-10-30 10:27:02 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
i = NDLOSLOTS(oldnfiles) * sizeof(uint32_t);
|
|
|
|
memcpy(newlomap, fdp->fd_lomap, i);
|
|
|
|
memset((uint8_t *)newlomap + i, 0,
|
2005-05-30 02:24:14 +04:00
|
|
|
NDLOSLOTS(numfiles) * sizeof(uint32_t) - i);
|
2003-10-30 10:27:02 +03:00
|
|
|
|
2004-05-31 19:30:55 +04:00
|
|
|
if (NDHISLOTS(oldnfiles) > NDHISLOTS(NDFILE)) {
|
2008-12-21 12:58:22 +03:00
|
|
|
fd_map_free(oldnfiles, fdp->fd_lomap, fdp->fd_himap);
|
2003-10-30 10:27:02 +03:00
|
|
|
}
|
|
|
|
fdp->fd_himap = newhimap;
|
|
|
|
fdp->fd_lomap = newlomap;
|
|
|
|
}
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* All other modifications must become globally visible before
|
2009-05-25 01:41:25 +04:00
|
|
|
* the change to fd_dt. See fd_getfile().
|
2008-03-22 00:53:35 +03:00
|
|
|
*/
|
|
|
|
membar_producer();
|
2009-05-25 01:41:25 +04:00
|
|
|
fdp->fd_dt = newdt;
|
|
|
|
KASSERT(newdt->dt_ff[0] == (fdfile_t *)fdp->fd_dfdfile[0]);
|
|
|
|
fd_checkmaps(fdp);
|
2008-03-22 00:53:35 +03:00
|
|
|
mutex_exit(&fdp->fd_lock);
|
Rework fdalloc() even further: split fdalloc() into fdalloc() and
fdexpand(). The former will return ENOSPC if there is not space
in the current filedesc table. The latter performs the expansion
of the filedesc table. This means that fdalloc() won't ever block,
and it gives callers an opportunity to clean up before the
potentially-blocking fdexpand() call.
Update all fdalloc() callers to deal with the need-to-fdexpand() case.
Rewrite unp_externalize() to use fdalloc() and fdexpand() in a
safe way, using an algorithm suggested by Bill Sommerfeld:
- Use a temporary array of integers to hold the new filedesc table
indexes. This allows us to repeat the loop if necessary.
- Loop through the array of file *'s, assigning them to filedesc table
slots. If fdalloc() indicates expansion is necessary, undo the
assignments we've done so far, expand, and retry the whole process.
- Once all file *'s have been assigned to slots, update the f_msgcount
and unp_rights counters.
- Right before we return, copy the temporary integer array to the message
buffer, and trim the length as before.
Note that once locking is added to the filedesc array, this entire
operation will be `atomic', in that the lock will be held while
file *'s are assigned to embryonic table slots, thus preventing anything
else from using them.
2001-06-07 05:29:16 +04:00
|
|
|
}
|
|
|
|
|
1994-05-17 08:21:49 +04:00
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Create a new open file structure and allocate a file descriptor
|
|
|
|
* for the current process.
|
1994-05-17 08:21:49 +04:00
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_allocfile(file_t **resultfp, int *resultfd)
|
1994-05-17 08:21:49 +04:00
|
|
|
{
|
2009-05-23 22:28:05 +04:00
|
|
|
kauth_cred_t cred;
|
2008-03-22 00:53:35 +03:00
|
|
|
file_t *fp;
|
|
|
|
proc_t *p;
|
|
|
|
int error;
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
p = curproc;
|
2006-07-24 02:06:03 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
while ((error = fd_alloc(p, 0, resultfd)) != 0) {
|
|
|
|
if (error != ENOSPC) {
|
|
|
|
return error;
|
Rework fdalloc() even further: split fdalloc() into fdalloc() and
fdexpand(). The former will return ENOSPC if there is not space
in the current filedesc table. The latter performs the expansion
of the filedesc table. This means that fdalloc() won't ever block,
and it gives callers an opportunity to clean up before the
potentially-blocking fdexpand() call.
Update all fdalloc() callers to deal with the need-to-fdexpand() case.
Rewrite unp_externalize() to use fdalloc() and fdexpand() in a
safe way, using an algorithm suggested by Bill Sommerfeld:
- Use a temporary array of integers to hold the new filedesc table
indexes. This allows us to repeat the loop if necessary.
- Loop through the array of file *'s, assigning them to filedesc table
slots. If fdalloc() indicates expansion is necessary, undo the
assignments we've done so far, expand, and retry the whole process.
- Once all file *'s have been assigned to slots, update the f_msgcount
and unp_rights counters.
- Right before we return, copy the temporary integer array to the message
buffer, and trim the length as before.
Note that once locking is added to the filedesc array, this entire
operation will be `atomic', in that the lock will be held while
file *'s are assigned to embryonic table slots, thus preventing anything
else from using them.
2001-06-07 05:29:16 +04:00
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_tryexpand(p);
|
2001-06-06 21:00:00 +04:00
|
|
|
}
|
2003-02-15 00:50:10 +03:00
|
|
|
|
2007-11-07 03:23:13 +03:00
|
|
|
fp = pool_cache_get(file_cache, PR_WAITOK);
|
2009-05-23 22:28:05 +04:00
|
|
|
if (fp == NULL) {
|
|
|
|
return ENFILE;
|
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(fp->f_count == 0);
|
2009-03-11 09:05:29 +03:00
|
|
|
KASSERT(fp->f_msgcount == 0);
|
|
|
|
KASSERT(fp->f_unpcount == 0);
|
2007-12-26 19:01:34 +03:00
|
|
|
|
2009-05-23 22:28:05 +04:00
|
|
|
/* Replace cached credentials if not what we need. */
|
|
|
|
cred = curlwp->l_cred;
|
|
|
|
if (__predict_false(cred != fp->f_cred)) {
|
|
|
|
kauth_cred_free(fp->f_cred);
|
|
|
|
kauth_cred_hold(cred);
|
|
|
|
fp->f_cred = cred;
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
2007-12-26 19:01:34 +03:00
|
|
|
|
2009-03-11 09:05:29 +03:00
|
|
|
/*
|
|
|
|
* Don't allow recycled files to be scanned.
|
2009-05-23 22:28:05 +04:00
|
|
|
* See uipc_usrreq.c.
|
2009-03-11 09:05:29 +03:00
|
|
|
*/
|
2009-05-23 22:28:05 +04:00
|
|
|
if (__predict_false((fp->f_flag & FSCAN) != 0)) {
|
2009-03-11 09:05:29 +03:00
|
|
|
mutex_enter(&fp->f_lock);
|
|
|
|
atomic_and_uint(&fp->f_flag, ~FSCAN);
|
|
|
|
mutex_exit(&fp->f_lock);
|
|
|
|
}
|
|
|
|
|
2007-12-26 19:01:34 +03:00
|
|
|
fp->f_advice = 0;
|
|
|
|
fp->f_offset = 0;
|
2008-03-22 00:53:35 +03:00
|
|
|
*resultfp = fp;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Successful creation of a new descriptor: make visible to the process.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
fd_affix(proc_t *p, file_t *fp, unsigned fd)
|
|
|
|
{
|
|
|
|
fdfile_t *ff;
|
|
|
|
filedesc_t *fdp;
|
|
|
|
|
|
|
|
KASSERT(p == curproc || p == &proc0);
|
|
|
|
|
|
|
|
/* Add a reference to the file structure. */
|
|
|
|
mutex_enter(&fp->f_lock);
|
|
|
|
fp->f_count++;
|
|
|
|
mutex_exit(&fp->f_lock);
|
2007-12-26 19:01:34 +03:00
|
|
|
|
1994-05-17 08:21:49 +04:00
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Insert the new file into the descriptor slot.
|
|
|
|
*
|
|
|
|
* The memory barriers provided by lock activity in this routine
|
|
|
|
* ensure that any updates to the file structure become globally
|
|
|
|
* visible before the file becomes visible to other LWPs in the
|
|
|
|
* current process.
|
1994-05-17 08:21:49 +04:00
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp = p->p_fd;
|
2009-05-25 01:41:25 +04:00
|
|
|
ff = fdp->fd_dt->dt_ff[fd];
|
2007-12-26 19:01:34 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(ff != NULL);
|
|
|
|
KASSERT(ff->ff_file == NULL);
|
|
|
|
KASSERT(ff->ff_allocated);
|
|
|
|
KASSERT(fd_isused(fdp, fd));
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(fd >= NDFDFILE || ff == (fdfile_t *)fdp->fd_dfdfile[fd]);
|
2007-12-26 19:01:34 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/* No need to lock in order to make file initially visible. */
|
|
|
|
ff->ff_file = fp;
|
|
|
|
}
|
2007-12-26 19:01:34 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/*
|
|
|
|
* Abort creation of a new descriptor: free descriptor slot and file.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
fd_abort(proc_t *p, file_t *fp, unsigned fd)
|
|
|
|
{
|
|
|
|
filedesc_t *fdp;
|
|
|
|
fdfile_t *ff;
|
2007-10-08 19:12:05 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(p == curproc || p == &proc0);
|
|
|
|
|
|
|
|
fdp = p->p_fd;
|
2009-05-25 01:41:25 +04:00
|
|
|
ff = fdp->fd_dt->dt_ff[fd];
|
2008-03-22 00:53:35 +03:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(fd >= NDFDFILE || ff == (fdfile_t *)fdp->fd_dfdfile[fd]);
|
2008-03-22 00:53:35 +03:00
|
|
|
|
|
|
|
mutex_enter(&fdp->fd_lock);
|
|
|
|
KASSERT(fd_isused(fdp, fd));
|
|
|
|
fd_unused(fdp, fd);
|
|
|
|
mutex_exit(&fdp->fd_lock);
|
|
|
|
|
|
|
|
if (fp != NULL) {
|
2009-05-23 22:28:05 +04:00
|
|
|
KASSERT(fp->f_count == 0);
|
|
|
|
KASSERT(fp->f_cred != NULL);
|
|
|
|
pool_cache_put(file_cache, fp);
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
1994-05-17 08:21:49 +04:00
|
|
|
}
|
|
|
|
|
2007-12-26 19:01:34 +03:00
|
|
|
static int
|
|
|
|
file_ctor(void *arg, void *obj, int flags)
|
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
file_t *fp = obj;
|
2007-12-26 19:01:34 +03:00
|
|
|
|
|
|
|
memset(fp, 0, sizeof(*fp));
|
|
|
|
|
|
|
|
mutex_enter(&filelist_lock);
|
2009-05-23 22:28:05 +04:00
|
|
|
if (__predict_false(nfiles >= maxfiles)) {
|
|
|
|
mutex_exit(&filelist_lock);
|
|
|
|
tablefull("file", "increase kern.maxfiles or MAXFILES");
|
|
|
|
return ENFILE;
|
|
|
|
}
|
|
|
|
nfiles++;
|
2007-12-26 19:01:34 +03:00
|
|
|
LIST_INSERT_HEAD(&filehead, fp, f_list);
|
2009-05-23 22:28:05 +04:00
|
|
|
mutex_init(&fp->f_lock, MUTEX_DEFAULT, IPL_NONE);
|
|
|
|
fp->f_cred = curlwp->l_cred;
|
|
|
|
kauth_cred_hold(fp->f_cred);
|
2007-12-26 19:01:34 +03:00
|
|
|
mutex_exit(&filelist_lock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
file_dtor(void *arg, void *obj)
|
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
file_t *fp = obj;
|
2007-12-26 19:01:34 +03:00
|
|
|
|
|
|
|
mutex_enter(&filelist_lock);
|
2009-05-23 22:28:05 +04:00
|
|
|
nfiles--;
|
2007-12-26 19:01:34 +03:00
|
|
|
LIST_REMOVE(fp, f_list);
|
|
|
|
mutex_exit(&filelist_lock);
|
|
|
|
|
2009-05-23 22:28:05 +04:00
|
|
|
kauth_cred_free(fp->f_cred);
|
2007-12-26 19:01:34 +03:00
|
|
|
mutex_destroy(&fp->f_lock);
|
|
|
|
}
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
static int
|
|
|
|
fdfile_ctor(void *arg, void *obj, int flags)
|
|
|
|
{
|
|
|
|
fdfile_t *ff = obj;
|
|
|
|
|
|
|
|
memset(ff, 0, sizeof(*ff));
|
|
|
|
cv_init(&ff->ff_closing, "fdclose");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fdfile_dtor(void *arg, void *obj)
|
|
|
|
{
|
|
|
|
fdfile_t *ff = obj;
|
|
|
|
|
|
|
|
cv_destroy(&ff->ff_closing);
|
|
|
|
}
|
|
|
|
|
|
|
|
file_t *
|
2008-01-06 02:53:21 +03:00
|
|
|
fgetdummy(void)
|
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
file_t *fp;
|
2008-01-06 02:53:21 +03:00
|
|
|
|
|
|
|
fp = kmem_alloc(sizeof(*fp), KM_SLEEP);
|
|
|
|
if (fp != NULL) {
|
|
|
|
memset(fp, 0, sizeof(*fp));
|
|
|
|
mutex_init(&fp->f_lock, MUTEX_DEFAULT, IPL_NONE);
|
|
|
|
}
|
|
|
|
return fp;
|
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
|
1999-04-30 22:42:58 +04:00
|
|
|
void
|
2008-03-22 00:53:35 +03:00
|
|
|
fputdummy(file_t *fp)
|
1999-04-30 22:42:58 +04:00
|
|
|
{
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
mutex_destroy(&fp->f_lock);
|
|
|
|
kmem_free(fp, sizeof(*fp));
|
1999-04-30 22:42:58 +04:00
|
|
|
}
|
|
|
|
|
1998-01-05 07:51:15 +03:00
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Create an initial filedesc structure.
|
1998-01-05 07:51:15 +03:00
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *
|
|
|
|
fd_init(filedesc_t *fdp)
|
1998-01-05 07:51:15 +03:00
|
|
|
{
|
2009-05-25 01:41:25 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2008-03-22 00:53:35 +03:00
|
|
|
unsigned fd;
|
2009-05-25 01:41:25 +04:00
|
|
|
#endif
|
1998-01-05 07:51:15 +03:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
if (__predict_true(fdp == NULL)) {
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp = pool_cache_get(filedesc_cache, PR_WAITOK);
|
|
|
|
} else {
|
2009-05-25 01:41:25 +04:00
|
|
|
/* XXXRUMP KASSERT(fdp == &filedesc0); */
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_ctor(NULL, fdp, PR_WAITOK);
|
|
|
|
}
|
1998-01-05 07:51:15 +03:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(fdp->fd_lastfile == -1);
|
|
|
|
KASSERT(fdp->fd_lastkqfile == -1);
|
|
|
|
KASSERT(fdp->fd_knhash == NULL);
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(fdp->fd_freefile == 0);
|
|
|
|
KASSERT(fdp->fd_exclose == false);
|
|
|
|
KASSERT(fdp->fd_dt == &fdp->fd_dtbuiltin);
|
|
|
|
KASSERT(fdp->fd_dtbuiltin.dt_nfiles == NDFILE);
|
2008-03-22 00:53:35 +03:00
|
|
|
for (fd = 0; fd < NDFDFILE; fd++) {
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(fdp->fd_dtbuiltin.dt_ff[fd] ==
|
|
|
|
(fdfile_t *)fdp->fd_dfdfile[fd]);
|
|
|
|
}
|
|
|
|
for (fd = NDFDFILE; fd < NDFILE; fd++) {
|
|
|
|
KASSERT(fdp->fd_dtbuiltin.dt_ff[fd] == NULL);
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
2009-05-29 04:10:52 +04:00
|
|
|
KASSERT(fdp->fd_himap == fdp->fd_dhimap);
|
|
|
|
KASSERT(fdp->fd_lomap == fdp->fd_dlomap);
|
2009-05-25 01:41:25 +04:00
|
|
|
#endif /* DIAGNOSTIC */
|
|
|
|
|
|
|
|
fdp->fd_refcnt = 1;
|
2009-08-16 15:00:20 +04:00
|
|
|
fd_checkmaps(fdp);
|
1998-01-05 07:51:15 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
return fdp;
|
1998-01-05 07:51:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize a file descriptor table.
|
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
static int
|
|
|
|
filedesc_ctor(void *arg, void *obj, int flag)
|
1998-01-05 07:51:15 +03:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *fdp = obj;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdfile_t **ffp;
|
2008-03-22 00:53:35 +03:00
|
|
|
int i;
|
1998-01-05 07:51:15 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
memset(fdp, 0, sizeof(*fdp));
|
|
|
|
mutex_init(&fdp->fd_lock, MUTEX_DEFAULT, IPL_NONE);
|
|
|
|
fdp->fd_lastfile = -1;
|
|
|
|
fdp->fd_lastkqfile = -1;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdp->fd_dt = &fdp->fd_dtbuiltin;
|
|
|
|
fdp->fd_dtbuiltin.dt_nfiles = NDFILE;
|
2009-05-29 04:10:52 +04:00
|
|
|
fdp->fd_himap = fdp->fd_dhimap;
|
|
|
|
fdp->fd_lomap = fdp->fd_dlomap;
|
1998-01-05 07:51:15 +03:00
|
|
|
|
2008-07-02 18:47:34 +04:00
|
|
|
CTASSERT(sizeof(fdp->fd_dfdfile[0]) >= sizeof(fdfile_t));
|
2009-05-25 01:41:25 +04:00
|
|
|
for (i = 0, ffp = fdp->fd_dt->dt_ff; i < NDFDFILE; i++, ffp++) {
|
|
|
|
*ffp = (fdfile_t *)fdp->fd_dfdfile[i];
|
|
|
|
(void)fdfile_ctor(NULL, fdp->fd_dfdfile[i], PR_WAITOK);
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
1998-01-05 07:51:15 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
return 0;
|
1998-01-05 07:51:15 +03:00
|
|
|
}
|
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
static void
|
|
|
|
filedesc_dtor(void *arg, void *obj)
|
1998-01-05 07:51:15 +03:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *fdp = obj;
|
|
|
|
int i;
|
1998-01-05 07:51:15 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
for (i = 0; i < NDFDFILE; i++) {
|
|
|
|
fdfile_dtor(NULL, fdp->fd_dfdfile[i]);
|
|
|
|
}
|
1998-01-05 07:51:15 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
mutex_destroy(&fdp->fd_lock);
|
1998-01-05 07:51:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Make p2 share p1's filedesc structure.
|
1998-01-05 07:51:15 +03:00
|
|
|
*/
|
|
|
|
void
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_share(struct proc *p2)
|
1998-01-05 07:51:15 +03:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *fdp;
|
1998-01-05 07:51:15 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp = curlwp->l_fd;
|
|
|
|
p2->p_fd = fdp;
|
|
|
|
atomic_inc_uint(&fdp->fd_refcnt);
|
1998-01-05 07:51:15 +03:00
|
|
|
}
|
|
|
|
|
2009-05-23 22:28:05 +04:00
|
|
|
/*
|
|
|
|
* Acquire a hold on a filedesc structure.
|
|
|
|
*/
|
|
|
|
void
|
2009-10-27 05:58:28 +03:00
|
|
|
fd_hold(lwp_t *l)
|
2009-05-23 22:28:05 +04:00
|
|
|
{
|
2009-10-27 05:58:28 +03:00
|
|
|
filedesc_t *fdp = l->l_fd;
|
2009-05-23 22:28:05 +04:00
|
|
|
|
2009-10-27 05:58:28 +03:00
|
|
|
KASSERT(fdp == curlwp->l_fd || fdp == lwp0.l_fd);
|
|
|
|
atomic_inc_uint(&fdp->fd_refcnt);
|
2009-05-23 22:28:05 +04:00
|
|
|
}
|
|
|
|
|
1994-05-17 08:21:49 +04:00
|
|
|
/*
|
|
|
|
* Copy a filedesc structure.
|
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *
|
|
|
|
fd_copy(void)
|
1994-05-17 08:21:49 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *newfdp, *fdp;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdfile_t *ff, **ffp, **nffp, *ff2;
|
|
|
|
int i, j, numfiles, lastfile, newlast;
|
2008-03-22 00:53:35 +03:00
|
|
|
file_t *fp;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdtab_t *newdt;
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp = curproc->p_fd;
|
|
|
|
newfdp = pool_cache_get(filedesc_cache, PR_WAITOK);
|
1994-05-17 08:21:49 +04:00
|
|
|
newfdp->fd_refcnt = 1;
|
2004-05-31 19:30:55 +04:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
KASSERT(newfdp->fd_lastfile == -1);
|
|
|
|
KASSERT(newfdp->fd_lastkqfile == -1);
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(newfdp->fd_knhash == NULL);
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(newfdp->fd_freefile == 0);
|
|
|
|
KASSERT(newfdp->fd_exclose == false);
|
|
|
|
KASSERT(newfdp->fd_dt == &newfdp->fd_dtbuiltin);
|
|
|
|
KASSERT(newfdp->fd_dtbuiltin.dt_nfiles == NDFILE);
|
|
|
|
for (i = 0; i < NDFDFILE; i++) {
|
|
|
|
KASSERT(newfdp->fd_dtbuiltin.dt_ff[i] ==
|
|
|
|
(fdfile_t *)&newfdp->fd_dfdfile[i]);
|
|
|
|
}
|
|
|
|
for (i = NDFDFILE; i < NDFILE; i++) {
|
|
|
|
KASSERT(newfdp->fd_dtbuiltin.dt_ff[i] == NULL);
|
|
|
|
}
|
|
|
|
#endif /* DIAGNOSTIC */
|
2008-03-22 00:53:35 +03:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
mutex_enter(&fdp->fd_lock);
|
|
|
|
fd_checkmaps(fdp);
|
|
|
|
numfiles = fdp->fd_dt->dt_nfiles;
|
|
|
|
lastfile = fdp->fd_lastfile;
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
/*
|
|
|
|
* 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 (lastfile < NDFILE) {
|
|
|
|
i = NDFILE;
|
|
|
|
newdt = newfdp->fd_dt;
|
|
|
|
KASSERT(newfdp->fd_dt == &newfdp->fd_dtbuiltin);
|
|
|
|
} else {
|
1994-05-17 08:21:49 +04:00
|
|
|
/*
|
2009-05-25 01:41:25 +04:00
|
|
|
* Compute the smallest multiple of NDEXTENT needed
|
|
|
|
* for the file descriptors currently in use,
|
|
|
|
* allowing the table to shrink.
|
1994-05-17 08:21:49 +04:00
|
|
|
*/
|
2009-05-25 01:41:25 +04:00
|
|
|
i = numfiles;
|
|
|
|
while (i >= 2 * NDEXTENT && i > lastfile * 2) {
|
|
|
|
i /= 2;
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(i > NDFILE);
|
|
|
|
newdt = fd_dtab_alloc(i);
|
|
|
|
newfdp->fd_dt = newdt;
|
|
|
|
memcpy(newdt->dt_ff, newfdp->fd_dtbuiltin.dt_ff,
|
|
|
|
NDFDFILE * sizeof(fdfile_t **));
|
|
|
|
memset(newdt->dt_ff + NDFDFILE, 0,
|
|
|
|
(i - NDFDFILE) * sizeof(fdfile_t **));
|
|
|
|
}
|
|
|
|
if (NDHISLOTS(i) <= NDHISLOTS(NDFILE)) {
|
|
|
|
newfdp->fd_himap = newfdp->fd_dhimap;
|
|
|
|
newfdp->fd_lomap = newfdp->fd_dlomap;
|
|
|
|
} else {
|
|
|
|
fd_map_alloc(i, &newfdp->fd_lomap, &newfdp->fd_himap);
|
|
|
|
KASSERT(i >= NDENTRIES * NDENTRIES);
|
|
|
|
memset(newfdp->fd_himap, 0, NDHISLOTS(i)*sizeof(uint32_t));
|
|
|
|
memset(newfdp->fd_lomap, 0, NDLOSLOTS(i)*sizeof(uint32_t));
|
2003-10-30 10:27:02 +03:00
|
|
|
}
|
2004-05-31 19:30:55 +04:00
|
|
|
newfdp->fd_freefile = fdp->fd_freefile;
|
2008-03-22 00:53:35 +03:00
|
|
|
newfdp->fd_exclose = fdp->fd_exclose;
|
2004-05-31 19:30:55 +04:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
ffp = fdp->fd_dt->dt_ff;
|
|
|
|
nffp = newdt->dt_ff;
|
2008-03-22 00:53:35 +03:00
|
|
|
newlast = -1;
|
2009-05-25 01:41:25 +04:00
|
|
|
for (i = 0; i <= (int)lastfile; i++, ffp++, nffp++) {
|
|
|
|
KASSERT(i >= NDFDFILE ||
|
|
|
|
*nffp == (fdfile_t *)newfdp->fd_dfdfile[i]);
|
2008-03-22 00:53:35 +03:00
|
|
|
ff = *ffp;
|
2009-05-25 01:41:25 +04:00
|
|
|
if (ff == NULL || (fp = ff->ff_file) == NULL) {
|
|
|
|
/* Descriptor unused, or descriptor half open. */
|
|
|
|
KASSERT(!fd_isused(newfdp, i));
|
2004-05-31 19:30:55 +04:00
|
|
|
continue;
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
if (__predict_false(fp->f_type == DTYPE_KQUEUE)) {
|
2008-03-22 00:53:35 +03:00
|
|
|
/* kqueue descriptors cannot be copied. */
|
2009-07-01 00:32:49 +04:00
|
|
|
if (i < newfdp->fd_freefile)
|
|
|
|
newfdp->fd_freefile = i;
|
2008-03-22 00:53:35 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* It's active: add a reference to the file. */
|
|
|
|
mutex_enter(&fp->f_lock);
|
|
|
|
fp->f_count++;
|
|
|
|
mutex_exit(&fp->f_lock);
|
2009-05-25 01:41:25 +04:00
|
|
|
|
|
|
|
/* Allocate an fdfile_t to represent it. */
|
2008-03-22 00:53:35 +03:00
|
|
|
if (i >= NDFDFILE) {
|
2009-05-25 01:41:25 +04:00
|
|
|
ff2 = pool_cache_get(fdfile_cache, PR_WAITOK);
|
|
|
|
*nffp = ff2;
|
|
|
|
} else {
|
|
|
|
ff2 = newdt->dt_ff[i];
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
|
|
|
ff2->ff_file = fp;
|
|
|
|
ff2->ff_exclose = ff->ff_exclose;
|
2008-07-02 20:45:19 +04:00
|
|
|
ff2->ff_allocated = true;
|
2008-03-22 00:53:35 +03:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
/* Fix up bitmaps. */
|
|
|
|
j = i >> NDENTRYSHIFT;
|
|
|
|
KASSERT((newfdp->fd_lomap[j] & (1 << (i & NDENTRYMASK))) == 0);
|
|
|
|
newfdp->fd_lomap[j] |= 1 << (i & NDENTRYMASK);
|
|
|
|
if (__predict_false(newfdp->fd_lomap[j] == ~0)) {
|
|
|
|
KASSERT((newfdp->fd_himap[j >> NDENTRYSHIFT] &
|
|
|
|
(1 << (j & NDENTRYMASK))) == 0);
|
|
|
|
newfdp->fd_himap[j >> NDENTRYSHIFT] |=
|
|
|
|
1 << (j & NDENTRYMASK);
|
|
|
|
}
|
|
|
|
newlast = i;
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(newdt->dt_ff[0] == (fdfile_t *)newfdp->fd_dfdfile[0]);
|
2008-03-22 00:53:35 +03:00
|
|
|
newfdp->fd_lastfile = newlast;
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_checkmaps(newfdp);
|
|
|
|
mutex_exit(&fdp->fd_lock);
|
|
|
|
|
1994-05-17 08:21:49 +04:00
|
|
|
return (newfdp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Release a filedesc structure.
|
|
|
|
*/
|
|
|
|
void
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_free(void)
|
1994-05-17 08:21:49 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
fdfile_t *ff;
|
|
|
|
file_t *fp;
|
2009-05-25 01:41:25 +04:00
|
|
|
int fd, nf;
|
|
|
|
fdtab_t *dt;
|
2009-06-08 04:19:56 +04:00
|
|
|
lwp_t * const l = curlwp;
|
|
|
|
filedesc_t * const fdp = l->l_fd;
|
|
|
|
const bool noadvlock = (l->l_proc->p_flag & PK_ADVLOCK) == 0;
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(fdp->fd_dt->dt_ff[0] == (fdfile_t *)fdp->fd_dfdfile[0]);
|
|
|
|
KASSERT(fdp->fd_dtbuiltin.dt_nfiles == NDFILE);
|
|
|
|
KASSERT(fdp->fd_dtbuiltin.dt_link == NULL);
|
1999-05-06 00:01:01 +04:00
|
|
|
|
2009-05-25 01:41:25 +04:00
|
|
|
#ifndef __HAVE_ATOMIC_AS_MEMBAR
|
|
|
|
membar_exit();
|
|
|
|
#endif
|
2008-03-22 00:53:35 +03:00
|
|
|
if (atomic_dec_uint_nv(&fdp->fd_refcnt) > 0)
|
|
|
|
return;
|
1999-05-06 00:01:01 +04:00
|
|
|
|
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Close any files that the process holds open.
|
1999-05-06 00:01:01 +04:00
|
|
|
*/
|
2009-05-25 01:41:25 +04:00
|
|
|
dt = fdp->fd_dt;
|
|
|
|
fd_checkmaps(fdp);
|
2009-06-07 13:39:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
fdp->fd_refcnt = -1; /* see fd_checkmaps */
|
|
|
|
#endif
|
2009-05-25 01:41:25 +04:00
|
|
|
for (fd = 0, nf = dt->dt_nfiles; fd < nf; fd++) {
|
|
|
|
ff = dt->dt_ff[fd];
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(fd >= NDFDFILE ||
|
|
|
|
ff == (fdfile_t *)fdp->fd_dfdfile[fd]);
|
2009-05-25 01:41:25 +04:00
|
|
|
if (ff == NULL)
|
2008-03-22 00:53:35 +03:00
|
|
|
continue;
|
|
|
|
if ((fp = ff->ff_file) != NULL) {
|
|
|
|
/*
|
2009-05-25 01:41:25 +04:00
|
|
|
* Must use fd_close() here if there is
|
2009-06-08 04:19:56 +04:00
|
|
|
* a reference from kqueue or we might have posix
|
|
|
|
* advisory locks.
|
2008-03-22 00:53:35 +03:00
|
|
|
*/
|
2009-06-08 04:19:56 +04:00
|
|
|
if (__predict_true(ff->ff_refcnt == 0) &&
|
|
|
|
(noadvlock || fp->f_type != DTYPE_VNODE)) {
|
2009-05-25 01:41:25 +04:00
|
|
|
ff->ff_file = NULL;
|
|
|
|
ff->ff_exclose = false;
|
|
|
|
ff->ff_allocated = false;
|
|
|
|
closef(fp);
|
|
|
|
} else {
|
|
|
|
ff->ff_refcnt++;
|
|
|
|
fd_close(fd);
|
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
}
|
|
|
|
KASSERT(ff->ff_refcnt == 0);
|
|
|
|
KASSERT(ff->ff_file == NULL);
|
|
|
|
KASSERT(!ff->ff_exclose);
|
|
|
|
KASSERT(!ff->ff_allocated);
|
|
|
|
if (fd >= NDFDFILE) {
|
|
|
|
pool_cache_put(fdfile_cache, ff);
|
2009-05-25 01:41:25 +04:00
|
|
|
dt->dt_ff[fd] = NULL;
|
1999-05-06 00:01:01 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-03-22 00:53:35 +03:00
|
|
|
* Clean out the descriptor table for the next user and return
|
|
|
|
* to the cache.
|
1999-05-06 00:01:01 +04:00
|
|
|
*/
|
2009-05-25 01:41:25 +04:00
|
|
|
if (__predict_false(dt != &fdp->fd_dtbuiltin)) {
|
|
|
|
fd_dtab_free(fdp->fd_dt);
|
|
|
|
/* Otherwise, done above. */
|
|
|
|
memset(&fdp->fd_dtbuiltin.dt_ff[NDFDFILE], 0,
|
|
|
|
(NDFILE - NDFDFILE) * sizeof(fdp->fd_dtbuiltin.dt_ff[0]));
|
|
|
|
fdp->fd_dt = &fdp->fd_dtbuiltin;
|
|
|
|
}
|
|
|
|
if (__predict_false(NDHISLOTS(nf) > NDHISLOTS(NDFILE))) {
|
2008-03-22 00:53:35 +03:00
|
|
|
KASSERT(fdp->fd_himap != fdp->fd_dhimap);
|
|
|
|
KASSERT(fdp->fd_lomap != fdp->fd_dlomap);
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_map_free(nf, fdp->fd_lomap, fdp->fd_himap);
|
2005-11-30 01:52:02 +03:00
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
if (__predict_false(fdp->fd_knhash != NULL)) {
|
2008-05-05 21:11:16 +04:00
|
|
|
hashdone(fdp->fd_knhash, HASH_LIST, fdp->fd_knhashmask);
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp->fd_knhash = NULL;
|
|
|
|
fdp->fd_knhashmask = 0;
|
|
|
|
} else {
|
|
|
|
KASSERT(fdp->fd_knhashmask == 0);
|
2005-11-30 01:52:02 +03:00
|
|
|
}
|
2009-05-25 01:41:25 +04:00
|
|
|
fdp->fd_dt = &fdp->fd_dtbuiltin;
|
2008-03-22 00:53:35 +03:00
|
|
|
fdp->fd_lastkqfile = -1;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdp->fd_lastfile = -1;
|
|
|
|
fdp->fd_freefile = 0;
|
|
|
|
fdp->fd_exclose = false;
|
|
|
|
memset(&fdp->fd_startzero, 0, sizeof(*fdp) -
|
|
|
|
offsetof(filedesc_t, fd_startzero));
|
2009-05-29 04:10:52 +04:00
|
|
|
fdp->fd_himap = fdp->fd_dhimap;
|
|
|
|
fdp->fd_lomap = fdp->fd_dlomap;
|
2009-05-25 01:41:25 +04:00
|
|
|
KASSERT(fdp->fd_dtbuiltin.dt_nfiles == NDFILE);
|
|
|
|
KASSERT(fdp->fd_dtbuiltin.dt_link == NULL);
|
|
|
|
KASSERT(fdp->fd_dt == &fdp->fd_dtbuiltin);
|
2009-06-07 13:39:02 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
fdp->fd_refcnt = 0; /* see fd_checkmaps */
|
|
|
|
#endif
|
2009-05-25 01:41:25 +04:00
|
|
|
fd_checkmaps(fdp);
|
2008-03-22 00:53:35 +03:00
|
|
|
pool_cache_put(filedesc_cache, fdp);
|
2008-01-27 19:16:50 +03:00
|
|
|
}
|
|
|
|
|
1994-05-17 08:21:49 +04:00
|
|
|
/*
|
|
|
|
* File Descriptor pseudo-device driver (/dev/fd/).
|
|
|
|
*
|
|
|
|
* Opening minor device N dup()s the file (if any) connected to file
|
|
|
|
* descriptor N belonging to the calling process. Note that this driver
|
|
|
|
* consists of only the ``open()'' routine, because all subsequent
|
|
|
|
* references to this file will be direct to the other driver.
|
|
|
|
*/
|
2005-06-24 03:15:12 +04:00
|
|
|
static int
|
2008-03-22 00:53:35 +03:00
|
|
|
filedescopen(dev_t dev, int mode, int type, lwp_t *l)
|
1994-05-17 08:21:49 +04:00
|
|
|
{
|
|
|
|
|
1994-12-14 21:40:27 +03:00
|
|
|
/*
|
2003-09-13 12:32:10 +04:00
|
|
|
* XXX Kludge: set dupfd to contain the value of the
|
2002-04-28 01:31:41 +04:00
|
|
|
* the file descriptor being sought for duplication. The error
|
1994-12-14 21:40:27 +03:00
|
|
|
* return ensures that the vnode for this device will be released
|
|
|
|
* by vn_open. Open will detect this special error and take the
|
|
|
|
* actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
|
|
|
|
* will simply report the error.
|
|
|
|
*/
|
2005-12-11 15:16:03 +03:00
|
|
|
l->l_dupfd = minor(dev); /* XXX */
|
2004-11-30 07:25:43 +03:00
|
|
|
return EDUPFD;
|
1994-12-04 06:09:50 +03:00
|
|
|
}
|
|
|
|
|
1994-12-14 21:40:27 +03:00
|
|
|
/*
|
|
|
|
* Duplicate the specified descriptor to a free descriptor.
|
|
|
|
*/
|
1994-12-04 06:09:50 +03:00
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_dupopen(int old, int *new, int mode, int error)
|
1994-12-04 06:09:50 +03:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
filedesc_t *fdp;
|
|
|
|
fdfile_t *ff;
|
|
|
|
file_t *fp;
|
2009-05-25 01:41:25 +04:00
|
|
|
fdtab_t *dt;
|
2001-06-15 00:32:41 +04:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
if ((fp = fd_getfile(old)) == NULL) {
|
|
|
|
return EBADF;
|
|
|
|
}
|
|
|
|
fdp = curlwp->l_fd;
|
2009-05-25 01:41:25 +04:00
|
|
|
dt = fdp->fd_dt;
|
|
|
|
ff = dt->dt_ff[old];
|
1999-05-06 00:01:01 +04:00
|
|
|
|
1994-12-04 06:09:50 +03:00
|
|
|
/*
|
1994-12-14 21:40:27 +03:00
|
|
|
* There are two cases of interest here.
|
|
|
|
*
|
2004-11-30 07:25:43 +03:00
|
|
|
* For EDUPFD simply dup (dfd) to file descriptor
|
1994-12-14 21:40:27 +03:00
|
|
|
* (indx) and return.
|
|
|
|
*
|
2004-11-30 07:25:43 +03:00
|
|
|
* For EMOVEFD steal away the file structure from (dfd) and
|
1994-12-14 21:40:27 +03:00
|
|
|
* store it in (indx). (dfd) is effectively closed by
|
|
|
|
* this operation.
|
|
|
|
*
|
|
|
|
* Any other error code is just returned.
|
1994-12-04 06:09:50 +03:00
|
|
|
*/
|
1994-12-14 21:40:27 +03:00
|
|
|
switch (error) {
|
2004-11-30 07:25:43 +03:00
|
|
|
case EDUPFD:
|
1994-12-14 21:40:27 +03:00
|
|
|
/*
|
|
|
|
* Check that the mode the file is being opened for is a
|
|
|
|
* subset of the mode of the existing descriptor.
|
|
|
|
*/
|
2008-03-22 00:53:35 +03:00
|
|
|
if (((mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
|
|
|
|
error = EACCES;
|
|
|
|
break;
|
1999-05-06 00:01:01 +04:00
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
|
|
|
|
/* Copy it. */
|
2009-05-25 01:41:25 +04:00
|
|
|
error = fd_dup(fp, 0, new, ff->ff_exclose);
|
2008-03-22 00:53:35 +03:00
|
|
|
break;
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2004-11-30 07:25:43 +03:00
|
|
|
case EMOVEFD:
|
2008-03-22 00:53:35 +03:00
|
|
|
/* Copy it. */
|
2009-05-25 01:41:25 +04:00
|
|
|
error = fd_dup(fp, 0, new, ff->ff_exclose);
|
2008-03-22 00:53:35 +03:00
|
|
|
if (error != 0) {
|
|
|
|
break;
|
|
|
|
}
|
1994-12-04 06:09:50 +03:00
|
|
|
|
2008-03-22 00:53:35 +03:00
|
|
|
/* Steal away the file pointer from 'old'. */
|
|
|
|
(void)fd_close(old);
|
|
|
|
return 0;
|
1994-12-14 21:40:27 +03:00
|
|
|
}
|
2008-03-22 00:53:35 +03:00
|
|
|
|
|
|
|
fd_putfile(old);
|
|
|
|
return error;
|
1994-12-04 06:09:50 +03:00
|
|
|
}
|
1994-05-17 08:21:49 +04:00
|
|
|
|
2003-09-21 23:16:48 +04:00
|
|
|
/*
|
|
|
|
* Sets descriptor owner. If the owner is a process, 'pgid'
|
|
|
|
* is set to positive value, process ID. If the owner is process group,
|
|
|
|
* 'pgid' is set to -pg_id.
|
|
|
|
*/
|
|
|
|
int
|
2008-06-24 14:26:26 +04:00
|
|
|
fsetown(pid_t *pgid, u_long cmd, const void *data)
|
2003-09-21 23:16:48 +04:00
|
|
|
{
|
2005-05-30 02:24:14 +04:00
|
|
|
int id = *(const int *)data;
|
2003-09-21 23:16:48 +04:00
|
|
|
int error;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case TIOCSPGRP:
|
|
|
|
if (id < 0)
|
|
|
|
return (EINVAL);
|
|
|
|
id = -id;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id > 0 && !pfind(id))
|
|
|
|
return (ESRCH);
|
2008-03-22 00:53:35 +03:00
|
|
|
else if (id < 0 && (error = pgid_in_session(curproc, -id)))
|
2003-09-21 23:16:48 +04:00
|
|
|
return (error);
|
|
|
|
|
|
|
|
*pgid = id;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return descriptor owner information. If the value is positive,
|
|
|
|
* it's process ID. If it's negative, it's process group ID and
|
|
|
|
* needs the sign removed before use.
|
|
|
|
*/
|
|
|
|
int
|
2008-06-24 14:26:26 +04:00
|
|
|
fgetown(pid_t pgid, u_long cmd, void *data)
|
2003-09-21 23:16:48 +04:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
|
2003-09-21 23:16:48 +04:00
|
|
|
switch (cmd) {
|
|
|
|
case TIOCGPGRP:
|
|
|
|
*(int *)data = -pgid;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*(int *)data = pgid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send signal to descriptor owner, either process or process group.
|
|
|
|
*/
|
|
|
|
void
|
2003-09-22 16:59:55 +04:00
|
|
|
fownsignal(pid_t pgid, int signo, int code, int band, void *fdescdata)
|
2003-09-21 23:16:48 +04:00
|
|
|
{
|
2005-02-27 00:34:55 +03:00
|
|
|
ksiginfo_t ksi;
|
2003-09-21 23:16:48 +04:00
|
|
|
|
2008-04-24 19:35:27 +04:00
|
|
|
KASSERT(!cpu_intr_p());
|
|
|
|
|
2009-03-29 08:40:01 +04:00
|
|
|
if (pgid == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-12-06 13:02:22 +03:00
|
|
|
KSI_INIT(&ksi);
|
2003-09-22 16:59:55 +04:00
|
|
|
ksi.ksi_signo = signo;
|
2003-09-21 23:16:48 +04:00
|
|
|
ksi.ksi_code = code;
|
|
|
|
ksi.ksi_band = band;
|
|
|
|
|
2008-04-24 19:35:27 +04:00
|
|
|
mutex_enter(proc_lock);
|
2009-03-29 08:40:01 +04:00
|
|
|
if (pgid > 0) {
|
|
|
|
struct proc *p1;
|
|
|
|
|
|
|
|
p1 = p_find(pgid, PFIND_LOCKED);
|
|
|
|
if (p1 != NULL) {
|
|
|
|
kpsignal(p1, &ksi, fdescdata);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
struct pgrp *pgrp;
|
|
|
|
|
|
|
|
KASSERT(pgid < 0);
|
|
|
|
pgrp = pg_find(-pgid, PFIND_LOCKED);
|
|
|
|
if (pgrp != NULL) {
|
|
|
|
kpgsignal(pgrp, &ksi, fdescdata, 0);
|
|
|
|
}
|
|
|
|
}
|
2008-04-24 19:35:27 +04:00
|
|
|
mutex_exit(proc_lock);
|
2003-09-21 23:16:48 +04:00
|
|
|
}
|
2004-11-30 07:25:43 +03:00
|
|
|
|
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fd_clone(file_t *fp, unsigned fd, int flag, const struct fileops *fops,
|
|
|
|
void *data)
|
2004-11-30 07:25:43 +03:00
|
|
|
{
|
2008-03-22 00:53:35 +03:00
|
|
|
|
2005-02-13 02:14:03 +03:00
|
|
|
fp->f_flag = flag;
|
2004-11-30 07:25:43 +03:00
|
|
|
fp->f_type = DTYPE_MISC;
|
|
|
|
fp->f_ops = fops;
|
|
|
|
fp->f_data = data;
|
2008-03-22 00:53:35 +03:00
|
|
|
curlwp->l_dupfd = fd;
|
|
|
|
fd_affix(curproc, fp, fd);
|
2004-11-30 07:25:43 +03:00
|
|
|
|
|
|
|
return EMOVEFD;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fnullop_fcntl(file_t *fp, u_int cmd, void *data)
|
2004-11-30 07:25:43 +03:00
|
|
|
{
|
2006-11-01 13:17:58 +03:00
|
|
|
|
2004-11-30 07:25:43 +03:00
|
|
|
if (cmd == F_SETFL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fnullop_poll(file_t *fp, int which)
|
2004-11-30 07:25:43 +03:00
|
|
|
{
|
2006-11-01 13:17:58 +03:00
|
|
|
|
2004-11-30 07:25:43 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fnullop_kqfilter(file_t *fp, struct knote *kn)
|
2004-11-30 07:25:43 +03:00
|
|
|
{
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-04 14:12:51 +04:00
|
|
|
void
|
2009-12-20 12:36:05 +03:00
|
|
|
fnullop_restart(file_t *fp)
|
2009-04-04 14:12:51 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2007-09-07 22:56:02 +04:00
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fbadop_read(file_t *fp, off_t *offset, struct uio *uio,
|
|
|
|
kauth_cred_t cred, int flags)
|
2007-09-07 22:56:02 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fbadop_write(file_t *fp, off_t *offset, struct uio *uio,
|
|
|
|
kauth_cred_t cred, int flags)
|
2007-09-07 22:56:02 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fbadop_ioctl(file_t *fp, u_long com, void *data)
|
2007-09-07 22:56:02 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2004-11-30 07:25:43 +03:00
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fbadop_stat(file_t *fp, struct stat *sb)
|
2004-11-30 07:25:43 +03:00
|
|
|
{
|
2006-11-01 13:17:58 +03:00
|
|
|
|
2004-11-30 07:25:43 +03:00
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|
2007-09-07 22:56:02 +04:00
|
|
|
|
|
|
|
int
|
2008-03-22 00:53:35 +03:00
|
|
|
fbadop_close(file_t *fp)
|
2007-09-07 22:56:02 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
return EOPNOTSUPP;
|
|
|
|
}
|