diff options
Diffstat (limited to 'fs/fcntl.c')
-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 | } |