diff options
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 47 |
1 files changed, 29 insertions, 18 deletions
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) |