Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Wrap accesses to the fd_sets in struct fdtable

Wrap accesses to the fd_sets in struct fdtable (for recording open files and
close-on-exec flags) so that we can move away from using fd_sets since we
abuse the fd_set structs by not allocating the full-sized structure under
normal circumstances and by non-core code looking at the internals of the
fd_sets.

The first abuse means that use of FD_ZERO() on these fd_sets is not permitted,
since that cannot be told about their abnormal lengths.

This introduces six wrapper functions for setting, clearing and testing
close-on-exec flags and fd-is-open flags:

void __set_close_on_exec(int fd, struct fdtable *fdt);
void __clear_close_on_exec(int fd, struct fdtable *fdt);
bool close_on_exec(int fd, const struct fdtable *fdt);
void __set_open_fd(int fd, struct fdtable *fdt);
void __clear_open_fd(int fd, struct fdtable *fdt);
bool fd_is_open(int fd, const struct fdtable *fdt);

Note that I've prepended '__' to the names of the set/clear functions because
they require the caller to hold a lock to use them.

Note also that I haven't added wrappers for looking behind the scenes at the
the array. Possibly that should exist too.

Signed-off-by: David Howells <dhowells@redhat.com>
Link: http://lkml.kernel.org/r/20120216174942.23314.1364.stgit@warthog.procyon.org.uk
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>

authored by

David Howells and committed by
H. Peter Anvin
1dce27c5 8b3d1cda

