diff options
| -rw-r--r-- | arch/alpha/kernel/osf_sys.c | 4 | ||||
| -rw-r--r-- | arch/ia64/kernel/perfmon.c | 7 | ||||
| -rw-r--r-- | arch/sparc64/solaris/ioctl.c | 8 | ||||
| -rw-r--r-- | drivers/char/tty_io.c | 4 | ||||
| -rw-r--r-- | fs/exec.c | 8 | ||||
| -rw-r--r-- | fs/fcntl.c | 47 | ||||
| -rw-r--r-- | fs/file.c | 42 | ||||
| -rw-r--r-- | fs/locks.c | 8 | ||||
| -rw-r--r-- | fs/open.c | 41 | ||||
| -rw-r--r-- | fs/proc/array.c | 5 | ||||
| -rw-r--r-- | fs/proc/base.c | 4 | ||||
| -rw-r--r-- | fs/select.c | 12 | ||||
| -rw-r--r-- | include/linux/file.h | 23 | ||||
| -rw-r--r-- | include/linux/init_task.h | 13 | ||||
| -rw-r--r-- | kernel/exit.c | 21 | ||||
| -rw-r--r-- | kernel/fork.c | 82 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 6 |
17 files changed, 211 insertions, 124 deletions
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 167fd89f8707..2b034182a0ca 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c | |||
| @@ -974,6 +974,7 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, | |||
| 974 | size_t size; | 974 | size_t size; |
| 975 | long timeout; | 975 | long timeout; |
| 976 | int ret = -EINVAL; | 976 | int ret = -EINVAL; |
| 977 | struct fdtable *fdt; | ||
| 977 | 978 | ||
| 978 | timeout = MAX_SCHEDULE_TIMEOUT; | 979 | timeout = MAX_SCHEDULE_TIMEOUT; |
| 979 | if (tvp) { | 980 | if (tvp) { |
| @@ -995,7 +996,8 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, | |||
| 995 | } | 996 | } |
| 996 | } | 997 | } |
| 997 | 998 | ||
| 998 | if (n < 0 || n > current->files->max_fdset) | 999 | fdt = files_fdtable(current->files); |
| 1000 | if (n < 0 || n > fdt->max_fdset) | ||
| 999 | goto out_nofds; | 1001 | goto out_nofds; |
| 1000 | 1002 | ||
| 1001 | /* | 1003 | /* |
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index f1201ac8a116..4ad97b3b39dc 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/pagemap.h> | 38 | #include <linux/pagemap.h> |
| 39 | #include <linux/mount.h> | 39 | #include <linux/mount.h> |
| 40 | #include <linux/bitops.h> | 40 | #include <linux/bitops.h> |
| 41 | #include <linux/rcupdate.h> | ||
| 41 | 42 | ||
| 42 | #include <asm/errno.h> | 43 | #include <asm/errno.h> |
| 43 | #include <asm/intrinsics.h> | 44 | #include <asm/intrinsics.h> |
| @@ -2217,15 +2218,17 @@ static void | |||
| 2217 | pfm_free_fd(int fd, struct file *file) | 2218 | pfm_free_fd(int fd, struct file *file) |
| 2218 | { | 2219 | { |
| 2219 | struct files_struct *files = current->files; | 2220 | struct files_struct *files = current->files; |
| 2221 | struct fdtable *fdt = files_fdtable(files); | ||
| 2220 | 2222 | ||
| 2221 | /* | 2223 | /* |
| 2222 | * there ie no fd_uninstall(), so we do it here | 2224 | * there ie no fd_uninstall(), so we do it here |
| 2223 | */ | 2225 | */ |
| 2224 | spin_lock(&files->file_lock); | 2226 | spin_lock(&files->file_lock); |
| 2225 | files->fd[fd] = NULL; | 2227 | rcu_assign_pointer(fdt->fd[fd], NULL); |
| 2226 | spin_unlock(&files->file_lock); | 2228 | spin_unlock(&files->file_lock); |
| 2227 | 2229 | ||
| 2228 | if (file) put_filp(file); | 2230 | if (file) |
| 2231 | put_filp(file); | ||
| 2229 | put_unused_fd(fd); | 2232 | put_unused_fd(fd); |
| 2230 | } | 2233 | } |
| 2231 | 2234 | ||
diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c index cac0a1cf0050..374766455f5e 100644 --- a/arch/sparc64/solaris/ioctl.c +++ b/arch/sparc64/solaris/ioctl.c | |||
| @@ -293,11 +293,13 @@ static struct module_info { | |||
| 293 | static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg) | 293 | static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg) |
| 294 | { | 294 | { |
| 295 | struct inode *ino; | 295 | struct inode *ino; |
| 296 | struct fdtable *fdt; | ||
| 296 | /* I wonder which of these tests are superfluous... --patrik */ | 297 | /* I wonder which of these tests are superfluous... --patrik */ |
| 297 | spin_lock(¤t->files->file_lock); | 298 | spin_lock(¤t->files->file_lock); |
| 298 | if (! current->files->fd[fd] || | 299 | fdt = files_fdtable(current->files); |
| 299 | ! current->files->fd[fd]->f_dentry || | 300 | if (! fdt->fd[fd] || |
| 300 | ! (ino = current->files->fd[fd]->f_dentry->d_inode) || | 301 | ! fdt->fd[fd]->f_dentry || |
| 302 | ! (ino = fdt->fd[fd]->f_dentry->d_inode) || | ||
| 301 | ! S_ISSOCK(ino->i_mode)) { | 303 | ! S_ISSOCK(ino->i_mode)) { |
| 302 | spin_unlock(¤t->files->file_lock); | 304 | spin_unlock(¤t->files->file_lock); |
| 303 | return TBADF; | 305 | return TBADF; |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 6a56ae4f7725..0bfc7af68917 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
| @@ -2454,6 +2454,7 @@ static void __do_SAK(void *arg) | |||
| 2454 | int i; | 2454 | int i; |
| 2455 | struct file *filp; | 2455 | struct file *filp; |
| 2456 | struct tty_ldisc *disc; | 2456 | struct tty_ldisc *disc; |
| 2457 | struct fdtable *fdt; | ||
| 2457 | 2458 | ||
| 2458 | if (!tty) | 2459 | if (!tty) |
| 2459 | return; | 2460 | return; |
| @@ -2480,7 +2481,8 @@ static void __do_SAK(void *arg) | |||
| 2480 | task_lock(p); | 2481 | task_lock(p); |
| 2481 | if (p->files) { | 2482 | if (p->files) { |
| 2482 | spin_lock(&p->files->file_lock); | 2483 | spin_lock(&p->files->file_lock); |
| 2483 | for (i=0; i < p->files->max_fds; i++) { | 2484 | fdt = files_fdtable(p->files); |
| 2485 | for (i=0; i < fdt->max_fds; i++) { | ||
| 2484 | filp = fcheck_files(p->files, i); | 2486 | filp = fcheck_files(p->files, i); |
| 2485 | if (!filp) | 2487 | if (!filp) |
| 2486 | continue; | 2488 | continue; |
| @@ -798,6 +798,7 @@ no_thread_group: | |||
| 798 | static inline void flush_old_files(struct files_struct * files) | 798 | static inline void flush_old_files(struct files_struct * files) |
| 799 | { | 799 | { |
| 800 | long j = -1; | 800 | long j = -1; |
| 801 | struct fdtable *fdt; | ||
| 801 | 802 | ||
| 802 | spin_lock(&files->file_lock); | 803 | spin_lock(&files->file_lock); |
| 803 | for (;;) { | 804 | for (;;) { |
| @@ -805,12 +806,13 @@ static inline void flush_old_files(struct files_struct * files) | |||
| 805 | 806 | ||
| 806 | j++; | 807 | j++; |
| 807 | i = j * __NFDBITS; | 808 | i = j * __NFDBITS; |
| 808 | if (i >= files->max_fds || i >= files->max_fdset) | 809 | fdt = files_fdtable(files); |
| 810 | if (i >= fdt->max_fds || i >= fdt->max_fdset) | ||
| 809 | break; | 811 | break; |
| 810 | set = files->close_on_exec->fds_bits[j]; | 812 | set = fdt->close_on_exec->fds_bits[j]; |
| 811 | if (!set) | 813 | if (!set) |
| 812 | continue; | 814 | continue; |
| 813 | files->close_on_exec->fds_bits[j] = 0; | 815 | fdt->close_on_exec->fds_bits[j] = 0; |
| 814 | spin_unlock(&files->file_lock); | 816 | spin_unlock(&files->file_lock); |
| 815 | for ( ; set ; i++,set >>= 1) { | 817 | for ( ; set ; i++,set >>= 1) { |
| 816 | if (set & 1) { | 818 | if (set & 1) { |
diff --git a/fs/fcntl.c b/fs/fcntl.c index 6fbc9d8fcc36..bfecc6238083 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -24,20 +24,24 @@ | |||
| 24 | void fastcall set_close_on_exec(unsigned int fd, int flag) | 24 | void fastcall set_close_on_exec(unsigned int fd, int flag) |
| 25 | { | 25 | { |
| 26 | struct files_struct *files = current->files; | 26 | struct files_struct *files = current->files; |
| 27 | struct fdtable *fdt; | ||
| 27 | spin_lock(&files->file_lock); | 28 | spin_lock(&files->file_lock); |
| 29 | fdt = files_fdtable(files); | ||
| 28 | if (flag) | 30 | if (flag) |
| 29 | FD_SET(fd, files->close_on_exec); | 31 | FD_SET(fd, fdt->close_on_exec); |
| 30 | else | 32 | else |
| 31 | FD_CLR(fd, files->close_on_exec); | 33 | FD_CLR(fd, fdt->close_on_exec); |
| 32 | spin_unlock(&files->file_lock); | 34 | spin_unlock(&files->file_lock); |
| 33 | } | 35 | } |
| 34 | 36 | ||
| 35 | static inline int get_close_on_exec(unsigned int fd) | 37 | static inline int get_close_on_exec(unsigned int fd) |
| 36 | { | 38 | { |
| 37 | struct files_struct *files = current->files; | 39 | struct files_struct *files = current->files; |
| 40 | struct fdtable *fdt; | ||
| 38 | int res; | 41 | int res; |
| 39 | spin_lock(&files->file_lock); | 42 | spin_lock(&files->file_lock); |
| 40 | res = FD_ISSET(fd, files->close_on_exec); | 43 | fdt = files_fdtable(files); |
| 44 | res = FD_ISSET(fd, fdt->close_on_exec); | ||
| 41 | spin_unlock(&files->file_lock); | 45 | spin_unlock(&files->file_lock); |
| 42 | return res; | 46 | return res; |
| 43 | } | 47 | } |
| @@ -54,24 +58,26 @@ static int locate_fd(struct files_struct *files, | |||
| 54 | unsigned int newfd; | 58 | unsigned int newfd; |
| 55 | unsigned int start; | 59 | unsigned int start; |
| 56 | int error; | 60 | int error; |
| 61 | struct fdtable *fdt; | ||
| 57 | 62 | ||
| 58 | error = -EINVAL; | 63 | error = -EINVAL; |
| 59 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | 64 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) |
| 60 | goto out; | 65 | goto out; |
| 61 | 66 | ||
| 67 | fdt = files_fdtable(files); | ||
| 62 | repeat: | 68 | repeat: |
| 63 | /* | 69 | /* |
| 64 | * Someone might have closed fd's in the range | 70 | * Someone might have closed fd's in the range |
| 65 | * orig_start..files->next_fd | 71 | * orig_start..fdt->next_fd |
| 66 | */ | 72 | */ |
| 67 | start = orig_start; | 73 | start = orig_start; |
| 68 | if (start < files->next_fd) | 74 | if (start < fdt->next_fd) |
| 69 | start = files->next_fd; | 75 | start = fdt->next_fd; |
| 70 | 76 | ||
| 71 | newfd = start; | 77 | newfd = start; |
| 72 | if (start < files->max_fdset) { | 78 | if (start < fdt->max_fdset) { |
| 73 | newfd = find_next_zero_bit(files->open_fds->fds_bits, | 79 | newfd = find_next_zero_bit(fdt->open_fds->fds_bits, |
| 74 | files->max_fdset, start); | 80 | fdt->max_fdset, start); |
| 75 | } | 81 | } |
| 76 | 82 | ||
| 77 | error = -EMFILE; | 83 | error = -EMFILE; |
| @@ -89,8 +95,8 @@ repeat: | |||
| 89 | if (error) | 95 | if (error) |
| 90 | goto repeat; | 96 | goto repeat; |
| 91 | 97 | ||
| 92 | if (start <= files->next_fd) | 98 | if (start <= fdt->next_fd) |
| 93 | files->next_fd = newfd + 1; | 99 | fdt->next_fd = newfd + 1; |
| 94 | 100 | ||
| 95 | error = newfd; | 101 | error = newfd; |
| 96 | 102 | ||
| @@ -101,13 +107,16 @@ out: | |||
| 101 | static int dupfd(struct file *file, unsigned int start) | 107 | static int dupfd(struct file *file, unsigned int start) |
| 102 | { | 108 | { |
| 103 | struct files_struct * files = current->files; | 109 | struct files_struct * files = current->files; |
| 110 | struct fdtable *fdt; | ||
| 104 | int fd; | 111 | int fd; |
| 105 | 112 | ||
| 106 | spin_lock(&files->file_lock); | 113 | spin_lock(&files->file_lock); |
| 107 | fd = locate_fd(files, file, start); | 114 | fd = locate_fd(files, file, start); |
| 108 | if (fd >= 0) { | 115 | if (fd >= 0) { |
| 109 | FD_SET(fd, files->open_fds); | 116 | /* locate_fd() may have expanded fdtable, load the ptr */ |
| 110 | FD_CLR(fd, files->close_on_exec); | 117 | fdt = files_fdtable(files); |
| 118 | FD_SET(fd, fdt->open_fds); | ||
| 119 | FD_CLR(fd, fdt->close_on_exec); | ||
| 111 | spin_unlock(&files->file_lock); | 120 | spin_unlock(&files->file_lock); |
| 112 | fd_install(fd, file); | 121 | fd_install(fd, file); |
| 113 | } else { | 122 | } else { |
| @@ -123,6 +132,7 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) | |||
| 123 | int err = -EBADF; | 132 | int err = -EBADF; |
| 124 | struct file * file, *tofree; | 133 | struct file * file, *tofree; |
| 125 | struct files_struct * files = current->files; | 134 | struct files_struct * files = current->files; |
| 135 | struct fdtable *fdt; | ||
| 126 | 136 | ||
| 127 | spin_lock(&files->file_lock); | 137 | spin_lock(&files->file_lock); |
| 128 | if (!(file = fcheck(oldfd))) | 138 | if (!(file = fcheck(oldfd))) |
| @@ -148,13 +158,14 @@ asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) | |||
| 148 | 158 | ||
| 149 | /* Yes. It's a race. In user space. Nothing sane to do */ | 159 | /* Yes. It's a race. In user space. Nothing sane to do */ |
| 150 | err = -EBUSY; | 160 | err = -EBUSY; |
| 151 | tofree = files->fd[newfd]; | 161 | fdt = files_fdtable(files); |
| 152 | if (!tofree && FD_ISSET(newfd, files->open_fds)) | 162 | tofree = fdt->fd[newfd]; |
| 163 | if (!tofree && FD_ISSET(newfd, fdt->open_fds)) | ||
| 153 | goto out_fput; | 164 | goto out_fput; |
| 154 | 165 | ||
| 155 | files->fd[newfd] = file; | 166 | fdt->fd[newfd] = file; |
| 156 | FD_SET(newfd, files->open_fds); | 167 | FD_SET(newfd, fdt->open_fds); |
| 157 | FD_CLR(newfd, files->close_on_exec); | 168 | FD_CLR(newfd, fdt->close_on_exec); |
| 158 | spin_unlock(&files->file_lock); | 169 | spin_unlock(&files->file_lock); |
| 159 | 170 | ||
| 160 | if (tofree) | 171 | if (tofree) |
| @@ -59,13 +59,15 @@ static int expand_fd_array(struct files_struct *files, int nr) | |||
| 59 | { | 59 | { |
| 60 | struct file **new_fds; | 60 | struct file **new_fds; |
| 61 | int error, nfds; | 61 | int error, nfds; |
| 62 | struct fdtable *fdt; | ||
| 62 | 63 | ||
| 63 | 64 | ||
| 64 | error = -EMFILE; | 65 | error = -EMFILE; |
| 65 | if (files->max_fds >= NR_OPEN || nr >= NR_OPEN) | 66 | fdt = files_fdtable(files); |
| 67 | if (fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) | ||
| 66 | goto out; | 68 | goto out; |
| 67 | 69 | ||
| 68 | nfds = files->max_fds; | 70 | nfds = fdt->max_fds; |
| 69 | spin_unlock(&files->file_lock); | 71 | spin_unlock(&files->file_lock); |
| 70 | 72 | ||
| 71 | /* | 73 | /* |
| @@ -95,13 +97,14 @@ static int expand_fd_array(struct files_struct *files, int nr) | |||
| 95 | goto out; | 97 | goto out; |
| 96 | 98 | ||
| 97 | /* Copy the existing array and install the new pointer */ | 99 | /* Copy the existing array and install the new pointer */ |
| 100 | fdt = files_fdtable(files); | ||
| 98 | 101 | ||
| 99 | if (nfds > files->max_fds) { | 102 | if (nfds > fdt->max_fds) { |
| 100 | struct file **old_fds; | 103 | struct file **old_fds; |
| 101 | int i; | 104 | int i; |
| 102 | 105 | ||
| 103 | old_fds = xchg(&files->fd, new_fds); | 106 | old_fds = xchg(&fdt->fd, new_fds); |
| 104 | i = xchg(&files->max_fds, nfds); | 107 | i = xchg(&fdt->max_fds, nfds); |
| 105 | 108 | ||
| 106 | /* Don't copy/clear the array if we are creating a new | 109 | /* Don't copy/clear the array if we are creating a new |
| 107 | fd array for fork() */ | 110 | fd array for fork() */ |
| @@ -164,12 +167,14 @@ static int expand_fdset(struct files_struct *files, int nr) | |||
| 164 | { | 167 | { |
| 165 | fd_set *new_openset = NULL, *new_execset = NULL; | 168 | fd_set *new_openset = NULL, *new_execset = NULL; |
| 166 | int error, nfds = 0; | 169 | int error, nfds = 0; |
| 170 | struct fdtable *fdt; | ||
| 167 | 171 | ||
| 168 | error = -EMFILE; | 172 | error = -EMFILE; |
| 169 | if (files->max_fdset >= NR_OPEN || nr >= NR_OPEN) | 173 | fdt = files_fdtable(files); |
| 174 | if (fdt->max_fdset >= NR_OPEN || nr >= NR_OPEN) | ||
| 170 | goto out; | 175 | goto out; |
| 171 | 176 | ||
| 172 | nfds = files->max_fdset; | 177 | nfds = fdt->max_fdset; |
| 173 | spin_unlock(&files->file_lock); | 178 | spin_unlock(&files->file_lock); |
| 174 | 179 | ||
| 175 | /* Expand to the max in easy steps */ | 180 | /* Expand to the max in easy steps */ |
| @@ -193,24 +198,25 @@ static int expand_fdset(struct files_struct *files, int nr) | |||
| 193 | error = 0; | 198 | error = 0; |
| 194 | 199 | ||
| 195 | /* Copy the existing tables and install the new pointers */ | 200 | /* Copy the existing tables and install the new pointers */ |
| 196 | if (nfds > files->max_fdset) { | 201 | fdt = files_fdtable(files); |
| 197 | int i = files->max_fdset / (sizeof(unsigned long) * 8); | 202 | if (nfds > fdt->max_fdset) { |
| 198 | int count = (nfds - files->max_fdset) / 8; | 203 | int i = fdt->max_fdset / (sizeof(unsigned long) * 8); |
| 204 | int count = (nfds - fdt->max_fdset) / 8; | ||
| 199 | 205 | ||
| 200 | /* | 206 | /* |
| 201 | * Don't copy the entire array if the current fdset is | 207 | * Don't copy the entire array if the current fdset is |
| 202 | * not yet initialised. | 208 | * not yet initialised. |
| 203 | */ | 209 | */ |
| 204 | if (i) { | 210 | if (i) { |
| 205 | memcpy (new_openset, files->open_fds, files->max_fdset/8); | 211 | memcpy (new_openset, fdt->open_fds, fdt->max_fdset/8); |
| 206 | memcpy (new_execset, files->close_on_exec, files->max_fdset/8); | 212 | memcpy (new_execset, fdt->close_on_exec, fdt->max_fdset/8); |
| 207 | memset (&new_openset->fds_bits[i], 0, count); | 213 | memset (&new_openset->fds_bits[i], 0, count); |
| 208 | memset (&new_execset->fds_bits[i], 0, count); | 214 | memset (&new_execset->fds_bits[i], 0, count); |
| 209 | } | 215 | } |
| 210 | 216 | ||
| 211 | nfds = xchg(&files->max_fdset, nfds); | 217 | nfds = xchg(&fdt->max_fdset, nfds); |
| 212 | new_openset = xchg(&files->open_fds, new_openset); | 218 | new_openset = xchg(&fdt->open_fds, new_openset); |
| 213 | new_execset = xchg(&files->close_on_exec, new_execset); | 219 | new_execset = xchg(&fdt->close_on_exec, new_execset); |
| 214 | spin_unlock(&files->file_lock); | 220 | spin_unlock(&files->file_lock); |
| 215 | free_fdset (new_openset, nfds); | 221 | free_fdset (new_openset, nfds); |
| 216 | free_fdset (new_execset, nfds); | 222 | free_fdset (new_execset, nfds); |
| @@ -237,13 +243,15 @@ out: | |||
| 237 | int expand_files(struct files_struct *files, int nr) | 243 | int expand_files(struct files_struct *files, int nr) |
| 238 | { | 244 | { |
| 239 | int err, expand = 0; | 245 | int err, expand = 0; |
| 246 | struct fdtable *fdt; | ||
| 240 | 247 | ||
| 241 | if (nr >= files->max_fdset) { | 248 | fdt = files_fdtable(files); |
| 249 | if (nr >= fdt->max_fdset) { | ||
| 242 | expand = 1; | 250 | expand = 1; |
| 243 | if ((err = expand_fdset(files, nr))) | 251 | if ((err = expand_fdset(files, nr))) |
| 244 | goto out; | 252 | goto out; |
| 245 | } | 253 | } |
| 246 | if (nr >= files->max_fds) { | 254 | if (nr >= fdt->max_fds) { |
| 247 | expand = 1; | 255 | expand = 1; |
| 248 | if ((err = expand_fd_array(files, nr))) | 256 | if ((err = expand_fd_array(files, nr))) |
| 249 | goto out; | 257 | goto out; |
diff --git a/fs/locks.c b/fs/locks.c index 11956b6179ff..c2c09b4798d6 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -2198,21 +2198,23 @@ void steal_locks(fl_owner_t from) | |||
| 2198 | { | 2198 | { |
| 2199 | struct files_struct *files = current->files; | 2199 | struct files_struct *files = current->files; |
| 2200 | int i, j; | 2200 | int i, j; |
| 2201 | struct fdtable *fdt; | ||
| 2201 | 2202 | ||
| 2202 | if (from == files) | 2203 | if (from == files) |
| 2203 | return; | 2204 | return; |
| 2204 | 2205 | ||
| 2205 | lock_kernel(); | 2206 | lock_kernel(); |
| 2206 | j = 0; | 2207 | j = 0; |
| 2208 | fdt = files_fdtable(files); | ||
| 2207 | for (;;) { | 2209 | for (;;) { |
| 2208 | unsigned long set; | 2210 | unsigned long set; |
| 2209 | i = j * __NFDBITS; | 2211 | i = j * __NFDBITS; |
| 2210 | if (i >= files->max_fdset || i >= files->max_fds) | 2212 | if (i >= fdt->max_fdset || i >= fdt->max_fds) |
| 2211 | break; | 2213 | break; |
| 2212 | set = files->open_fds->fds_bits[j++]; | 2214 | set = fdt->open_fds->fds_bits[j++]; |
| 2213 | while (set) { | 2215 | while (set) { |
| 2214 | if (set & 1) { | 2216 | if (set & 1) { |
| 2215 | struct file *file = files->fd[i]; | 2217 | struct file *file = fdt->fd[i]; |
| 2216 | if (file) | 2218 | if (file) |
| 2217 | __steal_locks(file, from); | 2219 | __steal_locks(file, from); |
| 2218 | } | 2220 | } |
| @@ -842,14 +842,16 @@ int get_unused_fd(void) | |||
| 842 | { | 842 | { |
| 843 | struct files_struct * files = current->files; | 843 | struct files_struct * files = current->files; |
| 844 | int fd, error; | 844 | int fd, error; |
| 845 | struct fdtable *fdt; | ||
| 845 | 846 | ||
| 846 | error = -EMFILE; | 847 | error = -EMFILE; |
| 847 | spin_lock(&files->file_lock); | 848 | spin_lock(&files->file_lock); |
| 848 | 849 | ||
| 849 | repeat: | 850 | repeat: |
| 850 | fd = find_next_zero_bit(files->open_fds->fds_bits, | 851 | fdt = files_fdtable(files); |
| 851 | files->max_fdset, | 852 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, |
| 852 | files->next_fd); | 853 | fdt->max_fdset, |
| 854 | fdt->next_fd); | ||
| 853 | 855 | ||
| 854 | /* | 856 | /* |
| 855 | * N.B. For clone tasks sharing a files structure, this test | 857 | * N.B. For clone tasks sharing a files structure, this test |
| @@ -872,14 +874,14 @@ repeat: | |||
| 872 | goto repeat; | 874 | goto repeat; |
| 873 | } | 875 | } |
| 874 | 876 | ||
| 875 | FD_SET(fd, files->open_fds); | 877 | FD_SET(fd, fdt->open_fds); |
| 876 | FD_CLR(fd, files->close_on_exec); | 878 | FD_CLR(fd, fdt->close_on_exec); |
| 877 | files->next_fd = fd + 1; | 879 | fdt->next_fd = fd + 1; |
| 878 | #if 1 | 880 | #if 1 |
| 879 | /* Sanity check */ | 881 | /* Sanity check */ |
| 880 | if (files->fd[fd] != NULL) { | 882 | if (fdt->fd[fd] != NULL) { |
| 881 | printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); | 883 | printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); |
| 882 | files->fd[fd] = NULL; | 884 | fdt->fd[fd] = NULL; |
| 883 | } | 885 | } |
| 884 | #endif | 886 | #endif |
| 885 | error = fd; | 887 | error = fd; |
| @@ -893,9 +895,10 @@ EXPORT_SYMBOL(get_unused_fd); | |||
| 893 | 895 | ||
| 894 | static inline void __put_unused_fd(struct files_struct *files, unsigned int fd) | 896 | static inline void __put_unused_fd(struct files_struct *files, unsigned int fd) |
| 895 | { | 897 | { |
| 896 | __FD_CLR(fd, files->open_fds); | 898 | struct fdtable *fdt = files_fdtable(files); |
| 897 | if (fd < files->next_fd) | 899 | __FD_CLR(fd, fdt->open_fds); |
| 898 | files->next_fd = fd; | 900 | if (fd < fdt->next_fd) |
| 901 | fdt->next_fd = fd; | ||
| 899 | } | 902 | } |
| 900 | 903 | ||
| 901 | void fastcall put_unused_fd(unsigned int fd) | 904 | void fastcall put_unused_fd(unsigned int fd) |
| @@ -924,10 +927,12 @@ EXPORT_SYMBOL(put_unused_fd); | |||
| 924 | void fastcall fd_install(unsigned int fd, struct file * file) | 927 | void fastcall fd_install(unsigned int fd, struct file * file) |
| 925 | { | 928 | { |
| 926 | struct files_struct *files = current->files; | 929 | struct files_struct *files = current->files; |
| 930 | struct fdtable *fdt; | ||
| 927 | spin_lock(&files->file_lock); | 931 | spin_lock(&files->file_lock); |
| 928 | if (unlikely(files->fd[fd] != NULL)) | 932 | fdt = files_fdtable(files); |
| 933 | if (unlikely(fdt->fd[fd] != NULL)) | ||
| 929 | BUG(); | 934 | BUG(); |
| 930 | files->fd[fd] = file; | 935 | fdt->fd[fd] = file; |
| 931 | spin_unlock(&files->file_lock); | 936 | spin_unlock(&files->file_lock); |
| 932 | } | 937 | } |
| 933 | 938 | ||
| @@ -1010,15 +1015,17 @@ asmlinkage long sys_close(unsigned int fd) | |||
| 1010 | { | 1015 | { |
| 1011 | struct file * filp; | 1016 | struct file * filp; |
| 1012 | struct files_struct *files = current->files; | 1017 | struct files_struct *files = current->files; |
| 1018 | struct fdtable *fdt; | ||
| 1013 | 1019 | ||
| 1014 | spin_lock(&files->file_lock); | 1020 | spin_lock(&files->file_lock); |
| 1015 | if (fd >= files->max_fds) | 1021 | fdt = files_fdtable(files); |
| 1022 | if (fd >= fdt->max_fds) | ||
| 1016 | goto out_unlock; | 1023 | goto out_unlock; |
| 1017 | filp = files->fd[fd]; | 1024 | filp = fdt->fd[fd]; |
| 1018 | if (!filp) | 1025 | if (!filp) |
| 1019 | goto out_unlock; | 1026 | goto out_unlock; |
| 1020 | files->fd[fd] = NULL; | 1027 | fdt->fd[fd] = NULL; |
| 1021 | FD_CLR(fd, files->close_on_exec); | 1028 | FD_CLR(fd, fdt->close_on_exec); |
| 1022 | __put_unused_fd(files, fd); | 1029 | __put_unused_fd(files, fd); |
| 1023 | spin_unlock(&files->file_lock); | 1030 | spin_unlock(&files->file_lock); |
| 1024 | return filp_close(filp, files); | 1031 | return filp_close(filp, files); |
diff --git a/fs/proc/array.c b/fs/proc/array.c index 37668fe998ad..d88d518d30f6 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
| @@ -159,6 +159,7 @@ static inline char * task_state(struct task_struct *p, char *buffer) | |||
| 159 | { | 159 | { |
| 160 | struct group_info *group_info; | 160 | struct group_info *group_info; |
| 161 | int g; | 161 | int g; |
| 162 | struct fdtable *fdt = NULL; | ||
| 162 | 163 | ||
| 163 | read_lock(&tasklist_lock); | 164 | read_lock(&tasklist_lock); |
| 164 | buffer += sprintf(buffer, | 165 | buffer += sprintf(buffer, |
| @@ -179,10 +180,12 @@ static inline char * task_state(struct task_struct *p, char *buffer) | |||
| 179 | p->gid, p->egid, p->sgid, p->fsgid); | 180 | p->gid, p->egid, p->sgid, p->fsgid); |
| 180 | read_unlock(&tasklist_lock); | 181 | read_unlock(&tasklist_lock); |
| 181 | task_lock(p); | 182 | task_lock(p); |
| 183 | if (p->files) | ||
| 184 | fdt = files_fdtable(p->files); | ||
| 182 | buffer += sprintf(buffer, | 185 | buffer += sprintf(buffer, |
| 183 | "FDSize:\t%d\n" | 186 | "FDSize:\t%d\n" |
| 184 | "Groups:\t", | 187 | "Groups:\t", |
| 185 | p->files ? p->files->max_fds : 0); | 188 | fdt ? fdt->max_fds : 0); |
| 186 | 189 | ||
| 187 | group_info = p->group_info; | 190 | group_info = p->group_info; |
| 188 | get_group_info(group_info); | 191 | get_group_info(group_info); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 84751f3f52d5..d0087a0b024b 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -1039,6 +1039,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) | |||
| 1039 | int retval; | 1039 | int retval; |
| 1040 | char buf[NUMBUF]; | 1040 | char buf[NUMBUF]; |
| 1041 | struct files_struct * files; | 1041 | struct files_struct * files; |
| 1042 | struct fdtable *fdt; | ||
| 1042 | 1043 | ||
| 1043 | retval = -ENOENT; | 1044 | retval = -ENOENT; |
| 1044 | if (!pid_alive(p)) | 1045 | if (!pid_alive(p)) |
| @@ -1062,8 +1063,9 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) | |||
| 1062 | if (!files) | 1063 | if (!files) |
| 1063 | goto out; | 1064 | goto out; |
| 1064 | spin_lock(&files->file_lock); | 1065 | spin_lock(&files->file_lock); |
| 1066 | fdt = files_fdtable(files); | ||
| 1065 | for (fd = filp->f_pos-2; | 1067 | for (fd = filp->f_pos-2; |
| 1066 | fd < files->max_fds; | 1068 | fd < fdt->max_fds; |
| 1067 | fd++, filp->f_pos++) { | 1069 | fd++, filp->f_pos++) { |
| 1068 | unsigned int i,j; | 1070 | unsigned int i,j; |
| 1069 | 1071 | ||
diff --git a/fs/select.c b/fs/select.c index b80e7eb0ac0d..2e56325c73c4 100644 --- a/fs/select.c +++ b/fs/select.c | |||
| @@ -132,11 +132,13 @@ static int max_select_fd(unsigned long n, fd_set_bits *fds) | |||
| 132 | unsigned long *open_fds; | 132 | unsigned long *open_fds; |
| 133 | unsigned long set; | 133 | unsigned long set; |
| 134 | int max; | 134 | int max; |
| 135 | struct fdtable *fdt; | ||
| 135 | 136 | ||
| 136 | /* handle last in-complete long-word first */ | 137 | /* handle last in-complete long-word first */ |
| 137 | set = ~(~0UL << (n & (__NFDBITS-1))); | 138 | set = ~(~0UL << (n & (__NFDBITS-1))); |
| 138 | n /= __NFDBITS; | 139 | n /= __NFDBITS; |
| 139 | open_fds = current->files->open_fds->fds_bits+n; | 140 | fdt = files_fdtable(current->files); |
| 141 | open_fds = fdt->open_fds->fds_bits+n; | ||
| 140 | max = 0; | 142 | max = 0; |
| 141 | if (set) { | 143 | if (set) { |
| 142 | set &= BITS(fds, n); | 144 | set &= BITS(fds, n); |
| @@ -299,6 +301,7 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s | |||
| 299 | char *bits; | 301 | char *bits; |
| 300 | long timeout; | 302 | long timeout; |
| 301 | int ret, size, max_fdset; | 303 | int ret, size, max_fdset; |
| 304 | struct fdtable *fdt; | ||
| 302 | 305 | ||
| 303 | timeout = MAX_SCHEDULE_TIMEOUT; | 306 | timeout = MAX_SCHEDULE_TIMEOUT; |
| 304 | if (tvp) { | 307 | if (tvp) { |
| @@ -326,7 +329,8 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s | |||
| 326 | goto out_nofds; | 329 | goto out_nofds; |
| 327 | 330 | ||
| 328 | /* max_fdset can increase, so grab it once to avoid race */ | 331 | /* max_fdset can increase, so grab it once to avoid race */ |
| 329 | max_fdset = current->files->max_fdset; | 332 | fdt = files_fdtable(current->files); |
| 333 | max_fdset = fdt->max_fdset; | ||
| 330 | if (n > max_fdset) | 334 | if (n > max_fdset) |
| 331 | n = max_fdset; | 335 | n = max_fdset; |
| 332 | 336 | ||
| @@ -464,9 +468,11 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti | |||
| 464 | unsigned int i; | 468 | unsigned int i; |
| 465 | struct poll_list *head; | 469 | struct poll_list *head; |
| 466 | struct poll_list *walk; | 470 | struct poll_list *walk; |
| 471 | struct fdtable *fdt; | ||
| 467 | 472 | ||
| 468 | /* Do a sanity check on nfds ... */ | 473 | /* Do a sanity check on nfds ... */ |
| 469 | if (nfds > current->files->max_fdset && nfds > OPEN_MAX) | 474 | fdt = files_fdtable(current->files); |
| 475 | if (nfds > fdt->max_fdset && nfds > OPEN_MAX) | ||
| 470 | return -EINVAL; | 476 | return -EINVAL; |
| 471 | 477 | ||
| 472 | if (timeout) { | 478 | if (timeout) { |
diff --git a/include/linux/file.h b/include/linux/file.h index 5206beb9a80e..db372230848e 100644 --- a/include/linux/file.h +++ b/include/linux/file.h | |||
| @@ -16,23 +16,29 @@ | |||
| 16 | */ | 16 | */ |
| 17 | #define NR_OPEN_DEFAULT BITS_PER_LONG | 17 | #define NR_OPEN_DEFAULT BITS_PER_LONG |
| 18 | 18 | ||
| 19 | struct fdtable { | ||
| 20 | unsigned int max_fds; | ||
| 21 | int max_fdset; | ||
| 22 | int next_fd; | ||
| 23 | struct file ** fd; /* current fd array */ | ||
| 24 | fd_set *close_on_exec; | ||
| 25 | fd_set *open_fds; | ||
| 26 | }; | ||
| 27 | |||
| 19 | /* | 28 | /* |
| 20 | * Open file table structure | 29 | * Open file table structure |
| 21 | */ | 30 | */ |
| 22 | struct files_struct { | 31 | struct files_struct { |
| 23 | atomic_t count; | 32 | atomic_t count; |
| 24 | spinlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */ | 33 | spinlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */ |
| 25 | int max_fds; | 34 | struct fdtable fdtab; |
| 26 | int max_fdset; | ||
| 27 | int next_fd; | ||
| 28 | struct file ** fd; /* current fd array */ | ||
| 29 | fd_set *close_on_exec; | ||
| 30 | fd_set *open_fds; | ||
| 31 | fd_set close_on_exec_init; | 35 | fd_set close_on_exec_init; |
| 32 | fd_set open_fds_init; | 36 | fd_set open_fds_init; |
| 33 | struct file * fd_array[NR_OPEN_DEFAULT]; | 37 | struct file * fd_array[NR_OPEN_DEFAULT]; |
| 34 | }; | 38 | }; |
| 35 | 39 | ||
| 40 | #define files_fdtable(files) (&(files)->fdtab) | ||
| 41 | |||
| 36 | extern void FASTCALL(__fput(struct file *)); | 42 | extern void FASTCALL(__fput(struct file *)); |
| 37 | extern void FASTCALL(fput(struct file *)); | 43 | extern void FASTCALL(fput(struct file *)); |
| 38 | 44 | ||
| @@ -63,9 +69,10 @@ extern int expand_files(struct files_struct *, int nr); | |||
| 63 | static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) | 69 | static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) |
| 64 | { | 70 | { |
| 65 | struct file * file = NULL; | 71 | struct file * file = NULL; |
| 72 | struct fdtable *fdt = files_fdtable(files); | ||
| 66 | 73 | ||
| 67 | if (fd < files->max_fds) | 74 | if (fd < fdt->max_fds) |
| 68 | file = files->fd[fd]; | 75 | file = fdt->fd[fd]; |
| 69 | return file; | 76 | return file; |
| 70 | } | 77 | } |
| 71 | 78 | ||
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index c727c195a91a..94aefa54a1b5 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
| @@ -3,16 +3,21 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/file.h> | 4 | #include <linux/file.h> |
| 5 | 5 | ||
| 6 | #define INIT_FILES \ | 6 | #define INIT_FDTABLE \ |
| 7 | { \ | 7 | { \ |
| 8 | .count = ATOMIC_INIT(1), \ | ||
| 9 | .file_lock = SPIN_LOCK_UNLOCKED, \ | ||
| 10 | .max_fds = NR_OPEN_DEFAULT, \ | 8 | .max_fds = NR_OPEN_DEFAULT, \ |
| 11 | .max_fdset = __FD_SETSIZE, \ | 9 | .max_fdset = __FD_SETSIZE, \ |
| 12 | .next_fd = 0, \ | 10 | .next_fd = 0, \ |
| 13 | .fd = &init_files.fd_array[0], \ | 11 | .fd = &init_files.fd_array[0], \ |
| 14 | .close_on_exec = &init_files.close_on_exec_init, \ | 12 | .close_on_exec = &init_files.close_on_exec_init, \ |
| 15 | .open_fds = &init_files.open_fds_init, \ | 13 | .open_fds = &init_files.open_fds_init, \ |
| 14 | } | ||
| 15 | |||
| 16 | #define INIT_FILES \ | ||
| 17 | { \ | ||
| 18 | .count = ATOMIC_INIT(1), \ | ||
| 19 | .file_lock = SPIN_LOCK_UNLOCKED, \ | ||
| 20 | .fdtab = INIT_FDTABLE, \ | ||
| 16 | .close_on_exec_init = { { 0, } }, \ | 21 | .close_on_exec_init = { { 0, } }, \ |
| 17 | .open_fds_init = { { 0, } }, \ | 22 | .open_fds_init = { { 0, } }, \ |
| 18 | .fd_array = { NULL, } \ | 23 | .fd_array = { NULL, } \ |
diff --git a/kernel/exit.c b/kernel/exit.c index 5b0fb9f09f21..83beb1e93b18 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -368,17 +368,19 @@ EXPORT_SYMBOL(daemonize); | |||
| 368 | static inline void close_files(struct files_struct * files) | 368 | static inline void close_files(struct files_struct * files) |
| 369 | { | 369 | { |
| 370 | int i, j; | 370 | int i, j; |
| 371 | struct fdtable *fdt; | ||
| 371 | 372 | ||
| 372 | j = 0; | 373 | j = 0; |
| 374 | fdt = files_fdtable(files); | ||
| 373 | for (;;) { | 375 | for (;;) { |
| 374 | unsigned long set; | 376 | unsigned long set; |
| 375 | i = j * __NFDBITS; | 377 | i = j * __NFDBITS; |
| 376 | if (i >= files->max_fdset || i >= files->max_fds) | 378 | if (i >= fdt->max_fdset || i >= fdt->max_fds) |
| 377 | break; | 379 | break; |
| 378 | set = files->open_fds->fds_bits[j++]; | 380 | set = fdt->open_fds->fds_bits[j++]; |
| 379 | while (set) { | 381 | while (set) { |
| 380 | if (set & 1) { | 382 | if (set & 1) { |
| 381 | struct file * file = xchg(&files->fd[i], NULL); | 383 | struct file * file = xchg(&fdt->fd[i], NULL); |
| 382 | if (file) | 384 | if (file) |
| 383 | filp_close(file, files); | 385 | filp_close(file, files); |
| 384 | } | 386 | } |
| @@ -403,16 +405,19 @@ struct files_struct *get_files_struct(struct task_struct *task) | |||
| 403 | 405 | ||
| 404 | void fastcall put_files_struct(struct files_struct *files) | 406 | void fastcall put_files_struct(struct files_struct *files) |
| 405 | { | 407 | { |
| 408 | struct fdtable *fdt; | ||
| 409 | |||
| 406 | if (atomic_dec_and_test(&files->count)) { | 410 | if (atomic_dec_and_test(&files->count)) { |
| 407 | close_files(files); | 411 | close_files(files); |
| 408 | /* | 412 | /* |
| 409 | * Free the fd and fdset arrays if we expanded them. | 413 | * Free the fd and fdset arrays if we expanded them. |
| 410 | */ | 414 | */ |
| 411 | if (files->fd != &files->fd_array[0]) | 415 | fdt = files_fdtable(files); |
| 412 | free_fd_array(files->fd, files->max_fds); | 416 | if (fdt->fd != &files->fd_array[0]) |
| 413 | if (files->max_fdset > __FD_SETSIZE) { | 417 | free_fd_array(fdt->fd, fdt->max_fds); |
| 414 | free_fdset(files->open_fds, files->max_fdset); | 418 | if (fdt->max_fdset > __FD_SETSIZE) { |
| 415 | free_fdset(files->close_on_exec, files->max_fdset); | 419 | free_fdset(fdt->open_fds, fdt->max_fdset); |
| 420 | free_fdset(fdt->close_on_exec, fdt->max_fdset); | ||
| 416 | } | 421 | } |
| 417 | kmem_cache_free(files_cachep, files); | 422 | kmem_cache_free(files_cachep, files); |
| 418 | } | 423 | } |
diff --git a/kernel/fork.c b/kernel/fork.c index b25802065031..ecc694debb50 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -568,21 +568,47 @@ static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk) | |||
| 568 | static int count_open_files(struct files_struct *files, int size) | 568 | static int count_open_files(struct files_struct *files, int size) |
| 569 | { | 569 | { |
| 570 | int i; | 570 | int i; |
| 571 | struct fdtable *fdt; | ||
| 571 | 572 | ||
| 572 | /* Find the last open fd */ | 573 | /* Find the last open fd */ |
| 574 | fdt = files_fdtable(files); | ||
| 573 | for (i = size/(8*sizeof(long)); i > 0; ) { | 575 | for (i = size/(8*sizeof(long)); i > 0; ) { |
| 574 | if (files->open_fds->fds_bits[--i]) | 576 | if (fdt->open_fds->fds_bits[--i]) |
| 575 | break; | 577 | break; |
| 576 | } | 578 | } |
| 577 | i = (i+1) * 8 * sizeof(long); | 579 | i = (i+1) * 8 * sizeof(long); |
| 578 | return i; | 580 | return i; |
| 579 | } | 581 | } |
| 580 | 582 | ||
| 583 | static struct files_struct *alloc_files(void) | ||
| 584 | { | ||
| 585 | struct files_struct *newf; | ||
| 586 | struct fdtable *fdt; | ||
| 587 | |||
| 588 | newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); | ||
| 589 | if (!newf) | ||
| 590 | goto out; | ||
| 591 | |||
| 592 | atomic_set(&newf->count, 1); | ||
| 593 | |||
| 594 | spin_lock_init(&newf->file_lock); | ||
| 595 | fdt = files_fdtable(newf); | ||
| 596 | fdt->next_fd = 0; | ||
| 597 | fdt->max_fds = NR_OPEN_DEFAULT; | ||
| 598 | fdt->max_fdset = __FD_SETSIZE; | ||
| 599 | fdt->close_on_exec = &newf->close_on_exec_init; | ||
| 600 | fdt->open_fds = &newf->open_fds_init; | ||
| 601 | fdt->fd = &newf->fd_array[0]; | ||
| 602 | out: | ||
| 603 | return newf; | ||
| 604 | } | ||
| 605 | |||
| 581 | static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | 606 | static int copy_files(unsigned long clone_flags, struct task_struct * tsk) |
| 582 | { | 607 | { |
| 583 | struct files_struct *oldf, *newf; | 608 | struct files_struct *oldf, *newf; |
| 584 | struct file **old_fds, **new_fds; | 609 | struct file **old_fds, **new_fds; |
| 585 | int open_files, size, i, error = 0, expand; | 610 | int open_files, size, i, error = 0, expand; |
| 611 | struct fdtable *old_fdt, *new_fdt; | ||
| 586 | 612 | ||
| 587 | /* | 613 | /* |
| 588 | * A background process may not have any files ... | 614 | * A background process may not have any files ... |
| @@ -603,35 +629,27 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | |||
| 603 | */ | 629 | */ |
| 604 | tsk->files = NULL; | 630 | tsk->files = NULL; |
| 605 | error = -ENOMEM; | 631 | error = -ENOMEM; |
| 606 | newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); | 632 | newf = alloc_files(); |
| 607 | if (!newf) | 633 | if (!newf) |
| 608 | goto out; | 634 | goto out; |
| 609 | 635 | ||
| 610 | atomic_set(&newf->count, 1); | ||
| 611 | |||
| 612 | spin_lock_init(&newf->file_lock); | ||
| 613 | newf->next_fd = 0; | ||
| 614 | newf->max_fds = NR_OPEN_DEFAULT; | ||
| 615 | newf->max_fdset = __FD_SETSIZE; | ||
| 616 | newf->close_on_exec = &newf->close_on_exec_init; | ||
| 617 | newf->open_fds = &newf->open_fds_init; | ||
| 618 | newf->fd = &newf->fd_array[0]; | ||
| 619 | |||
| 620 | spin_lock(&oldf->file_lock); | 636 | spin_lock(&oldf->file_lock); |
| 621 | 637 | old_fdt = files_fdtable(oldf); | |
| 622 | open_files = count_open_files(oldf, oldf->max_fdset); | 638 | new_fdt = files_fdtable(newf); |
| 639 | size = old_fdt->max_fdset; | ||
| 640 | open_files = count_open_files(oldf, old_fdt->max_fdset); | ||
| 623 | expand = 0; | 641 | expand = 0; |
| 624 | 642 | ||
| 625 | /* | 643 | /* |
| 626 | * Check whether we need to allocate a larger fd array or fd set. | 644 | * Check whether we need to allocate a larger fd array or fd set. |
| 627 | * Note: we're not a clone task, so the open count won't change. | 645 | * Note: we're not a clone task, so the open count won't change. |
| 628 | */ | 646 | */ |
| 629 | if (open_files > newf->max_fdset) { | 647 | if (open_files > new_fdt->max_fdset) { |
| 630 | newf->max_fdset = 0; | 648 | new_fdt->max_fdset = 0; |
| 631 | expand = 1; | 649 | expand = 1; |
| 632 | } | 650 | } |
| 633 | if (open_files > newf->max_fds) { | 651 | if (open_files > new_fdt->max_fds) { |
| 634 | newf->max_fds = 0; | 652 | new_fdt->max_fds = 0; |
| 635 | expand = 1; | 653 | expand = 1; |
| 636 | } | 654 | } |
| 637 | 655 | ||
| @@ -646,11 +664,11 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | |||
| 646 | spin_lock(&oldf->file_lock); | 664 | spin_lock(&oldf->file_lock); |
| 647 | } | 665 | } |
| 648 | 666 | ||
| 649 | old_fds = oldf->fd; | 667 | old_fds = old_fdt->fd; |
| 650 | new_fds = newf->fd; | 668 | new_fds = new_fdt->fd; |
| 651 | 669 | ||
| 652 | memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, open_files/8); | 670 | memcpy(new_fdt->open_fds->fds_bits, old_fdt->open_fds->fds_bits, open_files/8); |
| 653 | memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, open_files/8); | 671 | memcpy(new_fdt->close_on_exec->fds_bits, old_fdt->close_on_exec->fds_bits, open_files/8); |
| 654 | 672 | ||
| 655 | for (i = open_files; i != 0; i--) { | 673 | for (i = open_files; i != 0; i--) { |
| 656 | struct file *f = *old_fds++; | 674 | struct file *f = *old_fds++; |
| @@ -663,24 +681,24 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) | |||
| 663 | * is partway through open(). So make sure that this | 681 | * is partway through open(). So make sure that this |
| 664 | * fd is available to the new process. | 682 | * fd is available to the new process. |
| 665 | */ | 683 | */ |
| 666 | FD_CLR(open_files - i, newf->open_fds); | 684 | FD_CLR(open_files - i, new_fdt->open_fds); |
| 667 | } | 685 | } |
| 668 | *new_fds++ = f; | 686 | *new_fds++ = f; |
| 669 | } | 687 | } |
| 670 | spin_unlock(&oldf->file_lock); | 688 | spin_unlock(&oldf->file_lock); |
| 671 | 689 | ||
| 672 | /* compute the remainder to be cleared */ | 690 | /* compute the remainder to be cleared */ |
| 673 | size = (newf->max_fds - open_files) * sizeof(struct file *); | 691 | size = (new_fdt->max_fds - open_files) * sizeof(struct file *); |
| 674 | 692 | ||
| 675 | /* This is long word aligned thus could use a optimized version */ | 693 | /* This is long word aligned thus could use a optimized version */ |
| 676 | memset(new_fds, 0, size); | 694 | memset(new_fds, 0, size); |
| 677 | 695 | ||
| 678 | if (newf->max_fdset > open_files) { | 696 | if (new_fdt->max_fdset > open_files) { |
| 679 | int left = (newf->max_fdset-open_files)/8; | 697 | int left = (new_fdt->max_fdset-open_files)/8; |
| 680 | int start = open_files / (8 * sizeof(unsigned long)); | 698 | int start = open_files / (8 * sizeof(unsigned long)); |
| 681 | 699 | ||
| 682 | memset(&newf->open_fds->fds_bits[start], 0, left); | 700 | memset(&new_fdt->open_fds->fds_bits[start], 0, left); |
| 683 | memset(&newf->close_on_exec->fds_bits[start], 0, left); | 701 | memset(&new_fdt->close_on_exec->fds_bits[start], 0, left); |
| 684 | } | 702 | } |
| 685 | 703 | ||
| 686 | tsk->files = newf; | 704 | tsk->files = newf; |
| @@ -689,9 +707,9 @@ out: | |||
| 689 | return error; | 707 | return error; |
| 690 | 708 | ||
| 691 | out_release: | 709 | out_release: |
| 692 | free_fdset (newf->close_on_exec, newf->max_fdset); | 710 | free_fdset (new_fdt->close_on_exec, new_fdt->max_fdset); |
| 693 | free_fdset (newf->open_fds, newf->max_fdset); | 711 | free_fdset (new_fdt->open_fds, new_fdt->max_fdset); |
| 694 | free_fd_array(newf->fd, newf->max_fds); | 712 | free_fd_array(new_fdt->fd, new_fdt->max_fds); |
| 695 | kmem_cache_free(files_cachep, newf); | 713 | kmem_cache_free(files_cachep, newf); |
| 696 | goto out; | 714 | goto out; |
| 697 | } | 715 | } |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3f0b533be92c..acb5a495a902 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -1594,6 +1594,7 @@ static inline void flush_unauthorized_files(struct files_struct * files) | |||
| 1594 | struct avc_audit_data ad; | 1594 | struct avc_audit_data ad; |
| 1595 | struct file *file, *devnull = NULL; | 1595 | struct file *file, *devnull = NULL; |
| 1596 | struct tty_struct *tty = current->signal->tty; | 1596 | struct tty_struct *tty = current->signal->tty; |
| 1597 | struct fdtable *fdt; | ||
| 1597 | long j = -1; | 1598 | long j = -1; |
| 1598 | 1599 | ||
| 1599 | if (tty) { | 1600 | if (tty) { |
| @@ -1627,9 +1628,10 @@ static inline void flush_unauthorized_files(struct files_struct * files) | |||
| 1627 | 1628 | ||
| 1628 | j++; | 1629 | j++; |
| 1629 | i = j * __NFDBITS; | 1630 | i = j * __NFDBITS; |
| 1630 | if (i >= files->max_fds || i >= files->max_fdset) | 1631 | fdt = files_fdtable(files); |
| 1632 | if (i >= fdt->max_fds || i >= fdt->max_fdset) | ||
| 1631 | break; | 1633 | break; |
| 1632 | set = files->open_fds->fds_bits[j]; | 1634 | set = fdt->open_fds->fds_bits[j]; |
| 1633 | if (!set) | 1635 | if (!set) |
| 1634 | continue; | 1636 | continue; |
| 1635 | spin_unlock(&files->file_lock); | 1637 | spin_unlock(&files->file_lock); |
