aboutsummaryrefslogtreecommitdiffstats
path: root/fs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/file.c')
-rw-r--r--fs/file.c98
1 files changed, 43 insertions, 55 deletions
diff --git a/fs/file.c b/fs/file.c
index 55f4e7022563..8e81775c5dc8 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -240,13 +240,9 @@ static struct fdtable *alloc_fdtable(int nr)
240 if (!fdt) 240 if (!fdt)
241 goto out; 241 goto out;
242 242
243 nfds = 8 * L1_CACHE_BYTES; 243 nfds = max_t(int, 8 * L1_CACHE_BYTES, roundup_pow_of_two(nr + 1));
244 /* Expand to the max in easy steps */ 244 if (nfds > NR_OPEN)
245 while (nfds <= nr) { 245 nfds = NR_OPEN;
246 nfds = nfds * 2;
247 if (nfds > NR_OPEN)
248 nfds = NR_OPEN;
249 }
250 246
251 new_openset = alloc_fdset(nfds); 247 new_openset = alloc_fdset(nfds);
252 new_execset = alloc_fdset(nfds); 248 new_execset = alloc_fdset(nfds);
@@ -277,86 +273,78 @@ static struct fdtable *alloc_fdtable(int nr)
277 } while (nfds <= nr); 273 } while (nfds <= nr);
278 new_fds = alloc_fd_array(nfds); 274 new_fds = alloc_fd_array(nfds);
279 if (!new_fds) 275 if (!new_fds)
280 goto out; 276 goto out2;
281 fdt->fd = new_fds; 277 fdt->fd = new_fds;
282 fdt->max_fds = nfds; 278 fdt->max_fds = nfds;
283 fdt->free_files = NULL; 279 fdt->free_files = NULL;
284 return fdt; 280 return fdt;
281out2:
282 nfds = fdt->max_fdset;
285out: 283out:
286 if (new_openset) 284 free_fdset(new_openset, nfds);
287 free_fdset(new_openset, nfds); 285 free_fdset(new_execset, nfds);
288 if (new_execset)
289 free_fdset(new_execset, nfds);
290 kfree(fdt); 286 kfree(fdt);
291 return NULL; 287 return NULL;
292} 288}
293 289
294/* 290/*
295 * Expands the file descriptor table - it will allocate a new fdtable and 291 * Expand the file descriptor table.
296 * both fd array and fdset. It is expected to be called with the 292 * This function will allocate a new fdtable and both fd array and fdset, of
297 * files_lock held. 293 * the given size.
294 * Return <0 error code on error; 1 on successful completion.
295 * The files->file_lock should be held on entry, and will be held on exit.
298 */ 296 */
299static int expand_fdtable(struct files_struct *files, int nr) 297static int expand_fdtable(struct files_struct *files, int nr)
300 __releases(files->file_lock) 298 __releases(files->file_lock)
301 __acquires(files->file_lock) 299 __acquires(files->file_lock)
302{ 300{
303 int error = 0; 301 struct fdtable *new_fdt, *cur_fdt;
304 struct fdtable *fdt;
305 struct fdtable *nfdt = NULL;
306 302
307 spin_unlock(&files->file_lock); 303 spin_unlock(&files->file_lock);
308 nfdt = alloc_fdtable(nr); 304 new_fdt = alloc_fdtable(nr);
309 if (!nfdt) {
310 error = -ENOMEM;
311 spin_lock(&files->file_lock);
312 goto out;
313 }
314
315 spin_lock(&files->file_lock); 305 spin_lock(&files->file_lock);
316 fdt = files_fdtable(files); 306 if (!new_fdt)
307 return -ENOMEM;
317 /* 308 /*
318 * Check again since another task may have expanded the 309 * Check again since another task may have expanded the fd table while
319 * fd table while we dropped the lock 310 * we dropped the lock
320 */ 311 */
321 if (nr >= fdt->max_fds || nr >= fdt->max_fdset) { 312 cur_fdt = files_fdtable(files);
322 copy_fdtable(nfdt, fdt); 313 if (nr >= cur_fdt->max_fds || nr >= cur_fdt->max_fdset) {
314 /* Continue as planned */
315 copy_fdtable(new_fdt, cur_fdt);
316 rcu_assign_pointer(files->fdt, new_fdt);
317 free_fdtable(cur_fdt);
323 } else { 318 } else {
324 /* Somebody expanded while we dropped file_lock */ 319 /* Somebody else expanded, so undo our attempt */
325 spin_unlock(&files->file_lock); 320 __free_fdtable(new_fdt);
326 __free_fdtable(nfdt);
327 spin_lock(&files->file_lock);
328 goto out;
329 } 321 }
330 rcu_assign_pointer(files->fdt, nfdt); 322 return 1;
331 free_fdtable(fdt);
332out:
333 return error;
334} 323}
335 324
336/* 325/*
337 * Expand files. 326 * Expand files.
338 * Return <0 on error; 0 nothing done; 1 files expanded, we may have blocked. 327 * This function will expand the file structures, if the requested size exceeds
339 * Should be called with the files->file_lock spinlock held for write. 328 * the current capacity and there is room for expansion.
329 * Return <0 error code on error; 0 when nothing done; 1 when files were
330 * expanded and execution may have blocked.
331 * The files->file_lock should be held on entry, and will be held on exit.
340 */ 332 */
341int expand_files(struct files_struct *files, int nr) 333int expand_files(struct files_struct *files, int nr)
342{ 334{
343 int err, expand = 0;
344 struct fdtable *fdt; 335 struct fdtable *fdt;
345 336
346 fdt = files_fdtable(files); 337 fdt = files_fdtable(files);
347 if (nr >= fdt->max_fdset || nr >= fdt->max_fds) { 338 /* Do we need to expand? */
348 if (fdt->max_fdset >= NR_OPEN || 339 if (nr < fdt->max_fdset && nr < fdt->max_fds)
349 fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) { 340 return 0;
350 err = -EMFILE; 341 /* Can we expand? */
351 goto out; 342 if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN ||
352 } 343 nr >= NR_OPEN)
353 expand = 1; 344 return -EMFILE;
354 if ((err = expand_fdtable(files, nr))) 345
355 goto out; 346 /* All good, so we try */
356 } 347 return expand_fdtable(files, nr);
357 err = expand;
358out:
359 return err;
360} 348}
361 349
362static void __devinit fdtable_defer_list_init(int cpu) 350static void __devinit fdtable_defer_list_init(int cpu)