aboutsummaryrefslogtreecommitdiffstats
path: root/fs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/file.c')
-rw-r--r--fs/file.c76
1 files changed, 35 insertions, 41 deletions
diff --git a/fs/file.c b/fs/file.c
index 8d3bfca7714b..2a991ac8e562 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -288,71 +288,65 @@ out:
288} 288}
289 289
290/* 290/*
291 * Expands the file descriptor table - it will allocate a new fdtable and 291 * Expand the file descriptor table.
292 * 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
293 * 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.
294 */ 296 */
295static int expand_fdtable(struct files_struct *files, int nr) 297static int expand_fdtable(struct files_struct *files, int nr)
296 __releases(files->file_lock) 298 __releases(files->file_lock)
297 __acquires(files->file_lock) 299 __acquires(files->file_lock)
298{ 300{
299 int error = 0; 301 struct fdtable *new_fdt, *cur_fdt;
300 struct fdtable *fdt;
301 struct fdtable *nfdt = NULL;
302 302
303 spin_unlock(&files->file_lock); 303 spin_unlock(&files->file_lock);
304 nfdt = alloc_fdtable(nr); 304 new_fdt = alloc_fdtable(nr);
305 if (!nfdt) {
306 error = -ENOMEM;
307 spin_lock(&files->file_lock);
308 goto out;
309 }
310
311 spin_lock(&files->file_lock); 305 spin_lock(&files->file_lock);
312 fdt = files_fdtable(files); 306 if (!new_fdt)
307 return -ENOMEM;
313 /* 308 /*
314 * Check again since another task may have expanded the 309 * Check again since another task may have expanded the fd table while
315 * fd table while we dropped the lock 310 * we dropped the lock
316 */ 311 */
317 if (nr >= fdt->max_fds || nr >= fdt->max_fdset) { 312 cur_fdt = files_fdtable(files);
318 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);
319 } else { 318 } else {
320 /* Somebody expanded while we dropped file_lock */ 319 /* Somebody else expanded, so undo our attempt */
321 spin_unlock(&files->file_lock); 320 spin_unlock(&files->file_lock);
322 __free_fdtable(nfdt); 321 __free_fdtable(new_fdt);
323 spin_lock(&files->file_lock); 322 spin_lock(&files->file_lock);
324 goto out;
325 } 323 }
326 rcu_assign_pointer(files->fdt, nfdt); 324 return 1;
327 free_fdtable(fdt);
328out:
329 return error;
330} 325}
331 326
332/* 327/*
333 * Expand files. 328 * Expand files.
334 * Return <0 on error; 0 nothing done; 1 files expanded, we may have blocked. 329 * This function will expand the file structures, if the requested size exceeds
335 * Should be called with the files->file_lock spinlock held for write. 330 * the current capacity and there is room for expansion.
331 * Return <0 error code on error; 0 when nothing done; 1 when files were
332 * expanded and execution may have blocked.
333 * The files->file_lock should be held on entry, and will be held on exit.
336 */ 334 */
337int expand_files(struct files_struct *files, int nr) 335int expand_files(struct files_struct *files, int nr)
338{ 336{
339 int err, expand = 0;
340 struct fdtable *fdt; 337 struct fdtable *fdt;
341 338
342 fdt = files_fdtable(files); 339 fdt = files_fdtable(files);
343 if (nr >= fdt->max_fdset || nr >= fdt->max_fds) { 340 /* Do we need to expand? */
344 if (fdt->max_fdset >= NR_OPEN || 341 if (nr < fdt->max_fdset && nr < fdt->max_fds)
345 fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) { 342 return 0;
346 err = -EMFILE; 343 /* Can we expand? */
347 goto out; 344 if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN ||
348 } 345 nr >= NR_OPEN)
349 expand = 1; 346 return -EMFILE;
350 if ((err = expand_fdtable(files, nr))) 347
351 goto out; 348 /* All good, so we try */
352 } 349 return expand_fdtable(files, nr);
353 err = expand;
354out:
355 return err;
356} 350}
357 351
358static void __devinit fdtable_defer_list_init(int cpu) 352static void __devinit fdtable_defer_list_init(int cpu)