aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Chagin <dchagin@FreeBSD.org>2021-06-10 12:11:25 +0000
committerDmitry Chagin <dchagin@FreeBSD.org>2021-06-10 12:11:25 +0000
commite884512ad143952f0dbacad631487ce28363fd08 (patch)
tree4aaee2526f9d0c6c08545a943fcd436b17bd06f7
parent981a60f112e213e7b8de04bf66588cab5c480b34 (diff)
downloadsrc-e884512ad143952f0dbacad631487ce28363fd08.tar.gz
src-e884512ad143952f0dbacad631487ce28363fd08.zip
Split kern_poll() on two counterparts.
The kern_poll_kfds() operates on clear kernel data, kfds points to an array in the kernel, while kern_poll() operates on user supplied pollfd. Move nfds check to kern_poll_maxfds(). No functional changes, it's for future use in the Linux emulation layer. Reviewd by: kib Differential Revision: https://reviews.freebsd.org/D30690 MFC after: 2 weeks
-rw-r--r--sys/kern/sys_generic.c83
-rw-r--r--sys/sys/syscallsubr.h3
2 files changed, 52 insertions, 34 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 6fcdee7a088f..c89a643cfcf9 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -1417,12 +1417,13 @@ sys_poll(struct thread *td, struct poll_args *uap)
return (kern_poll(td, uap->fds, uap->nfds, tsp, NULL));
}
+/*
+ * kfds points to an array in the kernel.
+ */
int
-kern_poll(struct thread *td, struct pollfd *ufds, u_int nfds,
+kern_poll_kfds(struct thread *td, struct pollfd *kfds, u_int nfds,
struct timespec *tsp, sigset_t *uset)
{
- struct pollfd *kfds;
- struct pollfd stackfds[32];
sbintime_t sbt, precision, tmp;
time_t over;
struct timespec ts;
@@ -1453,28 +1454,11 @@ kern_poll(struct thread *td, struct pollfd *ufds, u_int nfds,
} else
sbt = -1;
- /*
- * This is kinda bogus. We have fd limits, but that is not
- * really related to the size of the pollfd array. Make sure
- * we let the process use at least FD_SETSIZE entries and at
- * least enough for the system-wide limits. We want to be reasonably
- * safe, but not overly restrictive.
- */
- if (nfds > maxfilesperproc && nfds > FD_SETSIZE)
- return (EINVAL);
- if (nfds > nitems(stackfds))
- kfds = mallocarray(nfds, sizeof(*kfds), M_TEMP, M_WAITOK);
- else
- kfds = stackfds;
- error = copyin(ufds, kfds, nfds * sizeof(*kfds));
- if (error)
- goto done;
-
if (uset != NULL) {
error = kern_sigprocmask(td, SIG_SETMASK, uset,
&td->td_oldsigmask, 0);
if (error)
- goto done;
+ return (error);
td->td_pflags |= TDP_OLDMASK;
/*
* Make sure that ast() is called on return to
@@ -1501,20 +1485,11 @@ kern_poll(struct thread *td, struct pollfd *ufds, u_int nfds,
}
seltdclear(td);
-done:
/* poll is not restarted after signals... */
if (error == ERESTART)
error = EINTR;
if (error == EWOULDBLOCK)
error = 0;
- if (error == 0) {
- error = pollout(td, kfds, ufds, nfds);
- if (error)
- goto out;
- }
-out:
- if (nfds > nitems(stackfds))
- free(kfds, M_TEMP);
return (error);
}
@@ -1539,12 +1514,52 @@ sys_ppoll(struct thread *td, struct ppoll_args *uap)
ssp = &set;
} else
ssp = NULL;
+ return (kern_poll(td, uap->fds, uap->nfds, tsp, ssp));
+}
+
+/*
+ * ufds points to an array in user space.
+ */
+int
+kern_poll(struct thread *td, struct pollfd *ufds, u_int nfds,
+ struct timespec *tsp, sigset_t *set)
+{
+ struct pollfd *kfds;
+ struct pollfd stackfds[32];
+ int error;
+
+ if (kern_poll_maxfds(nfds))
+ return (EINVAL);
+ if (nfds > nitems(stackfds))
+ kfds = mallocarray(nfds, sizeof(*kfds), M_TEMP, M_WAITOK);
+ else
+ kfds = stackfds;
+ error = copyin(ufds, kfds, nfds * sizeof(*kfds));
+ if (error != 0)
+ goto out;
+
+ error = kern_poll_kfds(td, kfds, nfds, tsp, set);
+ if (error == 0)
+ error = pollout(td, kfds, ufds, nfds);
+
+out:
+ if (nfds > nitems(stackfds))
+ free(kfds, M_TEMP);
+ return (error);
+}
+
+bool
+kern_poll_maxfds(u_int nfds)
+{
+
/*
- * fds is still a pointer to user space. kern_poll() will
- * take care of copyin that array to the kernel space.
+ * This is kinda bogus. We have fd limits, but that is not
+ * really related to the size of the pollfd array. Make sure
+ * we let the process use at least FD_SETSIZE entries and at
+ * least enough for the system-wide limits. We want to be reasonably
+ * safe, but not overly restrictive.
*/
-
- return (kern_poll(td, uap->fds, uap->nfds, tsp, ssp));
+ return (nfds > maxfilesperproc && nfds > FD_SETSIZE);
}
static int
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index 471c38ab0e12..eb7b82946988 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -225,6 +225,9 @@ int kern_pipe(struct thread *td, int fildes[2], int flags,
struct filecaps *fcaps1, struct filecaps *fcaps2);
int kern_poll(struct thread *td, struct pollfd *fds, u_int nfds,
struct timespec *tsp, sigset_t *uset);
+int kern_poll_kfds(struct thread *td, struct pollfd *fds, u_int nfds,
+ struct timespec *tsp, sigset_t *uset);
+bool kern_poll_maxfds(u_int nfds);
int kern_posix_error(struct thread *td, int error);
int kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len,
int advice);