aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMateusz Guzik <mjg@FreeBSD.org>2021-01-28 23:52:08 +0000
committerMateusz Guzik <mjg@FreeBSD.org>2021-02-01 12:39:18 +0000
commit2bf72739da6f54572597369a1b5892a124c6c9ce (patch)
tree6c66a0af1fbeb49f69ff4f76a54f382268e1fd52
parent233225ef7d5604162b6bda47e35fa7a8075bd559 (diff)
downloadsrc-2bf72739da6f54572597369a1b5892a124c6c9ce.tar.gz
src-2bf72739da6f54572597369a1b5892a124c6c9ce.zip
poll: use fget_unlocked or fget_only_user when feasible
This follows select by eleminating the use of filedesc lock. This is a win for single-threaded processes and a mixed bag for others as at small concurrency it is faster to take the lock instead of refing/unrefing each file descriptor. Nonetheless, removal of shared lock usage is a step towards a mtx-protected fd table. (cherry picked from commit 45e1f8541428c19f63dba65d78a8d138e1bc6915)
-rw-r--r--sys/kern/sys_generic.c75
1 files changed, 24 insertions, 51 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index dc2cd56f5077..6fcdee7a088f 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -1547,49 +1547,6 @@ sys_ppoll(struct thread *td, struct ppoll_args *uap)
return (kern_poll(td, uap->fds, uap->nfds, tsp, ssp));
}
-#ifdef CAPABILITIES
-static int
-poll_fget(struct filedesc *fdp, int fd, struct file **fpp)
-{
- const struct filedescent *fde;
- const struct fdescenttbl *fdt;
- const cap_rights_t *haverights;
- struct file *fp;
- int error;
-
- if (__predict_false(fd >= fdp->fd_nfiles))
- return (EBADF);
-
- fdt = fdp->fd_files;
- fde = &fdt->fdt_ofiles[fd];
- fp = fde->fde_file;
- if (__predict_false(fp == NULL))
- return (EBADF);
- haverights = cap_rights_fde_inline(fde);
- error = cap_check_inline(haverights, &cap_event_rights);
- if (__predict_false(error != 0))
- return (EBADF);
- *fpp = fp;
- return (0);
-}
-#else
-static int
-poll_fget(struct filedesc *fdp, int fd, struct file **fpp)
-{
- struct file *fp;
-
- if (__predict_false(fd >= fdp->fd_nfiles))
- return (EBADF);
-
- fp = fdp->fd_ofiles[fd].fde_file;
- if (__predict_false(fp == NULL))
- return (EBADF);
-
- *fpp = fp;
- return (0);
-}
-#endif
-
static int
pollrescan(struct thread *td)
{
@@ -1600,12 +1557,13 @@ pollrescan(struct thread *td)
struct filedesc *fdp;
struct file *fp;
struct pollfd *fd;
- int n;
+ int n, error;
+ bool only_user;
n = 0;
fdp = td->td_proc->p_fd;
stp = td->td_sel;
- FILEDESC_SLOCK(fdp);
+ only_user = FILEDESC_IS_ONLY_USER(fdp);
STAILQ_FOREACH_SAFE(sfp, &stp->st_selq, sf_link, sfn) {
fd = (struct pollfd *)sfp->sf_cookie;
si = sfp->sf_si;
@@ -1613,7 +1571,11 @@ pollrescan(struct thread *td)
/* If the selinfo wasn't cleared the event didn't fire. */
if (si != NULL)
continue;
- if (poll_fget(fdp, fd->fd, &fp) != 0) {
+ if (only_user)
+ error = fget_only_user(fdp, fd->fd, &cap_event_rights, &fp);
+ else
+ error = fget_unlocked(fdp, fd->fd, &cap_event_rights, &fp);
+ if (__predict_false(error != 0)) {
fd->revents = POLLNVAL;
n++;
continue;
@@ -1623,10 +1585,13 @@ pollrescan(struct thread *td)
* POLLERR if appropriate.
*/
fd->revents = fo_poll(fp, fd->events, td->td_ucred, td);
+ if (only_user)
+ fput_only_user(fdp, fp);
+ else
+ fdrop(fp, td);
if (fd->revents != 0)
n++;
}
- FILEDESC_SUNLOCK(fdp);
stp->st_flags = 0;
td->td_retval[0] = n;
return (0);
@@ -1658,17 +1623,22 @@ pollscan(struct thread *td, struct pollfd *fds, u_int nfd)
{
struct filedesc *fdp;
struct file *fp;
- int i, n;
+ int i, n, error;
+ bool only_user;
n = 0;
fdp = td->td_proc->p_fd;
- FILEDESC_SLOCK(fdp);
+ only_user = FILEDESC_IS_ONLY_USER(fdp);
for (i = 0; i < nfd; i++, fds++) {
if (fds->fd < 0) {
fds->revents = 0;
continue;
}
- if (poll_fget(fdp, fds->fd, &fp) != 0) {
+ if (only_user)
+ error = fget_only_user(fdp, fds->fd, &cap_event_rights, &fp);
+ else
+ error = fget_unlocked(fdp, fds->fd, &cap_event_rights, &fp);
+ if (__predict_false(error != 0)) {
fds->revents = POLLNVAL;
n++;
continue;
@@ -1680,6 +1650,10 @@ pollscan(struct thread *td, struct pollfd *fds, u_int nfd)
selfdalloc(td, fds);
fds->revents = fo_poll(fp, fds->events,
td->td_ucred, td);
+ if (only_user)
+ fput_only_user(fdp, fp);
+ else
+ fdrop(fp, td);
/*
* POSIX requires POLLOUT to be never
* set simultaneously with POLLHUP.
@@ -1690,7 +1664,6 @@ pollscan(struct thread *td, struct pollfd *fds, u_int nfd)
if (fds->revents != 0)
n++;
}
- FILEDESC_SUNLOCK(fdp);
td->td_retval[0] = n;
return (0);
}