diff options
Diffstat (limited to 'fs/file.c')
-rw-r--r-- | fs/file.c | 39 |
1 files changed, 35 insertions, 4 deletions
@@ -56,6 +56,9 @@ static void free_fdtable_rcu(struct rcu_head *rcu) | |||
56 | __free_fdtable(container_of(rcu, struct fdtable, rcu)); | 56 | __free_fdtable(container_of(rcu, struct fdtable, rcu)); |
57 | } | 57 | } |
58 | 58 | ||
59 | #define BITBIT_NR(nr) BITS_TO_LONGS(BITS_TO_LONGS(nr)) | ||
60 | #define BITBIT_SIZE(nr) (BITBIT_NR(nr) * sizeof(long)) | ||
61 | |||
59 | /* | 62 | /* |
60 | * Expand the fdset in the files_struct. Called with the files spinlock | 63 | * Expand the fdset in the files_struct. Called with the files spinlock |
61 | * held for write. | 64 | * held for write. |
@@ -77,6 +80,11 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt) | |||
77 | memset((char *)(nfdt->open_fds) + cpy, 0, set); | 80 | memset((char *)(nfdt->open_fds) + cpy, 0, set); |
78 | memcpy(nfdt->close_on_exec, ofdt->close_on_exec, cpy); | 81 | memcpy(nfdt->close_on_exec, ofdt->close_on_exec, cpy); |
79 | memset((char *)(nfdt->close_on_exec) + cpy, 0, set); | 82 | memset((char *)(nfdt->close_on_exec) + cpy, 0, set); |
83 | |||
84 | cpy = BITBIT_SIZE(ofdt->max_fds); | ||
85 | set = BITBIT_SIZE(nfdt->max_fds) - cpy; | ||
86 | memcpy(nfdt->full_fds_bits, ofdt->full_fds_bits, cpy); | ||
87 | memset(cpy+(char *)nfdt->full_fds_bits, 0, set); | ||
80 | } | 88 | } |
81 | 89 | ||
82 | static struct fdtable * alloc_fdtable(unsigned int nr) | 90 | static struct fdtable * alloc_fdtable(unsigned int nr) |
@@ -115,12 +123,14 @@ static struct fdtable * alloc_fdtable(unsigned int nr) | |||
115 | fdt->fd = data; | 123 | fdt->fd = data; |
116 | 124 | ||
117 | data = alloc_fdmem(max_t(size_t, | 125 | data = alloc_fdmem(max_t(size_t, |
118 | 2 * nr / BITS_PER_BYTE, L1_CACHE_BYTES)); | 126 | 2 * nr / BITS_PER_BYTE + BITBIT_SIZE(nr), L1_CACHE_BYTES)); |
119 | if (!data) | 127 | if (!data) |
120 | goto out_arr; | 128 | goto out_arr; |
121 | fdt->open_fds = data; | 129 | fdt->open_fds = data; |
122 | data += nr / BITS_PER_BYTE; | 130 | data += nr / BITS_PER_BYTE; |
123 | fdt->close_on_exec = data; | 131 | fdt->close_on_exec = data; |
132 | data += nr / BITS_PER_BYTE; | ||
133 | fdt->full_fds_bits = data; | ||
124 | 134 | ||
125 | return fdt; | 135 | return fdt; |
126 | 136 | ||
@@ -229,14 +239,18 @@ static inline void __clear_close_on_exec(int fd, struct fdtable *fdt) | |||
229 | __clear_bit(fd, fdt->close_on_exec); | 239 | __clear_bit(fd, fdt->close_on_exec); |
230 | } | 240 | } |
231 | 241 | ||
232 | static inline void __set_open_fd(int fd, struct fdtable *fdt) | 242 | static inline void __set_open_fd(unsigned int fd, struct fdtable *fdt) |
233 | { | 243 | { |
234 | __set_bit(fd, fdt->open_fds); | 244 | __set_bit(fd, fdt->open_fds); |
245 | fd /= BITS_PER_LONG; | ||
246 | if (!~fdt->open_fds[fd]) | ||
247 | __set_bit(fd, fdt->full_fds_bits); | ||
235 | } | 248 | } |
236 | 249 | ||
237 | static inline void __clear_open_fd(int fd, struct fdtable *fdt) | 250 | static inline void __clear_open_fd(unsigned int fd, struct fdtable *fdt) |
238 | { | 251 | { |
239 | __clear_bit(fd, fdt->open_fds); | 252 | __clear_bit(fd, fdt->open_fds); |
253 | __clear_bit(fd / BITS_PER_LONG, fdt->full_fds_bits); | ||
240 | } | 254 | } |
241 | 255 | ||
242 | static int count_open_files(struct fdtable *fdt) | 256 | static int count_open_files(struct fdtable *fdt) |
@@ -280,6 +294,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) | |||
280 | new_fdt->max_fds = NR_OPEN_DEFAULT; | 294 | new_fdt->max_fds = NR_OPEN_DEFAULT; |
281 | new_fdt->close_on_exec = newf->close_on_exec_init; | 295 | new_fdt->close_on_exec = newf->close_on_exec_init; |
282 | new_fdt->open_fds = newf->open_fds_init; | 296 | new_fdt->open_fds = newf->open_fds_init; |
297 | new_fdt->full_fds_bits = newf->full_fds_bits_init; | ||
283 | new_fdt->fd = &newf->fd_array[0]; | 298 | new_fdt->fd = &newf->fd_array[0]; |
284 | 299 | ||
285 | spin_lock(&oldf->file_lock); | 300 | spin_lock(&oldf->file_lock); |
@@ -323,6 +338,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) | |||
323 | 338 | ||
324 | memcpy(new_fdt->open_fds, old_fdt->open_fds, open_files / 8); | 339 | memcpy(new_fdt->open_fds, old_fdt->open_fds, open_files / 8); |
325 | memcpy(new_fdt->close_on_exec, old_fdt->close_on_exec, open_files / 8); | 340 | memcpy(new_fdt->close_on_exec, old_fdt->close_on_exec, open_files / 8); |
341 | memcpy(new_fdt->full_fds_bits, old_fdt->full_fds_bits, BITBIT_SIZE(open_files)); | ||
326 | 342 | ||
327 | for (i = open_files; i != 0; i--) { | 343 | for (i = open_files; i != 0; i--) { |
328 | struct file *f = *old_fds++; | 344 | struct file *f = *old_fds++; |
@@ -454,10 +470,25 @@ struct files_struct init_files = { | |||
454 | .fd = &init_files.fd_array[0], | 470 | .fd = &init_files.fd_array[0], |
455 | .close_on_exec = init_files.close_on_exec_init, | 471 | .close_on_exec = init_files.close_on_exec_init, |
456 | .open_fds = init_files.open_fds_init, | 472 | .open_fds = init_files.open_fds_init, |
473 | .full_fds_bits = init_files.full_fds_bits_init, | ||
457 | }, | 474 | }, |
458 | .file_lock = __SPIN_LOCK_UNLOCKED(init_files.file_lock), | 475 | .file_lock = __SPIN_LOCK_UNLOCKED(init_files.file_lock), |
459 | }; | 476 | }; |
460 | 477 | ||
478 | static unsigned long find_next_fd(struct fdtable *fdt, unsigned long start) | ||
479 | { | ||
480 | unsigned long maxfd = fdt->max_fds; | ||
481 | unsigned long maxbit = maxfd / BITS_PER_LONG; | ||
482 | unsigned long bitbit = start / BITS_PER_LONG; | ||
483 | |||
484 | bitbit = find_next_zero_bit(fdt->full_fds_bits, maxbit, bitbit) * BITS_PER_LONG; | ||
485 | if (bitbit > maxfd) | ||
486 | return maxfd; | ||
487 | if (bitbit > start) | ||
488 | start = bitbit; | ||
489 | return find_next_zero_bit(fdt->open_fds, maxfd, start); | ||
490 | } | ||
491 | |||
461 | /* | 492 | /* |
462 | * allocate a file descriptor, mark it busy. | 493 | * allocate a file descriptor, mark it busy. |
463 | */ | 494 | */ |
@@ -476,7 +507,7 @@ repeat: | |||
476 | fd = files->next_fd; | 507 | fd = files->next_fd; |
477 | 508 | ||
478 | if (fd < fdt->max_fds) | 509 | if (fd < fdt->max_fds) |
479 | fd = find_next_zero_bit(fdt->open_fds, fdt->max_fds, fd); | 510 | fd = find_next_fd(fdt, fd); |
480 | 511 | ||
481 | /* | 512 | /* |
482 | * N.B. For clone tasks sharing a files structure, this test | 513 | * N.B. For clone tasks sharing a files structure, this test |