fs/poll: Fix poll_notify for CONFIG_BUILD_KERNEL

With flat addressing the user pollfd list is given directly to the
drivers that perform the notification. This is fine when the addressing
is flat, as there is no ambiguity on who gets notified and the fds memory
is always mapped.

For kernel mode with MMU this does not work. The notification must be done
via a temporary buffer allocated from kernel memory.

Thus, create a copy of the user fds and pass the copy to the drivers.
Afterwards copy the output events back to the user.
This commit is contained in:
Ville Juven 2023-01-10 17:24:34 +02:00 committed by Xiang Xiao
parent 3ea7a6fb77
commit f730cf8ad8

View File

@ -441,6 +441,7 @@ int file_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout) int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout)
{ {
struct pollfd *kfds;
sem_t sem; sem_t sem;
int count = 0; int count = 0;
int ret2; int ret2;
@ -452,8 +453,29 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout)
enter_cancellation_point(); enter_cancellation_point();
#ifdef CONFIG_BUILD_KERNEL
/* Allocate kernel memory for the fds */
kfds = kmm_malloc(nfds * sizeof(struct pollfd));
if (!kfds)
{
/* Out of memory */
ret = ENOMEM;
goto out_with_cancelpt;
}
/* Copy the user fds to neutral kernel memory */
memcpy(kfds, fds, nfds * sizeof(struct pollfd));
#else
/* Can use the user fds directly */
kfds = fds;
#endif
nxsem_init(&sem, 0, 0); nxsem_init(&sem, 0, 0);
ret = poll_setup(fds, nfds, &sem); ret = poll_setup(kfds, nfds, &sem);
if (ret >= 0) if (ret >= 0)
{ {
if (timeout == 0) if (timeout == 0)
@ -519,7 +541,7 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout)
* Preserve ret, if negative, since it holds the result of the wait. * Preserve ret, if negative, since it holds the result of the wait.
*/ */
ret2 = poll_teardown(fds, nfds, &count, ret); ret2 = poll_teardown(kfds, nfds, &count, ret);
if (ret2 < 0 && ret >= 0) if (ret2 < 0 && ret >= 0)
{ {
ret = ret2; ret = ret2;
@ -527,6 +549,26 @@ int poll(FAR struct pollfd *fds, nfds_t nfds, int timeout)
} }
nxsem_destroy(&sem); nxsem_destroy(&sem);
#ifdef CONFIG_BUILD_KERNEL
/* Copy the events back to user */
if (ret == OK)
{
int i;
for (i = 0; i < nfds; i++)
{
fds[i].revents = kfds[i].revents;
}
}
/* Free the temporary buffer */
kmm_free(kfds);
out_with_cancelpt:
#endif
leave_cancellation_point(); leave_cancellation_point();
if (ret < 0) if (ret < 0)