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 = ¤t->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