diff options
Diffstat (limited to 'fs/select.c')
-rw-r--r-- | fs/select.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/fs/select.c b/fs/select.c index b80e7eb0ac0d..f10a10317d54 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/personality.h> /* for STICKY_TIMEOUTS */ | 22 | #include <linux/personality.h> /* for STICKY_TIMEOUTS */ |
23 | #include <linux/file.h> | 23 | #include <linux/file.h> |
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <linux/rcupdate.h> | ||
25 | 26 | ||
26 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
27 | 28 | ||
@@ -132,11 +133,13 @@ static int max_select_fd(unsigned long n, fd_set_bits *fds) | |||
132 | unsigned long *open_fds; | 133 | unsigned long *open_fds; |
133 | unsigned long set; | 134 | unsigned long set; |
134 | int max; | 135 | int max; |
136 | struct fdtable *fdt; | ||
135 | 137 | ||
136 | /* handle last in-complete long-word first */ | 138 | /* handle last in-complete long-word first */ |
137 | set = ~(~0UL << (n & (__NFDBITS-1))); | 139 | set = ~(~0UL << (n & (__NFDBITS-1))); |
138 | n /= __NFDBITS; | 140 | n /= __NFDBITS; |
139 | open_fds = current->files->open_fds->fds_bits+n; | 141 | fdt = files_fdtable(current->files); |
142 | open_fds = fdt->open_fds->fds_bits+n; | ||
140 | max = 0; | 143 | max = 0; |
141 | if (set) { | 144 | if (set) { |
142 | set &= BITS(fds, n); | 145 | set &= BITS(fds, n); |
@@ -183,9 +186,9 @@ int do_select(int n, fd_set_bits *fds, long *timeout) | |||
183 | int retval, i; | 186 | int retval, i; |
184 | long __timeout = *timeout; | 187 | long __timeout = *timeout; |
185 | 188 | ||
186 | spin_lock(¤t->files->file_lock); | 189 | rcu_read_lock(); |
187 | retval = max_select_fd(n, fds); | 190 | retval = max_select_fd(n, fds); |
188 | spin_unlock(¤t->files->file_lock); | 191 | rcu_read_unlock(); |
189 | 192 | ||
190 | if (retval < 0) | 193 | if (retval < 0) |
191 | return retval; | 194 | return retval; |
@@ -299,6 +302,7 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s | |||
299 | char *bits; | 302 | char *bits; |
300 | long timeout; | 303 | long timeout; |
301 | int ret, size, max_fdset; | 304 | int ret, size, max_fdset; |
305 | struct fdtable *fdt; | ||
302 | 306 | ||
303 | timeout = MAX_SCHEDULE_TIMEOUT; | 307 | timeout = MAX_SCHEDULE_TIMEOUT; |
304 | if (tvp) { | 308 | if (tvp) { |
@@ -326,7 +330,10 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s | |||
326 | goto out_nofds; | 330 | goto out_nofds; |
327 | 331 | ||
328 | /* max_fdset can increase, so grab it once to avoid race */ | 332 | /* max_fdset can increase, so grab it once to avoid race */ |
329 | max_fdset = current->files->max_fdset; | 333 | rcu_read_lock(); |
334 | fdt = files_fdtable(current->files); | ||
335 | max_fdset = fdt->max_fdset; | ||
336 | rcu_read_unlock(); | ||
330 | if (n > max_fdset) | 337 | if (n > max_fdset) |
331 | n = max_fdset; | 338 | n = max_fdset; |
332 | 339 | ||
@@ -464,9 +471,15 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti | |||
464 | unsigned int i; | 471 | unsigned int i; |
465 | struct poll_list *head; | 472 | struct poll_list *head; |
466 | struct poll_list *walk; | 473 | struct poll_list *walk; |
474 | struct fdtable *fdt; | ||
475 | int max_fdset; | ||
467 | 476 | ||
468 | /* Do a sanity check on nfds ... */ | 477 | /* Do a sanity check on nfds ... */ |
469 | if (nfds > current->files->max_fdset && nfds > OPEN_MAX) | 478 | rcu_read_lock(); |
479 | fdt = files_fdtable(current->files); | ||
480 | max_fdset = fdt->max_fdset; | ||
481 | rcu_read_unlock(); | ||
482 | if (nfds > max_fdset && nfds > OPEN_MAX) | ||
470 | return -EINVAL; | 483 | return -EINVAL; |
471 | 484 | ||
472 | if (timeout) { | 485 | if (timeout) { |