18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * This file contains the procedures for the handling of select and poll
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Created for Linux based loosely upon Mathius Lattner's minix
68c2ecf20Sopenharmony_ci * patches by Peter MacDonald. Heavily edited by Linus.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  4 February 1994
98c2ecf20Sopenharmony_ci *     COFF/ELF binary emulation. If the process has the STICKY_TIMEOUTS
108c2ecf20Sopenharmony_ci *     flag set in its personality we do *not* modify the given timeout
118c2ecf20Sopenharmony_ci *     parameter to reflect time remaining.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *  24 January 2000
148c2ecf20Sopenharmony_ci *     Changed sys_poll()/do_poll() to use PAGE_SIZE chunk-based allocation
158c2ecf20Sopenharmony_ci *     of fds to overcome nfds < 16390 descriptors limit (Tigran Aivazian).
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
208c2ecf20Sopenharmony_ci#include <linux/sched/rt.h>
218c2ecf20Sopenharmony_ci#include <linux/syscalls.h>
228c2ecf20Sopenharmony_ci#include <linux/export.h>
238c2ecf20Sopenharmony_ci#include <linux/slab.h>
248c2ecf20Sopenharmony_ci#include <linux/poll.h>
258c2ecf20Sopenharmony_ci#include <linux/personality.h> /* for STICKY_TIMEOUTS */
268c2ecf20Sopenharmony_ci#include <linux/file.h>
278c2ecf20Sopenharmony_ci#include <linux/fdtable.h>
288c2ecf20Sopenharmony_ci#include <linux/fs.h>
298c2ecf20Sopenharmony_ci#include <linux/rcupdate.h>
308c2ecf20Sopenharmony_ci#include <linux/hrtimer.h>
318c2ecf20Sopenharmony_ci#include <linux/freezer.h>
328c2ecf20Sopenharmony_ci#include <net/busy_poll.h>
338c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * Estimate expected accuracy in ns from a timeval.
408c2ecf20Sopenharmony_ci *
418c2ecf20Sopenharmony_ci * After quite a bit of churning around, we've settled on
428c2ecf20Sopenharmony_ci * a simple thing of taking 0.1% of the timeout as the
438c2ecf20Sopenharmony_ci * slack, with a cap of 100 msec.
448c2ecf20Sopenharmony_ci * "nice" tasks get a 0.5% slack instead.
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * Consider this comment an open invitation to come up with even
478c2ecf20Sopenharmony_ci * better solutions..
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define MAX_SLACK	(100 * NSEC_PER_MSEC)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic long __estimate_accuracy(struct timespec64 *tv)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	long slack;
558c2ecf20Sopenharmony_ci	int divfactor = 1000;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	if (tv->tv_sec < 0)
588c2ecf20Sopenharmony_ci		return 0;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (task_nice(current) > 0)
618c2ecf20Sopenharmony_ci		divfactor = divfactor / 5;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (tv->tv_sec > MAX_SLACK / (NSEC_PER_SEC/divfactor))
648c2ecf20Sopenharmony_ci		return MAX_SLACK;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	slack = tv->tv_nsec / divfactor;
678c2ecf20Sopenharmony_ci	slack += tv->tv_sec * (NSEC_PER_SEC/divfactor);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (slack > MAX_SLACK)
708c2ecf20Sopenharmony_ci		return MAX_SLACK;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return slack;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciu64 select_estimate_accuracy(struct timespec64 *tv)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	u64 ret;
788c2ecf20Sopenharmony_ci	struct timespec64 now;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/*
818c2ecf20Sopenharmony_ci	 * Realtime tasks get a slack of 0 for obvious reasons.
828c2ecf20Sopenharmony_ci	 */
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (rt_task(current))
858c2ecf20Sopenharmony_ci		return 0;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	ktime_get_ts64(&now);
888c2ecf20Sopenharmony_ci	now = timespec64_sub(*tv, now);
898c2ecf20Sopenharmony_ci	ret = __estimate_accuracy(&now);
908c2ecf20Sopenharmony_ci	if (ret < current->timer_slack_ns)
918c2ecf20Sopenharmony_ci		return current->timer_slack_ns;
928c2ecf20Sopenharmony_ci	return ret;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistruct poll_table_page {
988c2ecf20Sopenharmony_ci	struct poll_table_page * next;
998c2ecf20Sopenharmony_ci	struct poll_table_entry * entry;
1008c2ecf20Sopenharmony_ci	struct poll_table_entry entries[];
1018c2ecf20Sopenharmony_ci};
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define POLL_TABLE_FULL(table) \
1048c2ecf20Sopenharmony_ci	((unsigned long)((table)->entry+1) > PAGE_SIZE + (unsigned long)(table))
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/*
1078c2ecf20Sopenharmony_ci * Ok, Peter made a complicated, but straightforward multiple_wait() function.
1088c2ecf20Sopenharmony_ci * I have rewritten this, taking some shortcuts: This code may not be easy to
1098c2ecf20Sopenharmony_ci * follow, but it should be free of race-conditions, and it's practical. If you
1108c2ecf20Sopenharmony_ci * understand what I'm doing here, then you understand how the linux
1118c2ecf20Sopenharmony_ci * sleep/wakeup mechanism works.
1128c2ecf20Sopenharmony_ci *
1138c2ecf20Sopenharmony_ci * Two very simple procedures, poll_wait() and poll_freewait() make all the
1148c2ecf20Sopenharmony_ci * work.  poll_wait() is an inline-function defined in <linux/poll.h>,
1158c2ecf20Sopenharmony_ci * as all select/poll functions have to call it to add an entry to the
1168c2ecf20Sopenharmony_ci * poll table.
1178c2ecf20Sopenharmony_ci */
1188c2ecf20Sopenharmony_cistatic void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
1198c2ecf20Sopenharmony_ci		       poll_table *p);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_civoid poll_initwait(struct poll_wqueues *pwq)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	init_poll_funcptr(&pwq->pt, __pollwait);
1248c2ecf20Sopenharmony_ci	pwq->polling_task = current;
1258c2ecf20Sopenharmony_ci	pwq->triggered = 0;
1268c2ecf20Sopenharmony_ci	pwq->error = 0;
1278c2ecf20Sopenharmony_ci	pwq->table = NULL;
1288c2ecf20Sopenharmony_ci	pwq->inline_index = 0;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(poll_initwait);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic void free_poll_entry(struct poll_table_entry *entry)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	remove_wait_queue(entry->wait_address, &entry->wait);
1358c2ecf20Sopenharmony_ci	fput(entry->filp);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_civoid poll_freewait(struct poll_wqueues *pwq)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct poll_table_page * p = pwq->table;
1418c2ecf20Sopenharmony_ci	int i;
1428c2ecf20Sopenharmony_ci	for (i = 0; i < pwq->inline_index; i++)
1438c2ecf20Sopenharmony_ci		free_poll_entry(pwq->inline_entries + i);
1448c2ecf20Sopenharmony_ci	while (p) {
1458c2ecf20Sopenharmony_ci		struct poll_table_entry * entry;
1468c2ecf20Sopenharmony_ci		struct poll_table_page *old;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci		entry = p->entry;
1498c2ecf20Sopenharmony_ci		do {
1508c2ecf20Sopenharmony_ci			entry--;
1518c2ecf20Sopenharmony_ci			free_poll_entry(entry);
1528c2ecf20Sopenharmony_ci		} while (entry > p->entries);
1538c2ecf20Sopenharmony_ci		old = p;
1548c2ecf20Sopenharmony_ci		p = p->next;
1558c2ecf20Sopenharmony_ci		free_page((unsigned long) old);
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(poll_freewait);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic struct poll_table_entry *poll_get_entry(struct poll_wqueues *p)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct poll_table_page *table = p->table;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (p->inline_index < N_INLINE_POLL_ENTRIES)
1658c2ecf20Sopenharmony_ci		return p->inline_entries + p->inline_index++;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	if (!table || POLL_TABLE_FULL(table)) {
1688c2ecf20Sopenharmony_ci		struct poll_table_page *new_table;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci		new_table = (struct poll_table_page *) __get_free_page(GFP_KERNEL);
1718c2ecf20Sopenharmony_ci		if (!new_table) {
1728c2ecf20Sopenharmony_ci			p->error = -ENOMEM;
1738c2ecf20Sopenharmony_ci			return NULL;
1748c2ecf20Sopenharmony_ci		}
1758c2ecf20Sopenharmony_ci		new_table->entry = new_table->entries;
1768c2ecf20Sopenharmony_ci		new_table->next = table;
1778c2ecf20Sopenharmony_ci		p->table = new_table;
1788c2ecf20Sopenharmony_ci		table = new_table;
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	return table->entry++;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic int __pollwake(wait_queue_entry_t *wait, unsigned mode, int sync, void *key)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct poll_wqueues *pwq = wait->private;
1878c2ecf20Sopenharmony_ci	DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	/*
1908c2ecf20Sopenharmony_ci	 * Although this function is called under waitqueue lock, LOCK
1918c2ecf20Sopenharmony_ci	 * doesn't imply write barrier and the users expect write
1928c2ecf20Sopenharmony_ci	 * barrier semantics on wakeup functions.  The following
1938c2ecf20Sopenharmony_ci	 * smp_wmb() is equivalent to smp_wmb() in try_to_wake_up()
1948c2ecf20Sopenharmony_ci	 * and is paired with smp_store_mb() in poll_schedule_timeout.
1958c2ecf20Sopenharmony_ci	 */
1968c2ecf20Sopenharmony_ci	smp_wmb();
1978c2ecf20Sopenharmony_ci	pwq->triggered = 1;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/*
2008c2ecf20Sopenharmony_ci	 * Perform the default wake up operation using a dummy
2018c2ecf20Sopenharmony_ci	 * waitqueue.
2028c2ecf20Sopenharmony_ci	 *
2038c2ecf20Sopenharmony_ci	 * TODO: This is hacky but there currently is no interface to
2048c2ecf20Sopenharmony_ci	 * pass in @sync.  @sync is scheduled to be removed and once
2058c2ecf20Sopenharmony_ci	 * that happens, wake_up_process() can be used directly.
2068c2ecf20Sopenharmony_ci	 */
2078c2ecf20Sopenharmony_ci	return default_wake_function(&dummy_wait, mode, sync, key);
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic int pollwake(wait_queue_entry_t *wait, unsigned mode, int sync, void *key)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct poll_table_entry *entry;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	entry = container_of(wait, struct poll_table_entry, wait);
2158c2ecf20Sopenharmony_ci	if (key && !(key_to_poll(key) & entry->key))
2168c2ecf20Sopenharmony_ci		return 0;
2178c2ecf20Sopenharmony_ci	return __pollwake(wait, mode, sync, key);
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/* Add a new entry */
2218c2ecf20Sopenharmony_cistatic void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
2228c2ecf20Sopenharmony_ci				poll_table *p)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
2258c2ecf20Sopenharmony_ci	struct poll_table_entry *entry = poll_get_entry(pwq);
2268c2ecf20Sopenharmony_ci	if (!entry)
2278c2ecf20Sopenharmony_ci		return;
2288c2ecf20Sopenharmony_ci	entry->filp = get_file(filp);
2298c2ecf20Sopenharmony_ci	entry->wait_address = wait_address;
2308c2ecf20Sopenharmony_ci	entry->key = p->_key;
2318c2ecf20Sopenharmony_ci	init_waitqueue_func_entry(&entry->wait, pollwake);
2328c2ecf20Sopenharmony_ci	entry->wait.private = pwq;
2338c2ecf20Sopenharmony_ci	add_wait_queue(wait_address, &entry->wait);
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int poll_schedule_timeout(struct poll_wqueues *pwq, int state,
2378c2ecf20Sopenharmony_ci			  ktime_t *expires, unsigned long slack)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	int rc = -EINTR;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	set_current_state(state);
2428c2ecf20Sopenharmony_ci	if (!pwq->triggered)
2438c2ecf20Sopenharmony_ci		rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS);
2448c2ecf20Sopenharmony_ci	__set_current_state(TASK_RUNNING);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/*
2478c2ecf20Sopenharmony_ci	 * Prepare for the next iteration.
2488c2ecf20Sopenharmony_ci	 *
2498c2ecf20Sopenharmony_ci	 * The following smp_store_mb() serves two purposes.  First, it's
2508c2ecf20Sopenharmony_ci	 * the counterpart rmb of the wmb in pollwake() such that data
2518c2ecf20Sopenharmony_ci	 * written before wake up is always visible after wake up.
2528c2ecf20Sopenharmony_ci	 * Second, the full barrier guarantees that triggered clearing
2538c2ecf20Sopenharmony_ci	 * doesn't pass event check of the next iteration.  Note that
2548c2ecf20Sopenharmony_ci	 * this problem doesn't exist for the first iteration as
2558c2ecf20Sopenharmony_ci	 * add_wait_queue() has full barrier semantics.
2568c2ecf20Sopenharmony_ci	 */
2578c2ecf20Sopenharmony_ci	smp_store_mb(pwq->triggered, 0);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return rc;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci/**
2638c2ecf20Sopenharmony_ci * poll_select_set_timeout - helper function to setup the timeout value
2648c2ecf20Sopenharmony_ci * @to:		pointer to timespec64 variable for the final timeout
2658c2ecf20Sopenharmony_ci * @sec:	seconds (from user space)
2668c2ecf20Sopenharmony_ci * @nsec:	nanoseconds (from user space)
2678c2ecf20Sopenharmony_ci *
2688c2ecf20Sopenharmony_ci * Note, we do not use a timespec for the user space value here, That
2698c2ecf20Sopenharmony_ci * way we can use the function for timeval and compat interfaces as well.
2708c2ecf20Sopenharmony_ci *
2718c2ecf20Sopenharmony_ci * Returns -EINVAL if sec/nsec are not normalized. Otherwise 0.
2728c2ecf20Sopenharmony_ci */
2738c2ecf20Sopenharmony_ciint poll_select_set_timeout(struct timespec64 *to, time64_t sec, long nsec)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	struct timespec64 ts = {.tv_sec = sec, .tv_nsec = nsec};
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if (!timespec64_valid(&ts))
2788c2ecf20Sopenharmony_ci		return -EINVAL;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* Optimize for the zero timeout value here */
2818c2ecf20Sopenharmony_ci	if (!sec && !nsec) {
2828c2ecf20Sopenharmony_ci		to->tv_sec = to->tv_nsec = 0;
2838c2ecf20Sopenharmony_ci	} else {
2848c2ecf20Sopenharmony_ci		ktime_get_ts64(to);
2858c2ecf20Sopenharmony_ci		*to = timespec64_add_safe(*to, ts);
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci	return 0;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cienum poll_time_type {
2918c2ecf20Sopenharmony_ci	PT_TIMEVAL = 0,
2928c2ecf20Sopenharmony_ci	PT_OLD_TIMEVAL = 1,
2938c2ecf20Sopenharmony_ci	PT_TIMESPEC = 2,
2948c2ecf20Sopenharmony_ci	PT_OLD_TIMESPEC = 3,
2958c2ecf20Sopenharmony_ci};
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic int poll_select_finish(struct timespec64 *end_time,
2988c2ecf20Sopenharmony_ci			      void __user *p,
2998c2ecf20Sopenharmony_ci			      enum poll_time_type pt_type, int ret)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct timespec64 rts;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	restore_saved_sigmask_unless(ret == -ERESTARTNOHAND);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (!p)
3068c2ecf20Sopenharmony_ci		return ret;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (current->personality & STICKY_TIMEOUTS)
3098c2ecf20Sopenharmony_ci		goto sticky;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	/* No update for zero timeout */
3128c2ecf20Sopenharmony_ci	if (!end_time->tv_sec && !end_time->tv_nsec)
3138c2ecf20Sopenharmony_ci		return ret;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	ktime_get_ts64(&rts);
3168c2ecf20Sopenharmony_ci	rts = timespec64_sub(*end_time, rts);
3178c2ecf20Sopenharmony_ci	if (rts.tv_sec < 0)
3188c2ecf20Sopenharmony_ci		rts.tv_sec = rts.tv_nsec = 0;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	switch (pt_type) {
3228c2ecf20Sopenharmony_ci	case PT_TIMEVAL:
3238c2ecf20Sopenharmony_ci		{
3248c2ecf20Sopenharmony_ci			struct __kernel_old_timeval rtv;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci			if (sizeof(rtv) > sizeof(rtv.tv_sec) + sizeof(rtv.tv_usec))
3278c2ecf20Sopenharmony_ci				memset(&rtv, 0, sizeof(rtv));
3288c2ecf20Sopenharmony_ci			rtv.tv_sec = rts.tv_sec;
3298c2ecf20Sopenharmony_ci			rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC;
3308c2ecf20Sopenharmony_ci			if (!copy_to_user(p, &rtv, sizeof(rtv)))
3318c2ecf20Sopenharmony_ci				return ret;
3328c2ecf20Sopenharmony_ci		}
3338c2ecf20Sopenharmony_ci		break;
3348c2ecf20Sopenharmony_ci	case PT_OLD_TIMEVAL:
3358c2ecf20Sopenharmony_ci		{
3368c2ecf20Sopenharmony_ci			struct old_timeval32 rtv;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci			rtv.tv_sec = rts.tv_sec;
3398c2ecf20Sopenharmony_ci			rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC;
3408c2ecf20Sopenharmony_ci			if (!copy_to_user(p, &rtv, sizeof(rtv)))
3418c2ecf20Sopenharmony_ci				return ret;
3428c2ecf20Sopenharmony_ci		}
3438c2ecf20Sopenharmony_ci		break;
3448c2ecf20Sopenharmony_ci	case PT_TIMESPEC:
3458c2ecf20Sopenharmony_ci		if (!put_timespec64(&rts, p))
3468c2ecf20Sopenharmony_ci			return ret;
3478c2ecf20Sopenharmony_ci		break;
3488c2ecf20Sopenharmony_ci	case PT_OLD_TIMESPEC:
3498c2ecf20Sopenharmony_ci		if (!put_old_timespec32(&rts, p))
3508c2ecf20Sopenharmony_ci			return ret;
3518c2ecf20Sopenharmony_ci		break;
3528c2ecf20Sopenharmony_ci	default:
3538c2ecf20Sopenharmony_ci		BUG();
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci	/*
3568c2ecf20Sopenharmony_ci	 * If an application puts its timeval in read-only memory, we
3578c2ecf20Sopenharmony_ci	 * don't want the Linux-specific update to the timeval to
3588c2ecf20Sopenharmony_ci	 * cause a fault after the select has completed
3598c2ecf20Sopenharmony_ci	 * successfully. However, because we're not updating the
3608c2ecf20Sopenharmony_ci	 * timeval, we can't restart the system call.
3618c2ecf20Sopenharmony_ci	 */
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cisticky:
3648c2ecf20Sopenharmony_ci	if (ret == -ERESTARTNOHAND)
3658c2ecf20Sopenharmony_ci		ret = -EINTR;
3668c2ecf20Sopenharmony_ci	return ret;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci/*
3708c2ecf20Sopenharmony_ci * Scalable version of the fd_set.
3718c2ecf20Sopenharmony_ci */
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_citypedef struct {
3748c2ecf20Sopenharmony_ci	unsigned long *in, *out, *ex;
3758c2ecf20Sopenharmony_ci	unsigned long *res_in, *res_out, *res_ex;
3768c2ecf20Sopenharmony_ci} fd_set_bits;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci/*
3798c2ecf20Sopenharmony_ci * How many longwords for "nr" bits?
3808c2ecf20Sopenharmony_ci */
3818c2ecf20Sopenharmony_ci#define FDS_BITPERLONG	(8*sizeof(long))
3828c2ecf20Sopenharmony_ci#define FDS_LONGS(nr)	(((nr)+FDS_BITPERLONG-1)/FDS_BITPERLONG)
3838c2ecf20Sopenharmony_ci#define FDS_BYTES(nr)	(FDS_LONGS(nr)*sizeof(long))
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci/*
3868c2ecf20Sopenharmony_ci * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned.
3878c2ecf20Sopenharmony_ci */
3888c2ecf20Sopenharmony_cistatic inline
3898c2ecf20Sopenharmony_ciint get_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	nr = FDS_BYTES(nr);
3928c2ecf20Sopenharmony_ci	if (ufdset)
3938c2ecf20Sopenharmony_ci		return copy_from_user(fdset, ufdset, nr) ? -EFAULT : 0;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	memset(fdset, 0, nr);
3968c2ecf20Sopenharmony_ci	return 0;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic inline unsigned long __must_check
4008c2ecf20Sopenharmony_ciset_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	if (ufdset)
4038c2ecf20Sopenharmony_ci		return __copy_to_user(ufdset, fdset, FDS_BYTES(nr));
4048c2ecf20Sopenharmony_ci	return 0;
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic inline
4088c2ecf20Sopenharmony_civoid zero_fd_set(unsigned long nr, unsigned long *fdset)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	memset(fdset, 0, FDS_BYTES(nr));
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci#define FDS_IN(fds, n)		(fds->in + n)
4148c2ecf20Sopenharmony_ci#define FDS_OUT(fds, n)		(fds->out + n)
4158c2ecf20Sopenharmony_ci#define FDS_EX(fds, n)		(fds->ex + n)
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci#define BITS(fds, n)	(*FDS_IN(fds, n)|*FDS_OUT(fds, n)|*FDS_EX(fds, n))
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic int max_select_fd(unsigned long n, fd_set_bits *fds)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	unsigned long *open_fds;
4228c2ecf20Sopenharmony_ci	unsigned long set;
4238c2ecf20Sopenharmony_ci	int max;
4248c2ecf20Sopenharmony_ci	struct fdtable *fdt;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	/* handle last in-complete long-word first */
4278c2ecf20Sopenharmony_ci	set = ~(~0UL << (n & (BITS_PER_LONG-1)));
4288c2ecf20Sopenharmony_ci	n /= BITS_PER_LONG;
4298c2ecf20Sopenharmony_ci	fdt = files_fdtable(current->files);
4308c2ecf20Sopenharmony_ci	open_fds = fdt->open_fds + n;
4318c2ecf20Sopenharmony_ci	max = 0;
4328c2ecf20Sopenharmony_ci	if (set) {
4338c2ecf20Sopenharmony_ci		set &= BITS(fds, n);
4348c2ecf20Sopenharmony_ci		if (set) {
4358c2ecf20Sopenharmony_ci			if (!(set & ~*open_fds))
4368c2ecf20Sopenharmony_ci				goto get_max;
4378c2ecf20Sopenharmony_ci			return -EBADF;
4388c2ecf20Sopenharmony_ci		}
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci	while (n) {
4418c2ecf20Sopenharmony_ci		open_fds--;
4428c2ecf20Sopenharmony_ci		n--;
4438c2ecf20Sopenharmony_ci		set = BITS(fds, n);
4448c2ecf20Sopenharmony_ci		if (!set)
4458c2ecf20Sopenharmony_ci			continue;
4468c2ecf20Sopenharmony_ci		if (set & ~*open_fds)
4478c2ecf20Sopenharmony_ci			return -EBADF;
4488c2ecf20Sopenharmony_ci		if (max)
4498c2ecf20Sopenharmony_ci			continue;
4508c2ecf20Sopenharmony_ciget_max:
4518c2ecf20Sopenharmony_ci		do {
4528c2ecf20Sopenharmony_ci			max++;
4538c2ecf20Sopenharmony_ci			set >>= 1;
4548c2ecf20Sopenharmony_ci		} while (set);
4558c2ecf20Sopenharmony_ci		max += n * BITS_PER_LONG;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	return max;
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci#define POLLIN_SET (EPOLLRDNORM | EPOLLRDBAND | EPOLLIN | EPOLLHUP | EPOLLERR |\
4628c2ecf20Sopenharmony_ci			EPOLLNVAL)
4638c2ecf20Sopenharmony_ci#define POLLOUT_SET (EPOLLWRBAND | EPOLLWRNORM | EPOLLOUT | EPOLLERR |\
4648c2ecf20Sopenharmony_ci			 EPOLLNVAL)
4658c2ecf20Sopenharmony_ci#define POLLEX_SET (EPOLLPRI | EPOLLNVAL)
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic inline void wait_key_set(poll_table *wait, unsigned long in,
4688c2ecf20Sopenharmony_ci				unsigned long out, unsigned long bit,
4698c2ecf20Sopenharmony_ci				__poll_t ll_flag)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	wait->_key = POLLEX_SET | ll_flag;
4728c2ecf20Sopenharmony_ci	if (in & bit)
4738c2ecf20Sopenharmony_ci		wait->_key |= POLLIN_SET;
4748c2ecf20Sopenharmony_ci	if (out & bit)
4758c2ecf20Sopenharmony_ci		wait->_key |= POLLOUT_SET;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	ktime_t expire, *to = NULL;
4818c2ecf20Sopenharmony_ci	struct poll_wqueues table;
4828c2ecf20Sopenharmony_ci	poll_table *wait;
4838c2ecf20Sopenharmony_ci	int retval, i, timed_out = 0;
4848c2ecf20Sopenharmony_ci	u64 slack = 0;
4858c2ecf20Sopenharmony_ci	__poll_t busy_flag = net_busy_loop_on() ? POLL_BUSY_LOOP : 0;
4868c2ecf20Sopenharmony_ci	unsigned long busy_start = 0;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	rcu_read_lock();
4898c2ecf20Sopenharmony_ci	retval = max_select_fd(n, fds);
4908c2ecf20Sopenharmony_ci	rcu_read_unlock();
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	if (retval < 0)
4938c2ecf20Sopenharmony_ci		return retval;
4948c2ecf20Sopenharmony_ci	n = retval;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	poll_initwait(&table);
4978c2ecf20Sopenharmony_ci	wait = &table.pt;
4988c2ecf20Sopenharmony_ci	if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
4998c2ecf20Sopenharmony_ci		wait->_qproc = NULL;
5008c2ecf20Sopenharmony_ci		timed_out = 1;
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (end_time && !timed_out)
5048c2ecf20Sopenharmony_ci		slack = select_estimate_accuracy(end_time);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	retval = 0;
5078c2ecf20Sopenharmony_ci	for (;;) {
5088c2ecf20Sopenharmony_ci		unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
5098c2ecf20Sopenharmony_ci		bool can_busy_loop = false;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci		inp = fds->in; outp = fds->out; exp = fds->ex;
5128c2ecf20Sopenharmony_ci		rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		for (i = 0; i < n; ++rinp, ++routp, ++rexp) {
5158c2ecf20Sopenharmony_ci			unsigned long in, out, ex, all_bits, bit = 1, j;
5168c2ecf20Sopenharmony_ci			unsigned long res_in = 0, res_out = 0, res_ex = 0;
5178c2ecf20Sopenharmony_ci			__poll_t mask;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci			in = *inp++; out = *outp++; ex = *exp++;
5208c2ecf20Sopenharmony_ci			all_bits = in | out | ex;
5218c2ecf20Sopenharmony_ci			if (all_bits == 0) {
5228c2ecf20Sopenharmony_ci				i += BITS_PER_LONG;
5238c2ecf20Sopenharmony_ci				continue;
5248c2ecf20Sopenharmony_ci			}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci			for (j = 0; j < BITS_PER_LONG; ++j, ++i, bit <<= 1) {
5278c2ecf20Sopenharmony_ci				struct fd f;
5288c2ecf20Sopenharmony_ci				if (i >= n)
5298c2ecf20Sopenharmony_ci					break;
5308c2ecf20Sopenharmony_ci				if (!(bit & all_bits))
5318c2ecf20Sopenharmony_ci					continue;
5328c2ecf20Sopenharmony_ci				mask = EPOLLNVAL;
5338c2ecf20Sopenharmony_ci				f = fdget(i);
5348c2ecf20Sopenharmony_ci				if (f.file) {
5358c2ecf20Sopenharmony_ci					wait_key_set(wait, in, out, bit,
5368c2ecf20Sopenharmony_ci						     busy_flag);
5378c2ecf20Sopenharmony_ci					mask = vfs_poll(f.file, wait);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci					fdput(f);
5408c2ecf20Sopenharmony_ci				}
5418c2ecf20Sopenharmony_ci				if ((mask & POLLIN_SET) && (in & bit)) {
5428c2ecf20Sopenharmony_ci					res_in |= bit;
5438c2ecf20Sopenharmony_ci					retval++;
5448c2ecf20Sopenharmony_ci					wait->_qproc = NULL;
5458c2ecf20Sopenharmony_ci				}
5468c2ecf20Sopenharmony_ci				if ((mask & POLLOUT_SET) && (out & bit)) {
5478c2ecf20Sopenharmony_ci					res_out |= bit;
5488c2ecf20Sopenharmony_ci					retval++;
5498c2ecf20Sopenharmony_ci					wait->_qproc = NULL;
5508c2ecf20Sopenharmony_ci				}
5518c2ecf20Sopenharmony_ci				if ((mask & POLLEX_SET) && (ex & bit)) {
5528c2ecf20Sopenharmony_ci					res_ex |= bit;
5538c2ecf20Sopenharmony_ci					retval++;
5548c2ecf20Sopenharmony_ci					wait->_qproc = NULL;
5558c2ecf20Sopenharmony_ci				}
5568c2ecf20Sopenharmony_ci				/* got something, stop busy polling */
5578c2ecf20Sopenharmony_ci				if (retval) {
5588c2ecf20Sopenharmony_ci					can_busy_loop = false;
5598c2ecf20Sopenharmony_ci					busy_flag = 0;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci				/*
5628c2ecf20Sopenharmony_ci				 * only remember a returned
5638c2ecf20Sopenharmony_ci				 * POLL_BUSY_LOOP if we asked for it
5648c2ecf20Sopenharmony_ci				 */
5658c2ecf20Sopenharmony_ci				} else if (busy_flag & mask)
5668c2ecf20Sopenharmony_ci					can_busy_loop = true;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci			}
5698c2ecf20Sopenharmony_ci			if (res_in)
5708c2ecf20Sopenharmony_ci				*rinp = res_in;
5718c2ecf20Sopenharmony_ci			if (res_out)
5728c2ecf20Sopenharmony_ci				*routp = res_out;
5738c2ecf20Sopenharmony_ci			if (res_ex)
5748c2ecf20Sopenharmony_ci				*rexp = res_ex;
5758c2ecf20Sopenharmony_ci			cond_resched();
5768c2ecf20Sopenharmony_ci		}
5778c2ecf20Sopenharmony_ci		wait->_qproc = NULL;
5788c2ecf20Sopenharmony_ci		if (retval || timed_out || signal_pending(current))
5798c2ecf20Sopenharmony_ci			break;
5808c2ecf20Sopenharmony_ci		if (table.error) {
5818c2ecf20Sopenharmony_ci			retval = table.error;
5828c2ecf20Sopenharmony_ci			break;
5838c2ecf20Sopenharmony_ci		}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		/* only if found POLL_BUSY_LOOP sockets && not out of time */
5868c2ecf20Sopenharmony_ci		if (can_busy_loop && !need_resched()) {
5878c2ecf20Sopenharmony_ci			if (!busy_start) {
5888c2ecf20Sopenharmony_ci				busy_start = busy_loop_current_time();
5898c2ecf20Sopenharmony_ci				continue;
5908c2ecf20Sopenharmony_ci			}
5918c2ecf20Sopenharmony_ci			if (!busy_loop_timeout(busy_start))
5928c2ecf20Sopenharmony_ci				continue;
5938c2ecf20Sopenharmony_ci		}
5948c2ecf20Sopenharmony_ci		busy_flag = 0;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		/*
5978c2ecf20Sopenharmony_ci		 * If this is the first loop and we have a timeout
5988c2ecf20Sopenharmony_ci		 * given, then we convert to ktime_t and set the to
5998c2ecf20Sopenharmony_ci		 * pointer to the expiry value.
6008c2ecf20Sopenharmony_ci		 */
6018c2ecf20Sopenharmony_ci		if (end_time && !to) {
6028c2ecf20Sopenharmony_ci			expire = timespec64_to_ktime(*end_time);
6038c2ecf20Sopenharmony_ci			to = &expire;
6048c2ecf20Sopenharmony_ci		}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci		if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,
6078c2ecf20Sopenharmony_ci					   to, slack))
6088c2ecf20Sopenharmony_ci			timed_out = 1;
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	poll_freewait(&table);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	return retval;
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci/*
6178c2ecf20Sopenharmony_ci * We can actually return ERESTARTSYS instead of EINTR, but I'd
6188c2ecf20Sopenharmony_ci * like to be certain this leads to no problems. So I return
6198c2ecf20Sopenharmony_ci * EINTR just for safety.
6208c2ecf20Sopenharmony_ci *
6218c2ecf20Sopenharmony_ci * Update: ERESTARTSYS breaks at least the xview clock binary, so
6228c2ecf20Sopenharmony_ci * I'm trying ERESTARTNOHAND which restart only when you want to.
6238c2ecf20Sopenharmony_ci */
6248c2ecf20Sopenharmony_ciint core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
6258c2ecf20Sopenharmony_ci			   fd_set __user *exp, struct timespec64 *end_time)
6268c2ecf20Sopenharmony_ci{
6278c2ecf20Sopenharmony_ci	fd_set_bits fds;
6288c2ecf20Sopenharmony_ci	void *bits;
6298c2ecf20Sopenharmony_ci	int ret, max_fds;
6308c2ecf20Sopenharmony_ci	size_t size, alloc_size;
6318c2ecf20Sopenharmony_ci	struct fdtable *fdt;
6328c2ecf20Sopenharmony_ci	/* Allocate small arguments on the stack to save memory and be faster */
6338c2ecf20Sopenharmony_ci	long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	ret = -EINVAL;
6368c2ecf20Sopenharmony_ci	if (n < 0)
6378c2ecf20Sopenharmony_ci		goto out_nofds;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	/* max_fds can increase, so grab it once to avoid race */
6408c2ecf20Sopenharmony_ci	rcu_read_lock();
6418c2ecf20Sopenharmony_ci	fdt = files_fdtable(current->files);
6428c2ecf20Sopenharmony_ci	max_fds = fdt->max_fds;
6438c2ecf20Sopenharmony_ci	rcu_read_unlock();
6448c2ecf20Sopenharmony_ci	if (n > max_fds)
6458c2ecf20Sopenharmony_ci		n = max_fds;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	/*
6488c2ecf20Sopenharmony_ci	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
6498c2ecf20Sopenharmony_ci	 * since we used fdset we need to allocate memory in units of
6508c2ecf20Sopenharmony_ci	 * long-words.
6518c2ecf20Sopenharmony_ci	 */
6528c2ecf20Sopenharmony_ci	size = FDS_BYTES(n);
6538c2ecf20Sopenharmony_ci	bits = stack_fds;
6548c2ecf20Sopenharmony_ci	if (size > sizeof(stack_fds) / 6) {
6558c2ecf20Sopenharmony_ci		/* Not enough space in on-stack array; must use kmalloc */
6568c2ecf20Sopenharmony_ci		ret = -ENOMEM;
6578c2ecf20Sopenharmony_ci		if (size > (SIZE_MAX / 6))
6588c2ecf20Sopenharmony_ci			goto out_nofds;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci		alloc_size = 6 * size;
6618c2ecf20Sopenharmony_ci		bits = kvmalloc(alloc_size, GFP_KERNEL);
6628c2ecf20Sopenharmony_ci		if (!bits)
6638c2ecf20Sopenharmony_ci			goto out_nofds;
6648c2ecf20Sopenharmony_ci	}
6658c2ecf20Sopenharmony_ci	fds.in      = bits;
6668c2ecf20Sopenharmony_ci	fds.out     = bits +   size;
6678c2ecf20Sopenharmony_ci	fds.ex      = bits + 2*size;
6688c2ecf20Sopenharmony_ci	fds.res_in  = bits + 3*size;
6698c2ecf20Sopenharmony_ci	fds.res_out = bits + 4*size;
6708c2ecf20Sopenharmony_ci	fds.res_ex  = bits + 5*size;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	if ((ret = get_fd_set(n, inp, fds.in)) ||
6738c2ecf20Sopenharmony_ci	    (ret = get_fd_set(n, outp, fds.out)) ||
6748c2ecf20Sopenharmony_ci	    (ret = get_fd_set(n, exp, fds.ex)))
6758c2ecf20Sopenharmony_ci		goto out;
6768c2ecf20Sopenharmony_ci	zero_fd_set(n, fds.res_in);
6778c2ecf20Sopenharmony_ci	zero_fd_set(n, fds.res_out);
6788c2ecf20Sopenharmony_ci	zero_fd_set(n, fds.res_ex);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	ret = do_select(n, &fds, end_time);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	if (ret < 0)
6838c2ecf20Sopenharmony_ci		goto out;
6848c2ecf20Sopenharmony_ci	if (!ret) {
6858c2ecf20Sopenharmony_ci		ret = -ERESTARTNOHAND;
6868c2ecf20Sopenharmony_ci		if (signal_pending(current))
6878c2ecf20Sopenharmony_ci			goto out;
6888c2ecf20Sopenharmony_ci		ret = 0;
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (set_fd_set(n, inp, fds.res_in) ||
6928c2ecf20Sopenharmony_ci	    set_fd_set(n, outp, fds.res_out) ||
6938c2ecf20Sopenharmony_ci	    set_fd_set(n, exp, fds.res_ex))
6948c2ecf20Sopenharmony_ci		ret = -EFAULT;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ciout:
6978c2ecf20Sopenharmony_ci	if (bits != stack_fds)
6988c2ecf20Sopenharmony_ci		kvfree(bits);
6998c2ecf20Sopenharmony_ciout_nofds:
7008c2ecf20Sopenharmony_ci	return ret;
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_cistatic int kern_select(int n, fd_set __user *inp, fd_set __user *outp,
7048c2ecf20Sopenharmony_ci		       fd_set __user *exp, struct __kernel_old_timeval __user *tvp)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	struct timespec64 end_time, *to = NULL;
7078c2ecf20Sopenharmony_ci	struct __kernel_old_timeval tv;
7088c2ecf20Sopenharmony_ci	int ret;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	if (tvp) {
7118c2ecf20Sopenharmony_ci		if (copy_from_user(&tv, tvp, sizeof(tv)))
7128c2ecf20Sopenharmony_ci			return -EFAULT;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci		to = &end_time;
7158c2ecf20Sopenharmony_ci		if (poll_select_set_timeout(to,
7168c2ecf20Sopenharmony_ci				tv.tv_sec + (tv.tv_usec / USEC_PER_SEC),
7178c2ecf20Sopenharmony_ci				(tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC))
7188c2ecf20Sopenharmony_ci			return -EINVAL;
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	ret = core_sys_select(n, inp, outp, exp, to);
7228c2ecf20Sopenharmony_ci	return poll_select_finish(&end_time, tvp, PT_TIMEVAL, ret);
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ciSYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,
7268c2ecf20Sopenharmony_ci		fd_set __user *, exp, struct __kernel_old_timeval __user *, tvp)
7278c2ecf20Sopenharmony_ci{
7288c2ecf20Sopenharmony_ci	return kern_select(n, inp, outp, exp, tvp);
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_cistatic long do_pselect(int n, fd_set __user *inp, fd_set __user *outp,
7328c2ecf20Sopenharmony_ci		       fd_set __user *exp, void __user *tsp,
7338c2ecf20Sopenharmony_ci		       const sigset_t __user *sigmask, size_t sigsetsize,
7348c2ecf20Sopenharmony_ci		       enum poll_time_type type)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	struct timespec64 ts, end_time, *to = NULL;
7378c2ecf20Sopenharmony_ci	int ret;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	if (tsp) {
7408c2ecf20Sopenharmony_ci		switch (type) {
7418c2ecf20Sopenharmony_ci		case PT_TIMESPEC:
7428c2ecf20Sopenharmony_ci			if (get_timespec64(&ts, tsp))
7438c2ecf20Sopenharmony_ci				return -EFAULT;
7448c2ecf20Sopenharmony_ci			break;
7458c2ecf20Sopenharmony_ci		case PT_OLD_TIMESPEC:
7468c2ecf20Sopenharmony_ci			if (get_old_timespec32(&ts, tsp))
7478c2ecf20Sopenharmony_ci				return -EFAULT;
7488c2ecf20Sopenharmony_ci			break;
7498c2ecf20Sopenharmony_ci		default:
7508c2ecf20Sopenharmony_ci			BUG();
7518c2ecf20Sopenharmony_ci		}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci		to = &end_time;
7548c2ecf20Sopenharmony_ci		if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
7558c2ecf20Sopenharmony_ci			return -EINVAL;
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	ret = set_user_sigmask(sigmask, sigsetsize);
7598c2ecf20Sopenharmony_ci	if (ret)
7608c2ecf20Sopenharmony_ci		return ret;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	ret = core_sys_select(n, inp, outp, exp, to);
7638c2ecf20Sopenharmony_ci	return poll_select_finish(&end_time, tsp, type, ret);
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci/*
7678c2ecf20Sopenharmony_ci * Most architectures can't handle 7-argument syscalls. So we provide a
7688c2ecf20Sopenharmony_ci * 6-argument version where the sixth argument is a pointer to a structure
7698c2ecf20Sopenharmony_ci * which has a pointer to the sigset_t itself followed by a size_t containing
7708c2ecf20Sopenharmony_ci * the sigset size.
7718c2ecf20Sopenharmony_ci */
7728c2ecf20Sopenharmony_cistruct sigset_argpack {
7738c2ecf20Sopenharmony_ci	sigset_t __user *p;
7748c2ecf20Sopenharmony_ci	size_t size;
7758c2ecf20Sopenharmony_ci};
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic inline int get_sigset_argpack(struct sigset_argpack *to,
7788c2ecf20Sopenharmony_ci				     struct sigset_argpack __user *from)
7798c2ecf20Sopenharmony_ci{
7808c2ecf20Sopenharmony_ci	// the path is hot enough for overhead of copy_from_user() to matter
7818c2ecf20Sopenharmony_ci	if (from) {
7828c2ecf20Sopenharmony_ci		if (!user_read_access_begin(from, sizeof(*from)))
7838c2ecf20Sopenharmony_ci			return -EFAULT;
7848c2ecf20Sopenharmony_ci		unsafe_get_user(to->p, &from->p, Efault);
7858c2ecf20Sopenharmony_ci		unsafe_get_user(to->size, &from->size, Efault);
7868c2ecf20Sopenharmony_ci		user_read_access_end();
7878c2ecf20Sopenharmony_ci	}
7888c2ecf20Sopenharmony_ci	return 0;
7898c2ecf20Sopenharmony_ciEfault:
7908c2ecf20Sopenharmony_ci	user_access_end();
7918c2ecf20Sopenharmony_ci	return -EFAULT;
7928c2ecf20Sopenharmony_ci}
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ciSYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp,
7958c2ecf20Sopenharmony_ci		fd_set __user *, exp, struct __kernel_timespec __user *, tsp,
7968c2ecf20Sopenharmony_ci		void __user *, sig)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	struct sigset_argpack x = {NULL, 0};
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	if (get_sigset_argpack(&x, sig))
8018c2ecf20Sopenharmony_ci		return -EFAULT;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	return do_pselect(n, inp, outp, exp, tsp, x.p, x.size, PT_TIMESPEC);
8048c2ecf20Sopenharmony_ci}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT)
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ciSYSCALL_DEFINE6(pselect6_time32, int, n, fd_set __user *, inp, fd_set __user *, outp,
8098c2ecf20Sopenharmony_ci		fd_set __user *, exp, struct old_timespec32 __user *, tsp,
8108c2ecf20Sopenharmony_ci		void __user *, sig)
8118c2ecf20Sopenharmony_ci{
8128c2ecf20Sopenharmony_ci	struct sigset_argpack x = {NULL, 0};
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	if (get_sigset_argpack(&x, sig))
8158c2ecf20Sopenharmony_ci		return -EFAULT;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	return do_pselect(n, inp, outp, exp, tsp, x.p, x.size, PT_OLD_TIMESPEC);
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci#endif
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci#ifdef __ARCH_WANT_SYS_OLD_SELECT
8238c2ecf20Sopenharmony_cistruct sel_arg_struct {
8248c2ecf20Sopenharmony_ci	unsigned long n;
8258c2ecf20Sopenharmony_ci	fd_set __user *inp, *outp, *exp;
8268c2ecf20Sopenharmony_ci	struct __kernel_old_timeval __user *tvp;
8278c2ecf20Sopenharmony_ci};
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ciSYSCALL_DEFINE1(old_select, struct sel_arg_struct __user *, arg)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	struct sel_arg_struct a;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (copy_from_user(&a, arg, sizeof(a)))
8348c2ecf20Sopenharmony_ci		return -EFAULT;
8358c2ecf20Sopenharmony_ci	return kern_select(a.n, a.inp, a.outp, a.exp, a.tvp);
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci#endif
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_cistruct poll_list {
8408c2ecf20Sopenharmony_ci	struct poll_list *next;
8418c2ecf20Sopenharmony_ci	int len;
8428c2ecf20Sopenharmony_ci	struct pollfd entries[];
8438c2ecf20Sopenharmony_ci};
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci#define POLLFD_PER_PAGE  ((PAGE_SIZE-sizeof(struct poll_list)) / sizeof(struct pollfd))
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci/*
8488c2ecf20Sopenharmony_ci * Fish for pollable events on the pollfd->fd file descriptor. We're only
8498c2ecf20Sopenharmony_ci * interested in events matching the pollfd->events mask, and the result
8508c2ecf20Sopenharmony_ci * matching that mask is both recorded in pollfd->revents and returned. The
8518c2ecf20Sopenharmony_ci * pwait poll_table will be used by the fd-provided poll handler for waiting,
8528c2ecf20Sopenharmony_ci * if pwait->_qproc is non-NULL.
8538c2ecf20Sopenharmony_ci */
8548c2ecf20Sopenharmony_cistatic inline __poll_t do_pollfd(struct pollfd *pollfd, poll_table *pwait,
8558c2ecf20Sopenharmony_ci				     bool *can_busy_poll,
8568c2ecf20Sopenharmony_ci				     __poll_t busy_flag)
8578c2ecf20Sopenharmony_ci{
8588c2ecf20Sopenharmony_ci	int fd = pollfd->fd;
8598c2ecf20Sopenharmony_ci	__poll_t mask = 0, filter;
8608c2ecf20Sopenharmony_ci	struct fd f;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	if (fd < 0)
8638c2ecf20Sopenharmony_ci		goto out;
8648c2ecf20Sopenharmony_ci	mask = EPOLLNVAL;
8658c2ecf20Sopenharmony_ci	f = fdget(fd);
8668c2ecf20Sopenharmony_ci	if (!f.file)
8678c2ecf20Sopenharmony_ci		goto out;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	/* userland u16 ->events contains POLL... bitmap */
8708c2ecf20Sopenharmony_ci	filter = demangle_poll(pollfd->events) | EPOLLERR | EPOLLHUP;
8718c2ecf20Sopenharmony_ci	pwait->_key = filter | busy_flag;
8728c2ecf20Sopenharmony_ci	mask = vfs_poll(f.file, pwait);
8738c2ecf20Sopenharmony_ci	if (mask & busy_flag)
8748c2ecf20Sopenharmony_ci		*can_busy_poll = true;
8758c2ecf20Sopenharmony_ci	mask &= filter;		/* Mask out unneeded events. */
8768c2ecf20Sopenharmony_ci	fdput(f);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ciout:
8798c2ecf20Sopenharmony_ci	/* ... and so does ->revents */
8808c2ecf20Sopenharmony_ci	pollfd->revents = mangle_poll(mask);
8818c2ecf20Sopenharmony_ci	return mask;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic int do_poll(struct poll_list *list, struct poll_wqueues *wait,
8858c2ecf20Sopenharmony_ci		   struct timespec64 *end_time)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	poll_table* pt = &wait->pt;
8888c2ecf20Sopenharmony_ci	ktime_t expire, *to = NULL;
8898c2ecf20Sopenharmony_ci	int timed_out = 0, count = 0;
8908c2ecf20Sopenharmony_ci	u64 slack = 0;
8918c2ecf20Sopenharmony_ci	__poll_t busy_flag = net_busy_loop_on() ? POLL_BUSY_LOOP : 0;
8928c2ecf20Sopenharmony_ci	unsigned long busy_start = 0;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	/* Optimise the no-wait case */
8958c2ecf20Sopenharmony_ci	if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
8968c2ecf20Sopenharmony_ci		pt->_qproc = NULL;
8978c2ecf20Sopenharmony_ci		timed_out = 1;
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	if (end_time && !timed_out)
9018c2ecf20Sopenharmony_ci		slack = select_estimate_accuracy(end_time);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	for (;;) {
9048c2ecf20Sopenharmony_ci		struct poll_list *walk;
9058c2ecf20Sopenharmony_ci		bool can_busy_loop = false;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci		for (walk = list; walk != NULL; walk = walk->next) {
9088c2ecf20Sopenharmony_ci			struct pollfd * pfd, * pfd_end;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci			pfd = walk->entries;
9118c2ecf20Sopenharmony_ci			pfd_end = pfd + walk->len;
9128c2ecf20Sopenharmony_ci			for (; pfd != pfd_end; pfd++) {
9138c2ecf20Sopenharmony_ci				/*
9148c2ecf20Sopenharmony_ci				 * Fish for events. If we found one, record it
9158c2ecf20Sopenharmony_ci				 * and kill poll_table->_qproc, so we don't
9168c2ecf20Sopenharmony_ci				 * needlessly register any other waiters after
9178c2ecf20Sopenharmony_ci				 * this. They'll get immediately deregistered
9188c2ecf20Sopenharmony_ci				 * when we break out and return.
9198c2ecf20Sopenharmony_ci				 */
9208c2ecf20Sopenharmony_ci				if (do_pollfd(pfd, pt, &can_busy_loop,
9218c2ecf20Sopenharmony_ci					      busy_flag)) {
9228c2ecf20Sopenharmony_ci					count++;
9238c2ecf20Sopenharmony_ci					pt->_qproc = NULL;
9248c2ecf20Sopenharmony_ci					/* found something, stop busy polling */
9258c2ecf20Sopenharmony_ci					busy_flag = 0;
9268c2ecf20Sopenharmony_ci					can_busy_loop = false;
9278c2ecf20Sopenharmony_ci				}
9288c2ecf20Sopenharmony_ci			}
9298c2ecf20Sopenharmony_ci		}
9308c2ecf20Sopenharmony_ci		/*
9318c2ecf20Sopenharmony_ci		 * All waiters have already been registered, so don't provide
9328c2ecf20Sopenharmony_ci		 * a poll_table->_qproc to them on the next loop iteration.
9338c2ecf20Sopenharmony_ci		 */
9348c2ecf20Sopenharmony_ci		pt->_qproc = NULL;
9358c2ecf20Sopenharmony_ci		if (!count) {
9368c2ecf20Sopenharmony_ci			count = wait->error;
9378c2ecf20Sopenharmony_ci			if (signal_pending(current))
9388c2ecf20Sopenharmony_ci				count = -ERESTARTNOHAND;
9398c2ecf20Sopenharmony_ci		}
9408c2ecf20Sopenharmony_ci		if (count || timed_out)
9418c2ecf20Sopenharmony_ci			break;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci		/* only if found POLL_BUSY_LOOP sockets && not out of time */
9448c2ecf20Sopenharmony_ci		if (can_busy_loop && !need_resched()) {
9458c2ecf20Sopenharmony_ci			if (!busy_start) {
9468c2ecf20Sopenharmony_ci				busy_start = busy_loop_current_time();
9478c2ecf20Sopenharmony_ci				continue;
9488c2ecf20Sopenharmony_ci			}
9498c2ecf20Sopenharmony_ci			if (!busy_loop_timeout(busy_start))
9508c2ecf20Sopenharmony_ci				continue;
9518c2ecf20Sopenharmony_ci		}
9528c2ecf20Sopenharmony_ci		busy_flag = 0;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci		/*
9558c2ecf20Sopenharmony_ci		 * If this is the first loop and we have a timeout
9568c2ecf20Sopenharmony_ci		 * given, then we convert to ktime_t and set the to
9578c2ecf20Sopenharmony_ci		 * pointer to the expiry value.
9588c2ecf20Sopenharmony_ci		 */
9598c2ecf20Sopenharmony_ci		if (end_time && !to) {
9608c2ecf20Sopenharmony_ci			expire = timespec64_to_ktime(*end_time);
9618c2ecf20Sopenharmony_ci			to = &expire;
9628c2ecf20Sopenharmony_ci		}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci		if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack))
9658c2ecf20Sopenharmony_ci			timed_out = 1;
9668c2ecf20Sopenharmony_ci	}
9678c2ecf20Sopenharmony_ci	return count;
9688c2ecf20Sopenharmony_ci}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci#define N_STACK_PPS ((sizeof(stack_pps) - sizeof(struct poll_list))  / \
9718c2ecf20Sopenharmony_ci			sizeof(struct pollfd))
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_cistatic int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
9748c2ecf20Sopenharmony_ci		struct timespec64 *end_time)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	struct poll_wqueues table;
9778c2ecf20Sopenharmony_ci	int err = -EFAULT, fdcount, len;
9788c2ecf20Sopenharmony_ci	/* Allocate small arguments on the stack to save memory and be
9798c2ecf20Sopenharmony_ci	   faster - use long to make sure the buffer is aligned properly
9808c2ecf20Sopenharmony_ci	   on 64 bit archs to avoid unaligned access */
9818c2ecf20Sopenharmony_ci	long stack_pps[POLL_STACK_ALLOC/sizeof(long)];
9828c2ecf20Sopenharmony_ci	struct poll_list *const head = (struct poll_list *)stack_pps;
9838c2ecf20Sopenharmony_ci 	struct poll_list *walk = head;
9848c2ecf20Sopenharmony_ci 	unsigned long todo = nfds;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	if (nfds > rlimit(RLIMIT_NOFILE))
9878c2ecf20Sopenharmony_ci		return -EINVAL;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	len = min_t(unsigned int, nfds, N_STACK_PPS);
9908c2ecf20Sopenharmony_ci	for (;;) {
9918c2ecf20Sopenharmony_ci		walk->next = NULL;
9928c2ecf20Sopenharmony_ci		walk->len = len;
9938c2ecf20Sopenharmony_ci		if (!len)
9948c2ecf20Sopenharmony_ci			break;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci		if (copy_from_user(walk->entries, ufds + nfds-todo,
9978c2ecf20Sopenharmony_ci					sizeof(struct pollfd) * walk->len))
9988c2ecf20Sopenharmony_ci			goto out_fds;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci		todo -= walk->len;
10018c2ecf20Sopenharmony_ci		if (!todo)
10028c2ecf20Sopenharmony_ci			break;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci		len = min(todo, POLLFD_PER_PAGE);
10058c2ecf20Sopenharmony_ci		walk = walk->next = kmalloc(struct_size(walk, entries, len),
10068c2ecf20Sopenharmony_ci					    GFP_KERNEL);
10078c2ecf20Sopenharmony_ci		if (!walk) {
10088c2ecf20Sopenharmony_ci			err = -ENOMEM;
10098c2ecf20Sopenharmony_ci			goto out_fds;
10108c2ecf20Sopenharmony_ci		}
10118c2ecf20Sopenharmony_ci	}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	poll_initwait(&table);
10148c2ecf20Sopenharmony_ci	fdcount = do_poll(head, &table, end_time);
10158c2ecf20Sopenharmony_ci	poll_freewait(&table);
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	if (!user_write_access_begin(ufds, nfds * sizeof(*ufds)))
10188c2ecf20Sopenharmony_ci		goto out_fds;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	for (walk = head; walk; walk = walk->next) {
10218c2ecf20Sopenharmony_ci		struct pollfd *fds = walk->entries;
10228c2ecf20Sopenharmony_ci		int j;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci		for (j = walk->len; j; fds++, ufds++, j--)
10258c2ecf20Sopenharmony_ci			unsafe_put_user(fds->revents, &ufds->revents, Efault);
10268c2ecf20Sopenharmony_ci  	}
10278c2ecf20Sopenharmony_ci	user_write_access_end();
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	err = fdcount;
10308c2ecf20Sopenharmony_ciout_fds:
10318c2ecf20Sopenharmony_ci	walk = head->next;
10328c2ecf20Sopenharmony_ci	while (walk) {
10338c2ecf20Sopenharmony_ci		struct poll_list *pos = walk;
10348c2ecf20Sopenharmony_ci		walk = walk->next;
10358c2ecf20Sopenharmony_ci		kfree(pos);
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	return err;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ciEfault:
10418c2ecf20Sopenharmony_ci	user_write_access_end();
10428c2ecf20Sopenharmony_ci	err = -EFAULT;
10438c2ecf20Sopenharmony_ci	goto out_fds;
10448c2ecf20Sopenharmony_ci}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_cistatic long do_restart_poll(struct restart_block *restart_block)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	struct pollfd __user *ufds = restart_block->poll.ufds;
10498c2ecf20Sopenharmony_ci	int nfds = restart_block->poll.nfds;
10508c2ecf20Sopenharmony_ci	struct timespec64 *to = NULL, end_time;
10518c2ecf20Sopenharmony_ci	int ret;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	if (restart_block->poll.has_timeout) {
10548c2ecf20Sopenharmony_ci		end_time.tv_sec = restart_block->poll.tv_sec;
10558c2ecf20Sopenharmony_ci		end_time.tv_nsec = restart_block->poll.tv_nsec;
10568c2ecf20Sopenharmony_ci		to = &end_time;
10578c2ecf20Sopenharmony_ci	}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	ret = do_sys_poll(ufds, nfds, to);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	if (ret == -ERESTARTNOHAND)
10628c2ecf20Sopenharmony_ci		ret = set_restart_fn(restart_block, do_restart_poll);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	return ret;
10658c2ecf20Sopenharmony_ci}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ciSYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,
10688c2ecf20Sopenharmony_ci		int, timeout_msecs)
10698c2ecf20Sopenharmony_ci{
10708c2ecf20Sopenharmony_ci	struct timespec64 end_time, *to = NULL;
10718c2ecf20Sopenharmony_ci	int ret;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	if (timeout_msecs >= 0) {
10748c2ecf20Sopenharmony_ci		to = &end_time;
10758c2ecf20Sopenharmony_ci		poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC,
10768c2ecf20Sopenharmony_ci			NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC));
10778c2ecf20Sopenharmony_ci	}
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	ret = do_sys_poll(ufds, nfds, to);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	if (ret == -ERESTARTNOHAND) {
10828c2ecf20Sopenharmony_ci		struct restart_block *restart_block;
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci		restart_block = &current->restart_block;
10858c2ecf20Sopenharmony_ci		restart_block->poll.ufds = ufds;
10868c2ecf20Sopenharmony_ci		restart_block->poll.nfds = nfds;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci		if (timeout_msecs >= 0) {
10898c2ecf20Sopenharmony_ci			restart_block->poll.tv_sec = end_time.tv_sec;
10908c2ecf20Sopenharmony_ci			restart_block->poll.tv_nsec = end_time.tv_nsec;
10918c2ecf20Sopenharmony_ci			restart_block->poll.has_timeout = 1;
10928c2ecf20Sopenharmony_ci		} else
10938c2ecf20Sopenharmony_ci			restart_block->poll.has_timeout = 0;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci		ret = set_restart_fn(restart_block, do_restart_poll);
10968c2ecf20Sopenharmony_ci	}
10978c2ecf20Sopenharmony_ci	return ret;
10988c2ecf20Sopenharmony_ci}
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ciSYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds,
11018c2ecf20Sopenharmony_ci		struct __kernel_timespec __user *, tsp, const sigset_t __user *, sigmask,
11028c2ecf20Sopenharmony_ci		size_t, sigsetsize)
11038c2ecf20Sopenharmony_ci{
11048c2ecf20Sopenharmony_ci	struct timespec64 ts, end_time, *to = NULL;
11058c2ecf20Sopenharmony_ci	int ret;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	if (tsp) {
11088c2ecf20Sopenharmony_ci		if (get_timespec64(&ts, tsp))
11098c2ecf20Sopenharmony_ci			return -EFAULT;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci		to = &end_time;
11128c2ecf20Sopenharmony_ci		if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
11138c2ecf20Sopenharmony_ci			return -EINVAL;
11148c2ecf20Sopenharmony_ci	}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	ret = set_user_sigmask(sigmask, sigsetsize);
11178c2ecf20Sopenharmony_ci	if (ret)
11188c2ecf20Sopenharmony_ci		return ret;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	ret = do_sys_poll(ufds, nfds, to);
11218c2ecf20Sopenharmony_ci	return poll_select_finish(&end_time, tsp, PT_TIMESPEC, ret);
11228c2ecf20Sopenharmony_ci}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci#if defined(CONFIG_COMPAT_32BIT_TIME) && !defined(CONFIG_64BIT)
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ciSYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds, unsigned int, nfds,
11278c2ecf20Sopenharmony_ci		struct old_timespec32 __user *, tsp, const sigset_t __user *, sigmask,
11288c2ecf20Sopenharmony_ci		size_t, sigsetsize)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	struct timespec64 ts, end_time, *to = NULL;
11318c2ecf20Sopenharmony_ci	int ret;
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	if (tsp) {
11348c2ecf20Sopenharmony_ci		if (get_old_timespec32(&ts, tsp))
11358c2ecf20Sopenharmony_ci			return -EFAULT;
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci		to = &end_time;
11388c2ecf20Sopenharmony_ci		if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
11398c2ecf20Sopenharmony_ci			return -EINVAL;
11408c2ecf20Sopenharmony_ci	}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	ret = set_user_sigmask(sigmask, sigsetsize);
11438c2ecf20Sopenharmony_ci	if (ret)
11448c2ecf20Sopenharmony_ci		return ret;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	ret = do_sys_poll(ufds, nfds, to);
11478c2ecf20Sopenharmony_ci	return poll_select_finish(&end_time, tsp, PT_OLD_TIMESPEC, ret);
11488c2ecf20Sopenharmony_ci}
11498c2ecf20Sopenharmony_ci#endif
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
11528c2ecf20Sopenharmony_ci#define __COMPAT_NFDBITS       (8 * sizeof(compat_ulong_t))
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci/*
11558c2ecf20Sopenharmony_ci * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
11568c2ecf20Sopenharmony_ci * 64-bit unsigned longs.
11578c2ecf20Sopenharmony_ci */
11588c2ecf20Sopenharmony_cistatic
11598c2ecf20Sopenharmony_ciint compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
11608c2ecf20Sopenharmony_ci			unsigned long *fdset)
11618c2ecf20Sopenharmony_ci{
11628c2ecf20Sopenharmony_ci	if (ufdset) {
11638c2ecf20Sopenharmony_ci		return compat_get_bitmap(fdset, ufdset, nr);
11648c2ecf20Sopenharmony_ci	} else {
11658c2ecf20Sopenharmony_ci		zero_fd_set(nr, fdset);
11668c2ecf20Sopenharmony_ci		return 0;
11678c2ecf20Sopenharmony_ci	}
11688c2ecf20Sopenharmony_ci}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_cistatic
11718c2ecf20Sopenharmony_ciint compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
11728c2ecf20Sopenharmony_ci		      unsigned long *fdset)
11738c2ecf20Sopenharmony_ci{
11748c2ecf20Sopenharmony_ci	if (!ufdset)
11758c2ecf20Sopenharmony_ci		return 0;
11768c2ecf20Sopenharmony_ci	return compat_put_bitmap(ufdset, fdset, nr);
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci/*
11818c2ecf20Sopenharmony_ci * This is a virtual copy of sys_select from fs/select.c and probably
11828c2ecf20Sopenharmony_ci * should be compared to it from time to time
11838c2ecf20Sopenharmony_ci */
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci/*
11868c2ecf20Sopenharmony_ci * We can actually return ERESTARTSYS instead of EINTR, but I'd
11878c2ecf20Sopenharmony_ci * like to be certain this leads to no problems. So I return
11888c2ecf20Sopenharmony_ci * EINTR just for safety.
11898c2ecf20Sopenharmony_ci *
11908c2ecf20Sopenharmony_ci * Update: ERESTARTSYS breaks at least the xview clock binary, so
11918c2ecf20Sopenharmony_ci * I'm trying ERESTARTNOHAND which restart only when you want to.
11928c2ecf20Sopenharmony_ci */
11938c2ecf20Sopenharmony_cistatic int compat_core_sys_select(int n, compat_ulong_t __user *inp,
11948c2ecf20Sopenharmony_ci	compat_ulong_t __user *outp, compat_ulong_t __user *exp,
11958c2ecf20Sopenharmony_ci	struct timespec64 *end_time)
11968c2ecf20Sopenharmony_ci{
11978c2ecf20Sopenharmony_ci	fd_set_bits fds;
11988c2ecf20Sopenharmony_ci	void *bits;
11998c2ecf20Sopenharmony_ci	int size, max_fds, ret = -EINVAL;
12008c2ecf20Sopenharmony_ci	struct fdtable *fdt;
12018c2ecf20Sopenharmony_ci	long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	if (n < 0)
12048c2ecf20Sopenharmony_ci		goto out_nofds;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	/* max_fds can increase, so grab it once to avoid race */
12078c2ecf20Sopenharmony_ci	rcu_read_lock();
12088c2ecf20Sopenharmony_ci	fdt = files_fdtable(current->files);
12098c2ecf20Sopenharmony_ci	max_fds = fdt->max_fds;
12108c2ecf20Sopenharmony_ci	rcu_read_unlock();
12118c2ecf20Sopenharmony_ci	if (n > max_fds)
12128c2ecf20Sopenharmony_ci		n = max_fds;
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	/*
12158c2ecf20Sopenharmony_ci	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
12168c2ecf20Sopenharmony_ci	 * since we used fdset we need to allocate memory in units of
12178c2ecf20Sopenharmony_ci	 * long-words.
12188c2ecf20Sopenharmony_ci	 */
12198c2ecf20Sopenharmony_ci	size = FDS_BYTES(n);
12208c2ecf20Sopenharmony_ci	bits = stack_fds;
12218c2ecf20Sopenharmony_ci	if (size > sizeof(stack_fds) / 6) {
12228c2ecf20Sopenharmony_ci		bits = kmalloc_array(6, size, GFP_KERNEL);
12238c2ecf20Sopenharmony_ci		ret = -ENOMEM;
12248c2ecf20Sopenharmony_ci		if (!bits)
12258c2ecf20Sopenharmony_ci			goto out_nofds;
12268c2ecf20Sopenharmony_ci	}
12278c2ecf20Sopenharmony_ci	fds.in      = (unsigned long *)  bits;
12288c2ecf20Sopenharmony_ci	fds.out     = (unsigned long *) (bits +   size);
12298c2ecf20Sopenharmony_ci	fds.ex      = (unsigned long *) (bits + 2*size);
12308c2ecf20Sopenharmony_ci	fds.res_in  = (unsigned long *) (bits + 3*size);
12318c2ecf20Sopenharmony_ci	fds.res_out = (unsigned long *) (bits + 4*size);
12328c2ecf20Sopenharmony_ci	fds.res_ex  = (unsigned long *) (bits + 5*size);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	if ((ret = compat_get_fd_set(n, inp, fds.in)) ||
12358c2ecf20Sopenharmony_ci	    (ret = compat_get_fd_set(n, outp, fds.out)) ||
12368c2ecf20Sopenharmony_ci	    (ret = compat_get_fd_set(n, exp, fds.ex)))
12378c2ecf20Sopenharmony_ci		goto out;
12388c2ecf20Sopenharmony_ci	zero_fd_set(n, fds.res_in);
12398c2ecf20Sopenharmony_ci	zero_fd_set(n, fds.res_out);
12408c2ecf20Sopenharmony_ci	zero_fd_set(n, fds.res_ex);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	ret = do_select(n, &fds, end_time);
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	if (ret < 0)
12458c2ecf20Sopenharmony_ci		goto out;
12468c2ecf20Sopenharmony_ci	if (!ret) {
12478c2ecf20Sopenharmony_ci		ret = -ERESTARTNOHAND;
12488c2ecf20Sopenharmony_ci		if (signal_pending(current))
12498c2ecf20Sopenharmony_ci			goto out;
12508c2ecf20Sopenharmony_ci		ret = 0;
12518c2ecf20Sopenharmony_ci	}
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	if (compat_set_fd_set(n, inp, fds.res_in) ||
12548c2ecf20Sopenharmony_ci	    compat_set_fd_set(n, outp, fds.res_out) ||
12558c2ecf20Sopenharmony_ci	    compat_set_fd_set(n, exp, fds.res_ex))
12568c2ecf20Sopenharmony_ci		ret = -EFAULT;
12578c2ecf20Sopenharmony_ciout:
12588c2ecf20Sopenharmony_ci	if (bits != stack_fds)
12598c2ecf20Sopenharmony_ci		kfree(bits);
12608c2ecf20Sopenharmony_ciout_nofds:
12618c2ecf20Sopenharmony_ci	return ret;
12628c2ecf20Sopenharmony_ci}
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_cistatic int do_compat_select(int n, compat_ulong_t __user *inp,
12658c2ecf20Sopenharmony_ci	compat_ulong_t __user *outp, compat_ulong_t __user *exp,
12668c2ecf20Sopenharmony_ci	struct old_timeval32 __user *tvp)
12678c2ecf20Sopenharmony_ci{
12688c2ecf20Sopenharmony_ci	struct timespec64 end_time, *to = NULL;
12698c2ecf20Sopenharmony_ci	struct old_timeval32 tv;
12708c2ecf20Sopenharmony_ci	int ret;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	if (tvp) {
12738c2ecf20Sopenharmony_ci		if (copy_from_user(&tv, tvp, sizeof(tv)))
12748c2ecf20Sopenharmony_ci			return -EFAULT;
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci		to = &end_time;
12778c2ecf20Sopenharmony_ci		if (poll_select_set_timeout(to,
12788c2ecf20Sopenharmony_ci				tv.tv_sec + (tv.tv_usec / USEC_PER_SEC),
12798c2ecf20Sopenharmony_ci				(tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC))
12808c2ecf20Sopenharmony_ci			return -EINVAL;
12818c2ecf20Sopenharmony_ci	}
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	ret = compat_core_sys_select(n, inp, outp, exp, to);
12848c2ecf20Sopenharmony_ci	return poll_select_finish(&end_time, tvp, PT_OLD_TIMEVAL, ret);
12858c2ecf20Sopenharmony_ci}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(select, int, n, compat_ulong_t __user *, inp,
12888c2ecf20Sopenharmony_ci	compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
12898c2ecf20Sopenharmony_ci	struct old_timeval32 __user *, tvp)
12908c2ecf20Sopenharmony_ci{
12918c2ecf20Sopenharmony_ci	return do_compat_select(n, inp, outp, exp, tvp);
12928c2ecf20Sopenharmony_ci}
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_cistruct compat_sel_arg_struct {
12958c2ecf20Sopenharmony_ci	compat_ulong_t n;
12968c2ecf20Sopenharmony_ci	compat_uptr_t inp;
12978c2ecf20Sopenharmony_ci	compat_uptr_t outp;
12988c2ecf20Sopenharmony_ci	compat_uptr_t exp;
12998c2ecf20Sopenharmony_ci	compat_uptr_t tvp;
13008c2ecf20Sopenharmony_ci};
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE1(old_select, struct compat_sel_arg_struct __user *, arg)
13038c2ecf20Sopenharmony_ci{
13048c2ecf20Sopenharmony_ci	struct compat_sel_arg_struct a;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	if (copy_from_user(&a, arg, sizeof(a)))
13078c2ecf20Sopenharmony_ci		return -EFAULT;
13088c2ecf20Sopenharmony_ci	return do_compat_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
13098c2ecf20Sopenharmony_ci				compat_ptr(a.exp), compat_ptr(a.tvp));
13108c2ecf20Sopenharmony_ci}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_cistatic long do_compat_pselect(int n, compat_ulong_t __user *inp,
13138c2ecf20Sopenharmony_ci	compat_ulong_t __user *outp, compat_ulong_t __user *exp,
13148c2ecf20Sopenharmony_ci	void __user *tsp, compat_sigset_t __user *sigmask,
13158c2ecf20Sopenharmony_ci	compat_size_t sigsetsize, enum poll_time_type type)
13168c2ecf20Sopenharmony_ci{
13178c2ecf20Sopenharmony_ci	struct timespec64 ts, end_time, *to = NULL;
13188c2ecf20Sopenharmony_ci	int ret;
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	if (tsp) {
13218c2ecf20Sopenharmony_ci		switch (type) {
13228c2ecf20Sopenharmony_ci		case PT_OLD_TIMESPEC:
13238c2ecf20Sopenharmony_ci			if (get_old_timespec32(&ts, tsp))
13248c2ecf20Sopenharmony_ci				return -EFAULT;
13258c2ecf20Sopenharmony_ci			break;
13268c2ecf20Sopenharmony_ci		case PT_TIMESPEC:
13278c2ecf20Sopenharmony_ci			if (get_timespec64(&ts, tsp))
13288c2ecf20Sopenharmony_ci				return -EFAULT;
13298c2ecf20Sopenharmony_ci			break;
13308c2ecf20Sopenharmony_ci		default:
13318c2ecf20Sopenharmony_ci			BUG();
13328c2ecf20Sopenharmony_ci		}
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		to = &end_time;
13358c2ecf20Sopenharmony_ci		if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
13368c2ecf20Sopenharmony_ci			return -EINVAL;
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	ret = set_compat_user_sigmask(sigmask, sigsetsize);
13408c2ecf20Sopenharmony_ci	if (ret)
13418c2ecf20Sopenharmony_ci		return ret;
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	ret = compat_core_sys_select(n, inp, outp, exp, to);
13448c2ecf20Sopenharmony_ci	return poll_select_finish(&end_time, tsp, type, ret);
13458c2ecf20Sopenharmony_ci}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_cistruct compat_sigset_argpack {
13488c2ecf20Sopenharmony_ci	compat_uptr_t p;
13498c2ecf20Sopenharmony_ci	compat_size_t size;
13508c2ecf20Sopenharmony_ci};
13518c2ecf20Sopenharmony_cistatic inline int get_compat_sigset_argpack(struct compat_sigset_argpack *to,
13528c2ecf20Sopenharmony_ci					    struct compat_sigset_argpack __user *from)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	if (from) {
13558c2ecf20Sopenharmony_ci		if (!user_read_access_begin(from, sizeof(*from)))
13568c2ecf20Sopenharmony_ci			return -EFAULT;
13578c2ecf20Sopenharmony_ci		unsafe_get_user(to->p, &from->p, Efault);
13588c2ecf20Sopenharmony_ci		unsafe_get_user(to->size, &from->size, Efault);
13598c2ecf20Sopenharmony_ci		user_read_access_end();
13608c2ecf20Sopenharmony_ci	}
13618c2ecf20Sopenharmony_ci	return 0;
13628c2ecf20Sopenharmony_ciEfault:
13638c2ecf20Sopenharmony_ci	user_access_end();
13648c2ecf20Sopenharmony_ci	return -EFAULT;
13658c2ecf20Sopenharmony_ci}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE6(pselect6_time64, int, n, compat_ulong_t __user *, inp,
13688c2ecf20Sopenharmony_ci	compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
13698c2ecf20Sopenharmony_ci	struct __kernel_timespec __user *, tsp, void __user *, sig)
13708c2ecf20Sopenharmony_ci{
13718c2ecf20Sopenharmony_ci	struct compat_sigset_argpack x = {0, 0};
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	if (get_compat_sigset_argpack(&x, sig))
13748c2ecf20Sopenharmony_ci		return -EFAULT;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(x.p),
13778c2ecf20Sopenharmony_ci				 x.size, PT_TIMESPEC);
13788c2ecf20Sopenharmony_ci}
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci#if defined(CONFIG_COMPAT_32BIT_TIME)
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE6(pselect6_time32, int, n, compat_ulong_t __user *, inp,
13838c2ecf20Sopenharmony_ci	compat_ulong_t __user *, outp, compat_ulong_t __user *, exp,
13848c2ecf20Sopenharmony_ci	struct old_timespec32 __user *, tsp, void __user *, sig)
13858c2ecf20Sopenharmony_ci{
13868c2ecf20Sopenharmony_ci	struct compat_sigset_argpack x = {0, 0};
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	if (get_compat_sigset_argpack(&x, sig))
13898c2ecf20Sopenharmony_ci		return -EFAULT;
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	return do_compat_pselect(n, inp, outp, exp, tsp, compat_ptr(x.p),
13928c2ecf20Sopenharmony_ci				 x.size, PT_OLD_TIMESPEC);
13938c2ecf20Sopenharmony_ci}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci#endif
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci#if defined(CONFIG_COMPAT_32BIT_TIME)
13988c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(ppoll_time32, struct pollfd __user *, ufds,
13998c2ecf20Sopenharmony_ci	unsigned int,  nfds, struct old_timespec32 __user *, tsp,
14008c2ecf20Sopenharmony_ci	const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize)
14018c2ecf20Sopenharmony_ci{
14028c2ecf20Sopenharmony_ci	struct timespec64 ts, end_time, *to = NULL;
14038c2ecf20Sopenharmony_ci	int ret;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	if (tsp) {
14068c2ecf20Sopenharmony_ci		if (get_old_timespec32(&ts, tsp))
14078c2ecf20Sopenharmony_ci			return -EFAULT;
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci		to = &end_time;
14108c2ecf20Sopenharmony_ci		if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
14118c2ecf20Sopenharmony_ci			return -EINVAL;
14128c2ecf20Sopenharmony_ci	}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	ret = set_compat_user_sigmask(sigmask, sigsetsize);
14158c2ecf20Sopenharmony_ci	if (ret)
14168c2ecf20Sopenharmony_ci		return ret;
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	ret = do_sys_poll(ufds, nfds, to);
14198c2ecf20Sopenharmony_ci	return poll_select_finish(&end_time, tsp, PT_OLD_TIMESPEC, ret);
14208c2ecf20Sopenharmony_ci}
14218c2ecf20Sopenharmony_ci#endif
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci/* New compat syscall for 64 bit time_t*/
14248c2ecf20Sopenharmony_ciCOMPAT_SYSCALL_DEFINE5(ppoll_time64, struct pollfd __user *, ufds,
14258c2ecf20Sopenharmony_ci	unsigned int,  nfds, struct __kernel_timespec __user *, tsp,
14268c2ecf20Sopenharmony_ci	const compat_sigset_t __user *, sigmask, compat_size_t, sigsetsize)
14278c2ecf20Sopenharmony_ci{
14288c2ecf20Sopenharmony_ci	struct timespec64 ts, end_time, *to = NULL;
14298c2ecf20Sopenharmony_ci	int ret;
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	if (tsp) {
14328c2ecf20Sopenharmony_ci		if (get_timespec64(&ts, tsp))
14338c2ecf20Sopenharmony_ci			return -EFAULT;
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci		to = &end_time;
14368c2ecf20Sopenharmony_ci		if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec))
14378c2ecf20Sopenharmony_ci			return -EINVAL;
14388c2ecf20Sopenharmony_ci	}
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	ret = set_compat_user_sigmask(sigmask, sigsetsize);
14418c2ecf20Sopenharmony_ci	if (ret)
14428c2ecf20Sopenharmony_ci		return ret;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	ret = do_sys_poll(ufds, nfds, to);
14458c2ecf20Sopenharmony_ci	return poll_select_finish(&end_time, tsp, PT_TIMESPEC, ret);
14468c2ecf20Sopenharmony_ci}
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci#endif
1449