diff options
Diffstat (limited to 'fs/file.c')
| -rw-r--r-- | fs/file.c | 70 |
1 files changed, 70 insertions, 0 deletions
| @@ -6,6 +6,7 @@ | |||
| 6 | * Manage the dynamic fd arrays in the process files_struct. | 6 | * Manage the dynamic fd arrays in the process files_struct. |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/module.h> | ||
| 9 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
| 10 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
| 11 | #include <linux/time.h> | 12 | #include <linux/time.h> |
| @@ -250,9 +251,18 @@ int expand_files(struct files_struct *files, int nr) | |||
| 250 | struct fdtable *fdt; | 251 | struct fdtable *fdt; |
| 251 | 252 | ||
| 252 | fdt = files_fdtable(files); | 253 | fdt = files_fdtable(files); |
| 254 | |||
| 255 | /* | ||
| 256 | * N.B. For clone tasks sharing a files structure, this test | ||
| 257 | * will limit the total number of files that can be opened. | ||
| 258 | */ | ||
| 259 | if (nr >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | ||
| 260 | return -EMFILE; | ||
| 261 | |||
| 253 | /* Do we need to expand? */ | 262 | /* Do we need to expand? */ |
| 254 | if (nr < fdt->max_fds) | 263 | if (nr < fdt->max_fds) |
| 255 | return 0; | 264 | return 0; |
| 265 | |||
| 256 | /* Can we expand? */ | 266 | /* Can we expand? */ |
| 257 | if (nr >= sysctl_nr_open) | 267 | if (nr >= sysctl_nr_open) |
| 258 | return -EMFILE; | 268 | return -EMFILE; |
| @@ -423,3 +433,63 @@ struct files_struct init_files = { | |||
| 423 | }, | 433 | }, |
| 424 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), | 434 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), |
| 425 | }; | 435 | }; |
| 436 | |||
| 437 | /* | ||
| 438 | * allocate a file descriptor, mark it busy. | ||
| 439 | */ | ||
| 440 | int alloc_fd(unsigned start, unsigned flags) | ||
| 441 | { | ||
| 442 | struct files_struct *files = current->files; | ||
| 443 | unsigned int fd; | ||
| 444 | int error; | ||
| 445 | struct fdtable *fdt; | ||
| 446 | |||
| 447 | spin_lock(&files->file_lock); | ||
| 448 | repeat: | ||
| 449 | fdt = files_fdtable(files); | ||
| 450 | fd = start; | ||
| 451 | if (fd < files->next_fd) | ||
| 452 | fd = files->next_fd; | ||
| 453 | |||
| 454 | if (fd < fdt->max_fds) | ||
| 455 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, | ||
| 456 | fdt->max_fds, fd); | ||
| 457 | |||
| 458 | error = expand_files(files, fd); | ||
| 459 | if (error < 0) | ||
| 460 | goto out; | ||
| 461 | |||
| 462 | /* | ||
| 463 | * If we needed to expand the fs array we | ||
| 464 | * might have blocked - try again. | ||
| 465 | */ | ||
| 466 | if (error) | ||
| 467 | goto repeat; | ||
| 468 | |||
| 469 | if (start <= files->next_fd) | ||
| 470 | files->next_fd = fd + 1; | ||
| 471 | |||
| 472 | FD_SET(fd, fdt->open_fds); | ||
| 473 | if (flags & O_CLOEXEC) | ||
| 474 | FD_SET(fd, fdt->close_on_exec); | ||
| 475 | else | ||
| 476 | FD_CLR(fd, fdt->close_on_exec); | ||
| 477 | error = fd; | ||
| 478 | #if 1 | ||
| 479 | /* Sanity check */ | ||
| 480 | if (rcu_dereference(fdt->fd[fd]) != NULL) { | ||
| 481 | printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd); | ||
| 482 | rcu_assign_pointer(fdt->fd[fd], NULL); | ||
| 483 | } | ||
| 484 | #endif | ||
| 485 | |||
| 486 | out: | ||
| 487 | spin_unlock(&files->file_lock); | ||
| 488 | return error; | ||
| 489 | } | ||
| 490 | |||
| 491 | int get_unused_fd(void) | ||
| 492 | { | ||
| 493 | return alloc_fd(0, 0); | ||
| 494 | } | ||
| 495 | EXPORT_SYMBOL(get_unused_fd); | ||
