use a two-level bitmap as suggested by mogul and banga for fdalloc;

approved thorpej@
This commit is contained in:
provos 2003-10-30 07:27:02 +00:00
parent 654720aaa9
commit 4b425670af
2 changed files with 159 additions and 16 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_descrip.c,v 1.114 2003/09/22 12:59:55 christos Exp $ */
/* $NetBSD: kern_descrip.c,v 1.115 2003/10/30 07:27:02 provos Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_descrip.c,v 1.114 2003/09/22 12:59:55 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_descrip.c,v 1.115 2003/10/30 07:27:02 provos Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -82,7 +82,9 @@ MALLOC_DEFINE(M_IOCTLOPS, "ioctlops", "ioctl data buffer");
static __inline void fd_used(struct filedesc *, int);
static __inline void fd_unused(struct filedesc *, int);
static __inline int find_next_zero(uint32_t *, int, u_int);
int finishdup(struct proc *, int, int, register_t *);
int find_last_set(struct filedesc *, int);
int fcntl_forfs(int, struct proc *, int, void *);
dev_type_open(filedescopen);
@ -92,9 +94,70 @@ const struct cdevsw filedesc_cdevsw = {
nostop, notty, nopoll, nommap, nokqfilter,
};
static __inline int
find_next_zero(uint32_t *bitmap, int want, u_int bits)
{
int i, off, maxoff;
uint32_t sub;
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;
}
int
find_last_set(struct filedesc *fd, int last)
{
int off, i;
struct file **ofiles = fd->fd_ofiles;
uint32_t *bitmap = fd->fd_lomap;
off = (last - 1) >> NDENTRYSHIFT;
while (!bitmap[off] && off >= 0)
off--;
if (off < 0)
return (0);
i = ((off + 1) << NDENTRYSHIFT) - 1;
if (i >= last)
i = last - 1;
while (i > 0 && ofiles[i] == NULL)
i--;
return (i);
}
static __inline void
fd_used(struct filedesc *fdp, int fd)
{
u_int off = fd >> NDENTRYSHIFT;
fdp->fd_lomap[off] |= 1 << (fd & NDENTRYMASK);
if (fdp->fd_lomap[off] == ~0)
fdp->fd_himap[off >> NDENTRYSHIFT] |= 1 << (off & NDENTRYMASK);
if (fd > fdp->fd_lastfile)
fdp->fd_lastfile = fd;
@ -103,19 +166,21 @@ fd_used(struct filedesc *fdp, int fd)
static __inline void
fd_unused(struct filedesc *fdp, int fd)
{
u_int off = fd >> NDENTRYSHIFT;
if (fd < fdp->fd_freefile)
fdp->fd_freefile = fd;
if (fdp->fd_lomap[off] == ~0)
fdp->fd_himap[off >> NDENTRYSHIFT] &= ~(1 << (off & NDENTRYMASK));
fdp->fd_lomap[off] &= ~(1 << (fd & NDENTRYMASK));
#ifdef DIAGNOSTIC
if (fd > fdp->fd_lastfile)
panic("fd_unused: fd_lastfile inconsistent");
#endif
if (fd == fdp->fd_lastfile) {
do {
fd--;
} while (fd >= 0 && fdp->fd_ofiles[fd] == NULL);
fdp->fd_lastfile = fd;
}
if (fd == fdp->fd_lastfile)
fdp->fd_lastfile = find_last_set(fdp, fd);
}
/*
@ -646,6 +711,7 @@ fdalloc(struct proc *p, int want, int *result)
{
struct filedesc *fdp;
int i, lim, last;
u_int off, new;
fdp = p->p_fd;
@ -656,15 +722,32 @@ fdalloc(struct proc *p, int want, int *result)
*/
lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
last = min(fdp->fd_nfiles, lim);
again:
if ((i = want) < fdp->fd_freefile)
i = fdp->fd_freefile;
for (; i < last; i++) {
if (fdp->fd_ofiles[i] == NULL) {
fd_used(fdp, i);
if (want <= fdp->fd_freefile)
fdp->fd_freefile = i;
*result = i;
return (0);
off = i >> NDENTRYSHIFT;
new = find_next_zero(fdp->fd_himap, off,
(last + NDENTRIES - 1) >> NDENTRYSHIFT);
if (new != -1) {
i = find_next_zero(&fdp->fd_lomap[new],
new > off ? 0 : i & NDENTRYMASK, NDENTRIES);
if (i == -1) {
/*
* free file descriptor in this block was
* below want, try again with higher want.
*/
want = (new + 1) << NDENTRYSHIFT;
goto again;
}
i += (new << NDENTRYSHIFT);
if (i < last) {
if (fdp->fd_ofiles[i] == NULL) {
fd_used(fdp, i);
if (want <= fdp->fd_freefile)
fdp->fd_freefile = i;
*result = i;
return (0);
}
}
}
@ -683,6 +766,7 @@ fdexpand(struct proc *p)
int i, nfiles;
struct file **newofile;
char *newofileflags;
uint32_t *newhimap, *newlomap;
fdp = p->p_fd;
@ -705,6 +789,31 @@ fdexpand(struct proc *p)
memset(newofileflags + i, 0, nfiles * sizeof(char) - i);
if (fdp->fd_nfiles > NDFILE)
free(fdp->fd_ofiles, M_FILEDESC);
if (NDHISLOTS(nfiles) > NDHISLOTS(fdp->fd_nfiles)) {
newhimap = malloc(NDHISLOTS(nfiles) * sizeof(uint32_t),
M_FILEDESC, M_WAITOK);
newlomap = malloc(NDLOSLOTS(nfiles) * sizeof(uint32_t),
M_FILEDESC, M_WAITOK);
memcpy(newhimap, fdp->fd_himap,
(i = NDHISLOTS(fdp->fd_nfiles) * sizeof(uint32_t)));
memset((char *)newhimap + i, 0,
NDHISLOTS(nfiles) * sizeof(uint32_t) - i);
memcpy(newlomap, fdp->fd_lomap,
(i = NDLOSLOTS(fdp->fd_nfiles) * sizeof(uint32_t)));
memset((char *)newlomap + i, 0,
NDLOSLOTS(nfiles) * sizeof(uint32_t) - i);
if (NDHISLOTS(fdp->fd_nfiles) > NDHISLOTS(NDFILE)) {
free(fdp->fd_himap, M_FILEDESC);
free(fdp->fd_lomap, M_FILEDESC);
}
fdp->fd_himap = newhimap;
fdp->fd_lomap = newlomap;
}
fdp->fd_ofiles = newofile;
fdp->fd_ofileflags = newofileflags;
fdp->fd_nfiles = nfiles;
@ -772,6 +881,7 @@ falloc(struct proc *p, struct file **resultfp, int *resultfd)
if (nfiles >= maxfiles) {
tablefull("file", "increase kern.maxfiles or MAXFILES");
simple_unlock(&filelist_slock);
fd_unused(p->p_fd, i);
pool_put(&file_pool, fp);
return (ENFILE);
}
@ -927,6 +1037,8 @@ fdinit1(struct filedesc0 *newfdp)
newfdp->fd_fd.fd_ofileflags = newfdp->fd_dfileflags;
newfdp->fd_fd.fd_nfiles = NDFILE;
newfdp->fd_fd.fd_knlistsize = -1;
newfdp->fd_fd.fd_himap = newfdp->fd_dhimap;
newfdp->fd_fd.fd_lomap = newfdp->fd_dlomap;
}
/*
@ -1008,9 +1120,23 @@ fdcopy(struct proc *p)
newfdp->fd_ofiles = malloc(i * OFILESIZE, M_FILEDESC, M_WAITOK);
newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
}
if (NDHISLOTS(i) <= NDHISLOTS(NDFILE)) {
newfdp->fd_himap =
((struct filedesc0 *) newfdp)->fd_dhimap;
newfdp->fd_lomap =
((struct filedesc0 *) newfdp)->fd_dlomap;
} else {
newfdp->fd_himap = malloc(NDHISLOTS(i) * sizeof(uint32_t),
M_FILEDESC, M_WAITOK);
newfdp->fd_lomap = malloc(NDLOSLOTS(i) * sizeof(uint32_t),
M_FILEDESC, M_WAITOK);
}
newfdp->fd_nfiles = i;
memcpy(newfdp->fd_ofiles, fdp->fd_ofiles, i * sizeof(struct file **));
memcpy(newfdp->fd_ofileflags, fdp->fd_ofileflags, i * sizeof(char));
memcpy(newfdp->fd_himap, fdp->fd_himap, NDHISLOTS(i)*sizeof(uint32_t));
memcpy(newfdp->fd_lomap, fdp->fd_lomap, NDLOSLOTS(i)*sizeof(uint32_t));
/*
* kq descriptors cannot be copied.
*/
@ -1060,6 +1186,10 @@ fdfree(struct proc *p)
p->p_fd = NULL;
if (fdp->fd_nfiles > NDFILE)
free(fdp->fd_ofiles, M_FILEDESC);
if (NDHISLOTS(fdp->fd_nfiles) > NDHISLOTS(NDFILE)) {
free(fdp->fd_himap, M_FILEDESC);
free(fdp->fd_lomap, M_FILEDESC);
}
if (fdp->fd_knlist)
free(fdp->fd_knlist, M_KEVENT);
if (fdp->fd_knhash)

View File

@ -1,4 +1,4 @@
/* $NetBSD: filedesc.h,v 1.30 2003/08/07 16:34:04 agc Exp $ */
/* $NetBSD: filedesc.h,v 1.31 2003/10/30 07:27:02 provos Exp $ */
/*
* Copyright (c) 1990, 1993
@ -50,11 +50,18 @@
*/
#define NDFILE 20
#define NDEXTENT 50 /* 250 bytes in 256-byte alloc */
#define NDENTRIES 32 /* 32 fds per entry */
#define NDENTRYMASK (NDENTRIES - 1)
#define NDENTRYSHIFT 5 /* bits per entry */
#define NDLOSLOTS(x) (((x) + NDENTRIES - 1) >> NDENTRYSHIFT)
#define NDHISLOTS(x) ((NDLOSLOTS(x) + NDENTRIES - 1) >> NDENTRYSHIFT)
struct filedesc {
struct file **fd_ofiles; /* file structures for open files */
char *fd_ofileflags; /* per-process open file flags */
int fd_nfiles; /* number of open files allocated */
uint32_t *fd_himap; /* each bit points to 32 fds */
uint32_t *fd_lomap; /* bitmap of free fds */
int fd_lastfile; /* high-water mark of fd_ofiles */
int fd_freefile; /* approx. next free file */
int fd_refcnt; /* reference count */
@ -91,6 +98,12 @@ struct filedesc0 {
*/
struct file *fd_dfiles[NDFILE];
char fd_dfileflags[NDFILE];
/*
* These arrays are used when the number of open files is
* <= 1024, and are then pointed to by the pointers above.
*/
uint32_t fd_dhimap[NDENTRIES >> NDENTRYSHIFT];
uint32_t fd_dlomap[NDENTRIES];
};
/*