diff options
Diffstat (limited to 'fs/file.c')
-rw-r--r-- | fs/file.c | 56 |
1 files changed, 22 insertions, 34 deletions
@@ -68,8 +68,8 @@ void free_fd_array(struct file **array, int num) | |||
68 | 68 | ||
69 | static void __free_fdtable(struct fdtable *fdt) | 69 | static void __free_fdtable(struct fdtable *fdt) |
70 | { | 70 | { |
71 | free_fdset(fdt->open_fds, fdt->max_fdset); | 71 | free_fdset(fdt->open_fds, fdt->max_fds); |
72 | free_fdset(fdt->close_on_exec, fdt->max_fdset); | 72 | free_fdset(fdt->close_on_exec, fdt->max_fds); |
73 | free_fd_array(fdt->fd, fdt->max_fds); | 73 | free_fd_array(fdt->fd, fdt->max_fds); |
74 | kfree(fdt); | 74 | kfree(fdt); |
75 | } | 75 | } |
@@ -98,7 +98,7 @@ static void free_fdtable_rcu(struct rcu_head *rcu) | |||
98 | struct fdtable_defer *fddef; | 98 | struct fdtable_defer *fddef; |
99 | 99 | ||
100 | BUG_ON(!fdt); | 100 | BUG_ON(!fdt); |
101 | fdset_size = fdt->max_fdset / 8; | 101 | fdset_size = fdt->max_fds / 8; |
102 | fdarray_size = fdt->max_fds * sizeof(struct file *); | 102 | fdarray_size = fdt->max_fds * sizeof(struct file *); |
103 | 103 | ||
104 | if (fdt->free_files) { | 104 | if (fdt->free_files) { |
@@ -110,13 +110,11 @@ static void free_fdtable_rcu(struct rcu_head *rcu) | |||
110 | kmem_cache_free(files_cachep, fdt->free_files); | 110 | kmem_cache_free(files_cachep, fdt->free_files); |
111 | return; | 111 | return; |
112 | } | 112 | } |
113 | if (fdt->max_fdset <= EMBEDDED_FD_SET_SIZE && | 113 | if (fdt->max_fds <= NR_OPEN_DEFAULT) |
114 | fdt->max_fds <= NR_OPEN_DEFAULT) { | ||
115 | /* | 114 | /* |
116 | * The fdtable was embedded | 115 | * The fdtable was embedded |
117 | */ | 116 | */ |
118 | return; | 117 | return; |
119 | } | ||
120 | if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) { | 118 | if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) { |
121 | kfree(fdt->open_fds); | 119 | kfree(fdt->open_fds); |
122 | kfree(fdt->close_on_exec); | 120 | kfree(fdt->close_on_exec); |
@@ -136,9 +134,7 @@ static void free_fdtable_rcu(struct rcu_head *rcu) | |||
136 | 134 | ||
137 | void free_fdtable(struct fdtable *fdt) | 135 | void free_fdtable(struct fdtable *fdt) |
138 | { | 136 | { |
139 | if (fdt->free_files || | 137 | if (fdt->free_files || fdt->max_fds > NR_OPEN_DEFAULT) |
140 | fdt->max_fdset > EMBEDDED_FD_SET_SIZE || | ||
141 | fdt->max_fds > NR_OPEN_DEFAULT) | ||
142 | call_rcu(&fdt->rcu, free_fdtable_rcu); | 138 | call_rcu(&fdt->rcu, free_fdtable_rcu); |
143 | } | 139 | } |
144 | 140 | ||
@@ -151,12 +147,11 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt) | |||
151 | int i; | 147 | int i; |
152 | int count; | 148 | int count; |
153 | 149 | ||
154 | BUG_ON(nfdt->max_fdset < fdt->max_fdset); | ||
155 | BUG_ON(nfdt->max_fds < fdt->max_fds); | 150 | BUG_ON(nfdt->max_fds < fdt->max_fds); |
156 | /* Copy the existing tables and install the new pointers */ | 151 | /* Copy the existing tables and install the new pointers */ |
157 | 152 | ||
158 | i = fdt->max_fdset / (sizeof(unsigned long) * 8); | 153 | i = fdt->max_fds / (sizeof(unsigned long) * 8); |
159 | count = (nfdt->max_fdset - fdt->max_fdset) / 8; | 154 | count = (nfdt->max_fds - fdt->max_fds) / 8; |
160 | 155 | ||
161 | /* | 156 | /* |
162 | * Don't copy the entire array if the current fdset is | 157 | * Don't copy the entire array if the current fdset is |
@@ -164,9 +159,9 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt) | |||
164 | */ | 159 | */ |
165 | if (i) { | 160 | if (i) { |
166 | memcpy (nfdt->open_fds, fdt->open_fds, | 161 | memcpy (nfdt->open_fds, fdt->open_fds, |
167 | fdt->max_fdset/8); | 162 | fdt->max_fds/8); |
168 | memcpy (nfdt->close_on_exec, fdt->close_on_exec, | 163 | memcpy (nfdt->close_on_exec, fdt->close_on_exec, |
169 | fdt->max_fdset/8); | 164 | fdt->max_fds/8); |
170 | memset (&nfdt->open_fds->fds_bits[i], 0, count); | 165 | memset (&nfdt->open_fds->fds_bits[i], 0, count); |
171 | memset (&nfdt->close_on_exec->fds_bits[i], 0, count); | 166 | memset (&nfdt->close_on_exec->fds_bits[i], 0, count); |
172 | } | 167 | } |
@@ -201,7 +196,7 @@ fd_set * alloc_fdset(int num) | |||
201 | 196 | ||
202 | void free_fdset(fd_set *array, int num) | 197 | void free_fdset(fd_set *array, int num) |
203 | { | 198 | { |
204 | if (num <= EMBEDDED_FD_SET_SIZE) /* Don't free an embedded fdset */ | 199 | if (num <= NR_OPEN_DEFAULT) /* Don't free an embedded fdset */ |
205 | return; | 200 | return; |
206 | else if (num <= 8 * PAGE_SIZE) | 201 | else if (num <= 8 * PAGE_SIZE) |
207 | kfree(array); | 202 | kfree(array); |
@@ -220,18 +215,6 @@ static struct fdtable *alloc_fdtable(int nr) | |||
220 | if (!fdt) | 215 | if (!fdt) |
221 | goto out; | 216 | goto out; |
222 | 217 | ||
223 | nfds = max_t(int, 8 * L1_CACHE_BYTES, roundup_pow_of_two(nr + 1)); | ||
224 | if (nfds > NR_OPEN) | ||
225 | nfds = NR_OPEN; | ||
226 | |||
227 | new_openset = alloc_fdset(nfds); | ||
228 | new_execset = alloc_fdset(nfds); | ||
229 | if (!new_openset || !new_execset) | ||
230 | goto out; | ||
231 | fdt->open_fds = new_openset; | ||
232 | fdt->close_on_exec = new_execset; | ||
233 | fdt->max_fdset = nfds; | ||
234 | |||
235 | nfds = NR_OPEN_DEFAULT; | 218 | nfds = NR_OPEN_DEFAULT; |
236 | /* | 219 | /* |
237 | * Expand to the max in easy steps, and keep expanding it until | 220 | * Expand to the max in easy steps, and keep expanding it until |
@@ -251,15 +234,21 @@ static struct fdtable *alloc_fdtable(int nr) | |||
251 | nfds = NR_OPEN; | 234 | nfds = NR_OPEN; |
252 | } | 235 | } |
253 | } while (nfds <= nr); | 236 | } while (nfds <= nr); |
237 | |||
238 | new_openset = alloc_fdset(nfds); | ||
239 | new_execset = alloc_fdset(nfds); | ||
240 | if (!new_openset || !new_execset) | ||
241 | goto out; | ||
242 | fdt->open_fds = new_openset; | ||
243 | fdt->close_on_exec = new_execset; | ||
244 | |||
254 | new_fds = alloc_fd_array(nfds); | 245 | new_fds = alloc_fd_array(nfds); |
255 | if (!new_fds) | 246 | if (!new_fds) |
256 | goto out2; | 247 | goto out; |
257 | fdt->fd = new_fds; | 248 | fdt->fd = new_fds; |
258 | fdt->max_fds = nfds; | 249 | fdt->max_fds = nfds; |
259 | fdt->free_files = NULL; | 250 | fdt->free_files = NULL; |
260 | return fdt; | 251 | return fdt; |
261 | out2: | ||
262 | nfds = fdt->max_fdset; | ||
263 | out: | 252 | out: |
264 | free_fdset(new_openset, nfds); | 253 | free_fdset(new_openset, nfds); |
265 | free_fdset(new_execset, nfds); | 254 | free_fdset(new_execset, nfds); |
@@ -290,7 +279,7 @@ static int expand_fdtable(struct files_struct *files, int nr) | |||
290 | * we dropped the lock | 279 | * we dropped the lock |
291 | */ | 280 | */ |
292 | cur_fdt = files_fdtable(files); | 281 | cur_fdt = files_fdtable(files); |
293 | if (nr >= cur_fdt->max_fds || nr >= cur_fdt->max_fdset) { | 282 | if (nr >= cur_fdt->max_fds) { |
294 | /* Continue as planned */ | 283 | /* Continue as planned */ |
295 | copy_fdtable(new_fdt, cur_fdt); | 284 | copy_fdtable(new_fdt, cur_fdt); |
296 | rcu_assign_pointer(files->fdt, new_fdt); | 285 | rcu_assign_pointer(files->fdt, new_fdt); |
@@ -316,11 +305,10 @@ int expand_files(struct files_struct *files, int nr) | |||
316 | 305 | ||
317 | fdt = files_fdtable(files); | 306 | fdt = files_fdtable(files); |
318 | /* Do we need to expand? */ | 307 | /* Do we need to expand? */ |
319 | if (nr < fdt->max_fdset && nr < fdt->max_fds) | 308 | if (nr < fdt->max_fds) |
320 | return 0; | 309 | return 0; |
321 | /* Can we expand? */ | 310 | /* Can we expand? */ |
322 | if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN || | 311 | if (nr >= NR_OPEN) |
323 | nr >= NR_OPEN) | ||
324 | return -EMFILE; | 312 | return -EMFILE; |
325 | 313 | ||
326 | /* All good, so we try */ | 314 | /* All good, so we try */ |