diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 80376910155..843e683747c 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -144,6 +144,7 @@ static void filecaps_free_finish(u_long *ioctls); #define NDSLOT(x) ((x) / NDENTRIES) #define NDBIT(x) ((NDSLOTTYPE)1 << ((x) % NDENTRIES)) #define NDSLOTS(x) (((x) + NDENTRIES - 1) / NDENTRIES) +#define NFD2MAPSIZE(x) (NDSLOTS(x) * NDSLOTSIZE) /* * SLIST entry used to keep track of ofiles which must be reclaimed when @@ -1680,7 +1681,7 @@ fdgrowtable(struct filedesc *fdp, int nfd) * entries than the table can hold. */ if (NDSLOTS(nnfiles) > NDSLOTS(onfiles)) { - nmap = malloc(NDSLOTS(nnfiles) * NDSLOTSIZE, M_FILEDESC, + nmap = malloc(NFD2MAPSIZE(nnfiles), M_FILEDESC, M_ZERO | M_WAITOK); /* copy over the old data and update the pointer */ memcpy(nmap, omap, NDSLOTS(onfiles) * sizeof(*omap)); @@ -3313,6 +3314,55 @@ static SYSCTL_NODE(_kern_proc, KERN_PROC_NFDS, nfds, CTLFLAG_RD|CTLFLAG_CAPRD|CTLFLAG_MPSAFE, sysctl_kern_proc_nfds, "Number of open file descriptors"); +static int +sysctl_kern_proc_fdmap(SYSCTL_HANDLER_ARGS) +{ + struct filedesc *fdp; + NDSLOTTYPE lmap[NDSLOTS(NDFILE) * 16]; + NDSLOTTYPE *map; + size_t bsize, csize; + int error; + + CTASSERT(sizeof(lmap) <= 128); + + if (*(int *)arg1 != 0) + return (EINVAL); + + fdp = curproc->p_fd; + + if (req->oldptr == NULL) + return (SYSCTL_OUT(req, NULL, NFD2MAPSIZE(fdp->fd_nfiles))); + + if (curproc->p_numthreads == 1 && fdp->fd_refcnt == 1) + /* No need to lock anything as only we can modify the map. */ + return (SYSCTL_OUT(req, fdp->fd_map, NFD2MAPSIZE(fdp->fd_nfiles))); + + /* Potential other threads modifying the map. */ + map = lmap; + bsize = sizeof(lmap); + for (;;) { + FILEDESC_SLOCK(fdp); + csize = NFD2MAPSIZE(fdp->fd_nfiles); + if (bsize >= csize) + break; + FILEDESC_SUNLOCK(fdp); + if (map != lmap) + free(map, M_TEMP); + bsize = csize; + map = malloc(bsize, M_TEMP, M_WAITOK); + } + memcpy(map, fdp->fd_map, csize); + FILEDESC_SUNLOCK(fdp); + error = SYSCTL_OUT(req, map, csize); + if (map != lmap) + free(map, M_TEMP); + return (error); +} + +static SYSCTL_NODE(_kern_proc, KERN_PROC_FDMAP, fdmap, + CTLFLAG_RD|CTLFLAG_CAPRD|CTLFLAG_MPSAFE, sysctl_kern_proc_fdmap, + "File descriptor map"); + /* * Get file structures globally. */ diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h index 9cf4b901e58..79dc2df546d 100644 --- a/sys/sys/sysctl.h +++ b/sys/sys/sysctl.h @@ -977,6 +977,7 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry); #define KERN_PROC_SIGTRAMP 41 /* signal trampoline location */ #define KERN_PROC_CWD 42 /* process current working directory */ #define KERN_PROC_NFDS 43 /* number of open file descriptors */ +#define KERN_PROC_FDMAP 44 /* file descriptor map */ /* * KERN_IPC identifiers