aboutsummaryrefslogtreecommitdiffstats
path: root/fs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/file.c')
-rw-r--r--fs/file.c56
1 files changed, 22 insertions, 34 deletions
diff --git a/fs/file.c b/fs/file.c
index 51aef675470f..fb3d2038dc21 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -68,8 +68,8 @@ void free_fd_array(struct file **array, int num)
68 68
69static void __free_fdtable(struct fdtable *fdt) 69static void __free_fdtable(struct fdtable *fdt)
70{ 70{
71 free_fdset(fdt->open_fds, fdt->max_fdset); 71 free_fdset(fdt->open_fds, fdt->max_fds);
72 free_fdset(fdt->close_on_exec, fdt->max_fdset); 72 free_fdset(fdt->close_on_exec, fdt->max_fds);
73 free_fd_array(fdt->fd, fdt->max_fds); 73 free_fd_array(fdt->fd, fdt->max_fds);
74 kfree(fdt); 74 kfree(fdt);
75} 75}
@@ -98,7 +98,7 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
98 struct fdtable_defer *fddef; 98 struct fdtable_defer *fddef;
99 99
100 BUG_ON(!fdt); 100 BUG_ON(!fdt);
101 fdset_size = fdt->max_fdset / 8; 101 fdset_size = fdt->max_fds / 8;
102 fdarray_size = fdt->max_fds * sizeof(struct file *); 102 fdarray_size = fdt->max_fds * sizeof(struct file *);
103 103
104 if (fdt->free_files) { 104 if (fdt->free_files) {
@@ -110,13 +110,11 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
110 kmem_cache_free(files_cachep, fdt->free_files); 110 kmem_cache_free(files_cachep, fdt->free_files);
111 return; 111 return;
112 } 112 }
113 if (fdt->max_fdset <= EMBEDDED_FD_SET_SIZE && 113 if (fdt->max_fds <= NR_OPEN_DEFAULT)
114 fdt->max_fds <= NR_OPEN_DEFAULT) {
115 /* 114 /*
116 * The fdtable was embedded 115 * The fdtable was embedded
117 */ 116 */
118 return; 117 return;
119 }
120 if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) { 118 if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) {
121 kfree(fdt->open_fds); 119 kfree(fdt->open_fds);
122 kfree(fdt->close_on_exec); 120 kfree(fdt->close_on_exec);
@@ -136,9 +134,7 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
136 134
137void free_fdtable(struct fdtable *fdt) 135void free_fdtable(struct fdtable *fdt)
138{ 136{
139 if (fdt->free_files || 137 if (fdt->free_files || fdt->max_fds > NR_OPEN_DEFAULT)
140 fdt->max_fdset > EMBEDDED_FD_SET_SIZE ||
141 fdt->max_fds > NR_OPEN_DEFAULT)
142 call_rcu(&fdt->rcu, free_fdtable_rcu); 138 call_rcu(&fdt->rcu, free_fdtable_rcu);
143} 139}
144 140
@@ -151,12 +147,11 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt)
151 int i; 147 int i;
152 int count; 148 int count;
153 149
154 BUG_ON(nfdt->max_fdset < fdt->max_fdset);
155 BUG_ON(nfdt->max_fds < fdt->max_fds); 150 BUG_ON(nfdt->max_fds < fdt->max_fds);
156 /* Copy the existing tables and install the new pointers */ 151 /* Copy the existing tables and install the new pointers */
157 152
158 i = fdt->max_fdset / (sizeof(unsigned long) * 8); 153 i = fdt->max_fds / (sizeof(unsigned long) * 8);
159 count = (nfdt->max_fdset - fdt->max_fdset) / 8; 154 count = (nfdt->max_fds - fdt->max_fds) / 8;
160 155
161 /* 156 /*
162 * Don't copy the entire array if the current fdset is 157 * Don't copy the entire array if the current fdset is
@@ -164,9 +159,9 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt)
164 */ 159 */
165 if (i) { 160 if (i) {
166 memcpy (nfdt->open_fds, fdt->open_fds, 161 memcpy (nfdt->open_fds, fdt->open_fds,
167 fdt->max_fdset/8); 162 fdt->max_fds/8);
168 memcpy (nfdt->close_on_exec, fdt->close_on_exec, 163 memcpy (nfdt->close_on_exec, fdt->close_on_exec,
169 fdt->max_fdset/8); 164 fdt->max_fds/8);
170 memset (&nfdt->open_fds->fds_bits[i], 0, count); 165 memset (&nfdt->open_fds->fds_bits[i], 0, count);
171 memset (&nfdt->close_on_exec->fds_bits[i], 0, count); 166 memset (&nfdt->close_on_exec->fds_bits[i], 0, count);
172 } 167 }
@@ -201,7 +196,7 @@ fd_set * alloc_fdset(int num)
201 196
202void free_fdset(fd_set *array, int num) 197void free_fdset(fd_set *array, int num)
203{ 198{
204 if (num <= EMBEDDED_FD_SET_SIZE) /* Don't free an embedded fdset */ 199 if (num <= NR_OPEN_DEFAULT) /* Don't free an embedded fdset */
205 return; 200 return;
206 else if (num <= 8 * PAGE_SIZE) 201 else if (num <= 8 * PAGE_SIZE)
207 kfree(array); 202 kfree(array);
@@ -220,18 +215,6 @@ static struct fdtable *alloc_fdtable(int nr)
220 if (!fdt) 215 if (!fdt)
221 goto out; 216 goto out;
222 217
223 nfds = max_t(int, 8 * L1_CACHE_BYTES, roundup_pow_of_two(nr + 1));
224 if (nfds > NR_OPEN)
225 nfds = NR_OPEN;
226
227 new_openset = alloc_fdset(nfds);
228 new_execset = alloc_fdset(nfds);
229 if (!new_openset || !new_execset)
230 goto out;
231 fdt->open_fds = new_openset;
232 fdt->close_on_exec = new_execset;
233 fdt->max_fdset = nfds;
234
235 nfds = NR_OPEN_DEFAULT; 218 nfds = NR_OPEN_DEFAULT;
236 /* 219 /*
237 * Expand to the max in easy steps, and keep expanding it until 220 * Expand to the max in easy steps, and keep expanding it until
@@ -251,15 +234,21 @@ static struct fdtable *alloc_fdtable(int nr)
251 nfds = NR_OPEN; 234 nfds = NR_OPEN;
252 } 235 }
253 } while (nfds <= nr); 236 } while (nfds <= nr);
237
238 new_openset = alloc_fdset(nfds);
239 new_execset = alloc_fdset(nfds);
240 if (!new_openset || !new_execset)
241 goto out;
242 fdt->open_fds = new_openset;
243 fdt->close_on_exec = new_execset;
244
254 new_fds = alloc_fd_array(nfds); 245 new_fds = alloc_fd_array(nfds);
255 if (!new_fds) 246 if (!new_fds)
256 goto out2; 247 goto out;
257 fdt->fd = new_fds; 248 fdt->fd = new_fds;
258 fdt->max_fds = nfds; 249 fdt->max_fds = nfds;
259 fdt->free_files = NULL; 250 fdt->free_files = NULL;
260 return fdt; 251 return fdt;
261out2:
262 nfds = fdt->max_fdset;
263out: 252out:
264 free_fdset(new_openset, nfds); 253 free_fdset(new_openset, nfds);
265 free_fdset(new_execset, nfds); 254 free_fdset(new_execset, nfds);
@@ -290,7 +279,7 @@ static int expand_fdtable(struct files_struct *files, int nr)
290 * we dropped the lock 279 * we dropped the lock
291 */ 280 */
292 cur_fdt = files_fdtable(files); 281 cur_fdt = files_fdtable(files);
293 if (nr >= cur_fdt->max_fds || nr >= cur_fdt->max_fdset) { 282 if (nr >= cur_fdt->max_fds) {
294 /* Continue as planned */ 283 /* Continue as planned */
295 copy_fdtable(new_fdt, cur_fdt); 284 copy_fdtable(new_fdt, cur_fdt);
296 rcu_assign_pointer(files->fdt, new_fdt); 285 rcu_assign_pointer(files->fdt, new_fdt);
@@ -316,11 +305,10 @@ int expand_files(struct files_struct *files, int nr)
316 305
317 fdt = files_fdtable(files); 306 fdt = files_fdtable(files);
318 /* Do we need to expand? */ 307 /* Do we need to expand? */
319 if (nr < fdt->max_fdset && nr < fdt->max_fds) 308 if (nr < fdt->max_fds)
320 return 0; 309 return 0;
321 /* Can we expand? */ 310 /* Can we expand? */
322 if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN || 311 if (nr >= NR_OPEN)
323 nr >= NR_OPEN)
324 return -EMFILE; 312 return -EMFILE;
325 313
326 /* All good, so we try */ 314 /* All good, so we try */