diff options
author | David Howells <dhowells@redhat.com> | 2012-02-16 12:49:54 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2012-02-19 13:30:57 -0500 |
commit | 1fd36adcd98c14d2fd97f545293c488775cb2823 (patch) | |
tree | c13ab1934a15aebe0d81601d910ce5a3c6fa2c6f /fs/file.c | |
parent | 1dce27c5aa6770e9d195f2bb7db1db3d4dde5591 (diff) |
Replace the fd_sets in struct fdtable with an array of unsigned longs
Replace the fd_sets in struct fdtable with an array of unsigned longs and then
use the standard non-atomic bit operations rather than the FD_* macros.
This:
(1) Removes the abuses of struct fd_set:
(a) Since we don't want to allocate a full fd_set the vast majority of the
time, we actually, in effect, just allocate a just-big-enough array of
unsigned longs and cast it to an fd_set type - so why bother with the
fd_set at all?
(b) Some places outside of the core fdtable handling code (such as
SELinux) want to look inside the array of unsigned longs hidden inside
the fd_set struct for more efficient iteration over the entire set.
(2) Eliminates the use of FD_*() macros in the kernel completely.
(3) Permits the __FD_*() macros to be deleted entirely where not exposed to
userspace.
Signed-off-by: David Howells <dhowells@redhat.com>
Link: http://lkml.kernel.org/r/20120216174954.23314.48147.stgit@warthog.procyon.org.uk
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/file.c')
-rw-r--r-- | fs/file.c | 46 |
1 files changed, 22 insertions, 24 deletions
@@ -40,7 +40,7 @@ int sysctl_nr_open_max = 1024 * 1024; /* raised later */ | |||
40 | */ | 40 | */ |
41 | static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list); | 41 | static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list); |
42 | 42 | ||
43 | static void *alloc_fdmem(unsigned int size) | 43 | static void *alloc_fdmem(size_t size) |
44 | { | 44 | { |
45 | /* | 45 | /* |
46 | * Very large allocations can stress page reclaim, so fall back to | 46 | * Very large allocations can stress page reclaim, so fall back to |
@@ -142,7 +142,7 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt) | |||
142 | static struct fdtable * alloc_fdtable(unsigned int nr) | 142 | static struct fdtable * alloc_fdtable(unsigned int nr) |
143 | { | 143 | { |
144 | struct fdtable *fdt; | 144 | struct fdtable *fdt; |
145 | char *data; | 145 | void *data; |
146 | 146 | ||
147 | /* | 147 | /* |
148 | * Figure out how many fds we actually want to support in this fdtable. | 148 | * Figure out how many fds we actually want to support in this fdtable. |
@@ -172,14 +172,15 @@ static struct fdtable * alloc_fdtable(unsigned int nr) | |||
172 | data = alloc_fdmem(nr * sizeof(struct file *)); | 172 | data = alloc_fdmem(nr * sizeof(struct file *)); |
173 | if (!data) | 173 | if (!data) |
174 | goto out_fdt; | 174 | goto out_fdt; |
175 | fdt->fd = (struct file **)data; | 175 | fdt->fd = data; |
176 | data = alloc_fdmem(max_t(unsigned int, | 176 | |
177 | data = alloc_fdmem(max_t(size_t, | ||
177 | 2 * nr / BITS_PER_BYTE, L1_CACHE_BYTES)); | 178 | 2 * nr / BITS_PER_BYTE, L1_CACHE_BYTES)); |
178 | if (!data) | 179 | if (!data) |
179 | goto out_arr; | 180 | goto out_arr; |
180 | fdt->open_fds = (fd_set *)data; | 181 | fdt->open_fds = data; |
181 | data += nr / BITS_PER_BYTE; | 182 | data += nr / BITS_PER_LONG; |
182 | fdt->close_on_exec = (fd_set *)data; | 183 | fdt->close_on_exec = data; |
183 | fdt->next = NULL; | 184 | fdt->next = NULL; |
184 | 185 | ||
185 | return fdt; | 186 | return fdt; |
@@ -275,11 +276,11 @@ static int count_open_files(struct fdtable *fdt) | |||
275 | int i; | 276 | int i; |
276 | 277 | ||
277 | /* Find the last open fd */ | 278 | /* Find the last open fd */ |
278 | for (i = size/(8*sizeof(long)); i > 0; ) { | 279 | for (i = size / BITS_PER_LONG; i > 0; ) { |
279 | if (fdt->open_fds->fds_bits[--i]) | 280 | if (fdt->open_fds[--i]) |
280 | break; | 281 | break; |
281 | } | 282 | } |
282 | i = (i+1) * 8 * sizeof(long); | 283 | i = (i + 1) * BITS_PER_LONG; |
283 | return i; | 284 | return i; |
284 | } | 285 | } |
285 | 286 | ||
@@ -306,8 +307,8 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) | |||
306 | newf->next_fd = 0; | 307 | newf->next_fd = 0; |
307 | new_fdt = &newf->fdtab; | 308 | new_fdt = &newf->fdtab; |
308 | new_fdt->max_fds = NR_OPEN_DEFAULT; | 309 | new_fdt->max_fds = NR_OPEN_DEFAULT; |
309 | new_fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init; | 310 | new_fdt->close_on_exec = newf->close_on_exec_init; |
310 | new_fdt->open_fds = (fd_set *)&newf->open_fds_init; | 311 | new_fdt->open_fds = newf->open_fds_init; |
311 | new_fdt->fd = &newf->fd_array[0]; | 312 | new_fdt->fd = &newf->fd_array[0]; |
312 | new_fdt->next = NULL; | 313 | new_fdt->next = NULL; |
313 | 314 | ||
@@ -350,10 +351,8 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) | |||
350 | old_fds = old_fdt->fd; | 351 | old_fds = old_fdt->fd; |
351 | new_fds = new_fdt->fd; | 352 | new_fds = new_fdt->fd; |
352 | 353 | ||
353 | memcpy(new_fdt->open_fds->fds_bits, | 354 | memcpy(new_fdt->open_fds, old_fdt->open_fds, open_files / 8); |
354 | old_fdt->open_fds->fds_bits, open_files/8); | 355 | memcpy(new_fdt->close_on_exec, old_fdt->close_on_exec, open_files / 8); |
355 | memcpy(new_fdt->close_on_exec->fds_bits, | ||
356 | old_fdt->close_on_exec->fds_bits, open_files/8); | ||
357 | 356 | ||
358 | for (i = open_files; i != 0; i--) { | 357 | for (i = open_files; i != 0; i--) { |
359 | struct file *f = *old_fds++; | 358 | struct file *f = *old_fds++; |
@@ -379,11 +378,11 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) | |||
379 | memset(new_fds, 0, size); | 378 | memset(new_fds, 0, size); |
380 | 379 | ||
381 | if (new_fdt->max_fds > open_files) { | 380 | if (new_fdt->max_fds > open_files) { |
382 | int left = (new_fdt->max_fds-open_files)/8; | 381 | int left = (new_fdt->max_fds - open_files) / 8; |
383 | int start = open_files / (8 * sizeof(unsigned long)); | 382 | int start = open_files / BITS_PER_LONG; |
384 | 383 | ||
385 | memset(&new_fdt->open_fds->fds_bits[start], 0, left); | 384 | memset(&new_fdt->open_fds[start], 0, left); |
386 | memset(&new_fdt->close_on_exec->fds_bits[start], 0, left); | 385 | memset(&new_fdt->close_on_exec[start], 0, left); |
387 | } | 386 | } |
388 | 387 | ||
389 | rcu_assign_pointer(newf->fdt, new_fdt); | 388 | rcu_assign_pointer(newf->fdt, new_fdt); |
@@ -419,8 +418,8 @@ struct files_struct init_files = { | |||
419 | .fdtab = { | 418 | .fdtab = { |
420 | .max_fds = NR_OPEN_DEFAULT, | 419 | .max_fds = NR_OPEN_DEFAULT, |
421 | .fd = &init_files.fd_array[0], | 420 | .fd = &init_files.fd_array[0], |
422 | .close_on_exec = (fd_set *)&init_files.close_on_exec_init, | 421 | .close_on_exec = init_files.close_on_exec_init, |
423 | .open_fds = (fd_set *)&init_files.open_fds_init, | 422 | .open_fds = init_files.open_fds_init, |
424 | }, | 423 | }, |
425 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), | 424 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), |
426 | }; | 425 | }; |
@@ -443,8 +442,7 @@ repeat: | |||
443 | fd = files->next_fd; | 442 | fd = files->next_fd; |
444 | 443 | ||
445 | if (fd < fdt->max_fds) | 444 | if (fd < fdt->max_fds) |
446 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, | 445 | fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, fd); |
447 | fdt->max_fds, fd); | ||
448 | 446 | ||
449 | error = expand_files(files, fd); | 447 | error = expand_files(files, fd); |
450 | if (error < 0) | 448 | if (error < 0) |