+57 -27
+2 -2
Documentation/filesystems/files.txt
··· 113 113 if (fd >= 0) { 114 114 /* locate_fd() may have expanded fdtable, load the ptr */ 115 115 fdt = files_fdtable(files); 116 - FD_SET(fd, fdt->open_fds); 117 - FD_CLR(fd, fdt->close_on_exec); 116 + __set_open_fd(fd, fdt); 117 + __clear_close_on_exec(fd, fdt); 118 118 spin_unlock(&files->file_lock); 119 119 ..... 120 120
+1 -1
arch/powerpc/platforms/cell/spufs/coredump.c
··· 122 122 struct spu_context *ctx = NULL; 123 123 124 124 for (; *fd < fdt->max_fds; (*fd)++) { 125 - if (!FD_ISSET(*fd, fdt->open_fds)) 125 + if (!fd_is_open(*fd, fdt)) 126 126 continue; 127 127 128 128 file = fcheck(*fd);
+5 -5
drivers/staging/android/binder.c
··· 408 408 goto repeat; 409 409 } 410 410 411 - FD_SET(fd, fdt->open_fds); 411 + __set_open_fd(fd, fdt); 412 412 if (flags & O_CLOEXEC) 413 - FD_SET(fd, fdt->close_on_exec); 413 + __set_close_on_exec(fd, fdt); 414 414 else 415 - FD_CLR(fd, fdt->close_on_exec); 415 + __clear_close_on_exec(fd, fdt); 416 416 files->next_fd = fd + 1; 417 417 #if 1 418 418 /* Sanity check */ ··· 453 453 static void __put_unused_fd(struct files_struct *files, unsigned int fd) 454 454 { 455 455 struct fdtable *fdt = files_fdtable(files); 456 - __FD_CLR(fd, fdt->open_fds); 456 + __clear_open_fd(fd, fdt); 457 457 if (fd < files->next_fd) 458 458 files->next_fd = fd; 459 459 } ··· 479 479 if (!filp) 480 480 goto out_unlock; 481 481 rcu_assign_pointer(fdt->fd[fd], NULL); 482 - FD_CLR(fd, fdt->close_on_exec); 482 + __clear_close_on_exec(fd, fdt); 483 483 __put_unused_fd(files, fd); 484 484 spin_unlock(&files->file_lock); 485 485 retval = filp_close(filp, files);
+1 -1
fs/autofs4/dev-ioctl.c
··· 230 230 fdt = files_fdtable(files); 231 231 BUG_ON(fdt->fd[fd] != NULL); 232 232 rcu_assign_pointer(fdt->fd[fd], file); 233 - FD_SET(fd, fdt->close_on_exec); 233 + __set_close_on_exec(fd, fdt); 234 234 spin_unlock(&files->file_lock); 235 235 } 236 236
+2 -2
fs/exec.c
··· 2078 2078 fd_install(0, rp); 2079 2079 spin_lock(&cf->file_lock); 2080 2080 fdt = files_fdtable(cf); 2081 - FD_SET(0, fdt->open_fds); 2082 - FD_CLR(0, fdt->close_on_exec); 2081 + __set_open_fd(0, fdt); 2082 + __clear_close_on_exec(0, fdt); 2083 2083 spin_unlock(&cf->file_lock); 2084 2084 2085 2085 /* and disallow core files too */
+9 -9
fs/fcntl.c
··· 32 32 spin_lock(&files->file_lock); 33 33 fdt = files_fdtable(files); 34 34 if (flag) 35 - FD_SET(fd, fdt->close_on_exec); 35 + __set_close_on_exec(fd, fdt); 36 36 else 37 - FD_CLR(fd, fdt->close_on_exec); 37 + __clear_close_on_exec(fd, fdt); 38 38 spin_unlock(&files->file_lock); 39 39 } 40 40 41 - static int get_close_on_exec(unsigned int fd) 41 + static bool get_close_on_exec(unsigned int fd) 42 42 { 43 43 struct files_struct *files = current->files; 44 44 struct fdtable *fdt; 45 - int res; 45 + bool res; 46 46 rcu_read_lock(); 47 47 fdt = files_fdtable(files); 48 - res = FD_ISSET(fd, fdt->close_on_exec); 48 + res = close_on_exec(fd, fdt); 49 49 rcu_read_unlock(); 50 50 return res; 51 51 } ··· 90 90 err = -EBUSY; 91 91 fdt = files_fdtable(files); 92 92 tofree = fdt->fd[newfd]; 93 - if (!tofree && FD_ISSET(newfd, fdt->open_fds)) 93 + if (!tofree && fd_is_open(newfd, fdt)) 94 94 goto out_unlock; 95 95 get_file(file); 96 96 rcu_assign_pointer(fdt->fd[newfd], file); 97 - FD_SET(newfd, fdt->open_fds); 97 + __set_open_fd(newfd, fdt); 98 98 if (flags & O_CLOEXEC) 99 - FD_SET(newfd, fdt->close_on_exec); 99 + __set_close_on_exec(newfd, fdt); 100 100 else 101 - FD_CLR(newfd, fdt->close_on_exec); 101 + __clear_close_on_exec(newfd, fdt); 102 102 spin_unlock(&files->file_lock); 103 103 104 104 if (tofree)
+4 -4
fs/file.c
··· 366 366 * is partway through open(). So make sure that this 367 367 * fd is available to the new process. 368 368 */ 369 - FD_CLR(open_files - i, new_fdt->open_fds); 369 + __clear_open_fd(open_files - i, new_fdt); 370 370 } 371 371 rcu_assign_pointer(*new_fds++, f); 372 372 } ··· 460 460 if (start <= files->next_fd) 461 461 files->next_fd = fd + 1; 462 462 463 - FD_SET(fd, fdt->open_fds); 463 + __set_open_fd(fd, fdt); 464 464 if (flags & O_CLOEXEC) 465 - FD_SET(fd, fdt->close_on_exec); 465 + __set_close_on_exec(fd, fdt); 466 466 else 467 - FD_CLR(fd, fdt->close_on_exec); 467 + __clear_close_on_exec(fd, fdt); 468 468 error = fd; 469 469 #if 1 470 470 /* Sanity check */
+2 -2
fs/open.c
··· 836 836 static void __put_unused_fd(struct files_struct *files, unsigned int fd) 837 837 { 838 838 struct fdtable *fdt = files_fdtable(files); 839 - __FD_CLR(fd, fdt->open_fds); 839 + __clear_open_fd(fd, fdt); 840 840 if (fd < files->next_fd) 841 841 files->next_fd = fd; 842 842 } ··· 1080 1080 if (!filp) 1081 1081 goto out_unlock; 1082 1082 rcu_assign_pointer(fdt->fd[fd], NULL); 1083 - FD_CLR(fd, fdt->close_on_exec); 1083 + __clear_close_on_exec(fd, fdt); 1084 1084 __put_unused_fd(files, fd); 1085 1085 spin_unlock(&files->file_lock); 1086 1086 retval = filp_close(filp, files);
+1 -1
fs/proc/base.c
··· 1754 1754 1755 1755 fdt = files_fdtable(files); 1756 1756 f_flags = file->f_flags & ~O_CLOEXEC; 1757 - if (FD_ISSET(fd, fdt->close_on_exec)) 1757 + if (close_on_exec(fd, fdt)) 1758 1758 f_flags |= O_CLOEXEC; 1759 1759 1760 1760 if (path) {
+30
include/linux/fdtable.h
··· 38 38 struct fdtable *next; 39 39 }; 40 40 41 + static inline void __set_close_on_exec(int fd, struct fdtable *fdt) 42 + { 43 + FD_SET(fd, fdt->close_on_exec); 44 + } 45 + 46 + static inline void __clear_close_on_exec(int fd, struct fdtable *fdt) 47 + { 48 + FD_CLR(fd, fdt->close_on_exec); 49 + } 50 + 51 + static inline bool close_on_exec(int fd, const struct fdtable *fdt) 52 + { 53 + return FD_ISSET(fd, fdt->close_on_exec); 54 + } 55 + 56 + static inline void __set_open_fd(int fd, struct fdtable *fdt) 57 + { 58 + FD_SET(fd, fdt->open_fds); 59 + } 60 + 61 + static inline void __clear_open_fd(int fd, struct fdtable *fdt) 62 + { 63 + FD_CLR(fd, fdt->open_fds); 64 + } 65 + 66 + static inline bool fd_is_open(int fd, const struct fdtable *fdt) 67 + { 68 + return FD_ISSET(fd, fdt->open_fds); 69 + } 70 + 41 71 /* 42 72 * Open file table structure 43 73 */