diff options
| -rw-r--r-- | fs/fcntl.c | 40 |
1 files changed, 14 insertions, 26 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index e632da761fc1..3f3ac630ccde 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -55,14 +55,16 @@ static int get_close_on_exec(unsigned int fd) | |||
| 55 | * file_lock held for write. | 55 | * file_lock held for write. |
| 56 | */ | 56 | */ |
| 57 | 57 | ||
| 58 | static int locate_fd(struct files_struct *files, | 58 | static int locate_fd(unsigned int orig_start, int cloexec) |
| 59 | struct file *file, unsigned int orig_start) | ||
| 60 | { | 59 | { |
| 60 | struct files_struct *files = current->files; | ||
| 61 | unsigned int newfd; | 61 | unsigned int newfd; |
| 62 | unsigned int start; | 62 | unsigned int start; |
| 63 | int error; | 63 | int error; |
| 64 | struct fdtable *fdt; | 64 | struct fdtable *fdt; |
| 65 | 65 | ||
| 66 | spin_lock(&files->file_lock); | ||
| 67 | |||
| 66 | error = -EINVAL; | 68 | error = -EINVAL; |
| 67 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | 69 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) |
| 68 | goto out; | 70 | goto out; |
| @@ -97,42 +99,28 @@ repeat: | |||
| 97 | if (error) | 99 | if (error) |
| 98 | goto repeat; | 100 | goto repeat; |
| 99 | 101 | ||
| 100 | /* | ||
| 101 | * We reacquired files_lock, so we are safe as long as | ||
| 102 | * we reacquire the fdtable pointer and use it while holding | ||
| 103 | * the lock, no one can free it during that time. | ||
| 104 | */ | ||
| 105 | if (start <= files->next_fd) | 102 | if (start <= files->next_fd) |
| 106 | files->next_fd = newfd + 1; | 103 | files->next_fd = newfd + 1; |
| 107 | 104 | ||
| 105 | FD_SET(newfd, fdt->open_fds); | ||
| 106 | if (cloexec) | ||
| 107 | FD_SET(newfd, fdt->close_on_exec); | ||
| 108 | else | ||
| 109 | FD_CLR(newfd, fdt->close_on_exec); | ||
| 108 | error = newfd; | 110 | error = newfd; |
| 109 | 111 | ||
| 110 | out: | 112 | out: |
| 113 | spin_unlock(&files->file_lock); | ||
| 111 | return error; | 114 | return error; |
| 112 | } | 115 | } |
| 113 | 116 | ||
| 114 | static int dupfd(struct file *file, unsigned int start, int cloexec) | 117 | static int dupfd(struct file *file, unsigned int start, int cloexec) |
| 115 | { | 118 | { |
| 116 | struct files_struct * files = current->files; | 119 | int fd = locate_fd(start, cloexec); |
| 117 | struct fdtable *fdt; | 120 | if (fd >= 0) |
| 118 | int fd; | ||
| 119 | |||
| 120 | spin_lock(&files->file_lock); | ||
| 121 | fd = locate_fd(files, file, start); | ||
| 122 | if (fd >= 0) { | ||
| 123 | /* locate_fd() may have expanded fdtable, load the ptr */ | ||
| 124 | fdt = files_fdtable(files); | ||
| 125 | FD_SET(fd, fdt->open_fds); | ||
| 126 | if (cloexec) | ||
| 127 | FD_SET(fd, fdt->close_on_exec); | ||
| 128 | else | ||
| 129 | FD_CLR(fd, fdt->close_on_exec); | ||
| 130 | spin_unlock(&files->file_lock); | ||
| 131 | fd_install(fd, file); | 121 | fd_install(fd, file); |
| 132 | } else { | 122 | else |
| 133 | spin_unlock(&files->file_lock); | ||
| 134 | fput(file); | 123 | fput(file); |
| 135 | } | ||
| 136 | 124 | ||
| 137 | return fd; | 125 | return fd; |
| 138 | } | 126 | } |
