diff options
author | Vadim Lobanov <vlobanov@speakeasy.net> | 2006-12-10 05:21:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-10 12:57:22 -0500 |
commit | bbea9f69668a3d0cf9feba15a724cd02896f8675 (patch) | |
tree | bc58506e4daba4a04309181a5501ae4eb5424783 /fs/file.c | |
parent | f3d19c90fb117a5f080310a4592929aa8e1ad8e9 (diff) |
[PATCH] fdtable: Make fdarray and fdsets equal in size
Currently, each fdtable supports three dynamically-sized arrays of data: the
fdarray and two fdsets. The code allows the number of fds supported by the
fdarray (fdtable->max_fds) to differ from the number of fds supported by each
of the fdsets (fdtable->max_fdset).
In practice, it is wasteful for these two sizes to differ: whenever we hit a
limit on the smaller-capacity structure, we will reallocate the entire fdtable
and all the dynamic arrays within it, so any delta in the memory used by the
larger-capacity structure will never be touched at all.
Rather than hogging this excess, we shouldn't even allocate it in the first
place, and keep the capacities of the fdarray and the fdsets equal. This
patch removes fdtable->max_fdset. As an added bonus, most of the supporting
code becomes simpler.
Signed-off-by: Vadim Lobanov <vlobanov@speakeasy.net>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Dipankar Sarma <dipankar@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/file.c')
-rw-r--r-- | fs/file.c | 56 |
1 files changed, 22 insertions, 34 deletions
@@ -68,8 +68,8 @@ void free_fd_array(struct file **array, int num) | |||
68 | 68 | ||
69 | static void __free_fdtable(struct fdtable *fdt) | 69 | static 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 | ||
137 | void free_fdtable(struct fdtable *fdt) | 135 | void 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 | ||
202 | void free_fdset(fd_set *array, int num) | 197 | void 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; |
261 | out2: | ||
262 | nfds = fdt->max_fdset; | ||
263 | out: | 252 | out: |
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 */ |