|
@@ -130,6 +130,81 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
|
|
|
add_wait_queue(wait_address, &entry->wait);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * poll_select_set_timeout - helper function to setup the timeout value
|
|
|
+ * @to: pointer to timespec variable for the final timeout
|
|
|
+ * @sec: seconds (from user space)
|
|
|
+ * @nsec: nanoseconds (from user space)
|
|
|
+ *
|
|
|
+ * Note, we do not use a timespec for the user space value here, That
|
|
|
+ * way we can use the function for timeval and compat interfaces as well.
|
|
|
+ *
|
|
|
+ * Returns -EINVAL if sec/nsec are not normalized. Otherwise 0.
|
|
|
+ */
|
|
|
+int poll_select_set_timeout(struct timespec *to, long sec, long nsec)
|
|
|
+{
|
|
|
+ struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec};
|
|
|
+
|
|
|
+ if (!timespec_valid(&ts))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* Optimize for the zero timeout value here */
|
|
|
+ if (!sec && !nsec) {
|
|
|
+ to->tv_sec = to->tv_nsec = 0;
|
|
|
+ } else {
|
|
|
+ ktime_get_ts(to);
|
|
|
+ *to = timespec_add_safe(*to, ts);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int poll_select_copy_remaining(struct timespec *end_time, void __user *p,
|
|
|
+ int timeval, int ret)
|
|
|
+{
|
|
|
+ struct timespec rts;
|
|
|
+ struct timeval rtv;
|
|
|
+
|
|
|
+ if (!p)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if (current->personality & STICKY_TIMEOUTS)
|
|
|
+ goto sticky;
|
|
|
+
|
|
|
+ /* No update for zero timeout */
|
|
|
+ if (!end_time->tv_sec && !end_time->tv_nsec)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ktime_get_ts(&rts);
|
|
|
+ rts = timespec_sub(*end_time, rts);
|
|
|
+ if (rts.tv_sec < 0)
|
|
|
+ rts.tv_sec = rts.tv_nsec = 0;
|
|
|
+
|
|
|
+ if (timeval) {
|
|
|
+ rtv.tv_sec = rts.tv_sec;
|
|
|
+ rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC;
|
|
|
+
|
|
|
+ if (!copy_to_user(p, &rtv, sizeof(rtv)))
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ } else if (!copy_to_user(p, &rts, sizeof(rts)))
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If an application puts its timeval in read-only memory, we
|
|
|
+ * don't want the Linux-specific update to the timeval to
|
|
|
+ * cause a fault after the select has completed
|
|
|
+ * successfully. However, because we're not updating the
|
|
|
+ * timeval, we can't restart the system call.
|
|
|
+ */
|
|
|
+
|
|
|
+sticky:
|
|
|
+ if (ret == -ERESTARTNOHAND)
|
|
|
+ ret = -EINTR;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
#define FDS_IN(fds, n) (fds->in + n)
|
|
|
#define FDS_OUT(fds, n) (fds->out + n)
|
|
|
#define FDS_EX(fds, n) (fds->ex + n)
|