diff options
Diffstat (limited to 'fs/select.c')
-rw-r--r-- | fs/select.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/fs/select.c b/fs/select.c index da0e88201c3a..1180a6207789 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -130,6 +130,81 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | |||
130 | add_wait_queue(wait_address, &entry->wait); | 130 | add_wait_queue(wait_address, &entry->wait); |
131 | } | 131 | } |
132 | 132 | ||
133 | /** | ||
134 | * poll_select_set_timeout - helper function to setup the timeout value | ||
135 | * @to: pointer to timespec variable for the final timeout | ||
136 | * @sec: seconds (from user space) | ||
137 | * @nsec: nanoseconds (from user space) | ||
138 | * | ||
139 | * Note, we do not use a timespec for the user space value here, That | ||
140 | * way we can use the function for timeval and compat interfaces as well. | ||
141 | * | ||
142 | * Returns -EINVAL if sec/nsec are not normalized. Otherwise 0. | ||
143 | */ | ||
144 | int poll_select_set_timeout(struct timespec *to, long sec, long nsec) | ||
145 | { | ||
146 | struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec}; | ||
147 | |||
148 | if (!timespec_valid(&ts)) | ||
149 | return -EINVAL; | ||
150 | |||
151 | /* Optimize for the zero timeout value here */ | ||
152 | if (!sec && !nsec) { | ||
153 | to->tv_sec = to->tv_nsec = 0; | ||
154 | } else { | ||
155 | ktime_get_ts(to); | ||
156 | *to = timespec_add_safe(*to, ts); | ||
157 | } | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int poll_select_copy_remaining(struct timespec *end_time, void __user *p, | ||
162 | int timeval, int ret) | ||
163 | { | ||
164 | struct timespec rts; | ||
165 | struct timeval rtv; | ||
166 | |||
167 | if (!p) | ||
168 | return ret; | ||
169 | |||
170 | if (current->personality & STICKY_TIMEOUTS) | ||
171 | goto sticky; | ||
172 | |||
173 | /* No update for zero timeout */ | ||
174 | if (!end_time->tv_sec && !end_time->tv_nsec) | ||
175 | return ret; | ||
176 | |||
177 | ktime_get_ts(&rts); | ||
178 | rts = timespec_sub(*end_time, rts); | ||
179 | if (rts.tv_sec < 0) | ||
180 | rts.tv_sec = rts.tv_nsec = 0; | ||
181 | |||
182 | if (timeval) { | ||
183 | rtv.tv_sec = rts.tv_sec; | ||
184 | rtv.tv_usec = rts.tv_nsec / NSEC_PER_USEC; | ||
185 | |||
186 | if (!copy_to_user(p, &rtv, sizeof(rtv))) | ||
187 | return ret; | ||
188 | |||
189 | } else if (!copy_to_user(p, &rts, sizeof(rts))) | ||
190 | return ret; | ||
191 | |||
192 | /* | ||
193 | * If an application puts its timeval in read-only memory, we | ||
194 | * don't want the Linux-specific update to the timeval to | ||
195 | * cause a fault after the select has completed | ||
196 | * successfully. However, because we're not updating the | ||
197 | * timeval, we can't restart the system call. | ||
198 | */ | ||
199 | |||
200 | sticky: | ||
201 | if (ret == -ERESTARTNOHAND) | ||
202 | ret = -EINTR; | ||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | |||
207 | |||
133 | #define FDS_IN(fds, n) (fds->in + n) | 208 | #define FDS_IN(fds, n) (fds->in + n) |
134 | #define FDS_OUT(fds, n) (fds->out + n) | 209 | #define FDS_OUT(fds, n) (fds->out + n) |
135 | #define FDS_EX(fds, n) (fds->ex + n) | 210 | #define FDS_EX(fds, n) (fds->ex + n) |