aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVadim Lobanov <vlobanov@speakeasy.net>2006-12-10 05:21:17 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-10 12:57:22 -0500
commit4fd45812cbe875a620c86a096a5d46c742694b7e (patch)
tree8d2c99caa718da6cda87229076adf708494ff251
parentbbea9f69668a3d0cf9feba15a724cd02896f8675 (diff)
[PATCH] fdtable: Remove the free_files field
An fdtable can either be embedded inside a files_struct or standalone (after being expanded). When an fdtable is being discarded after all RCU references to it have expired, we must either free it directly, in the standalone case, or free the files_struct it is contained within, in the embedded case. Currently the free_files field controls this behavior, but we can get rid of it entirely, as all the necessary information is already recorded. We can distinguish embedded and standalone fdtables using max_fds, and if it is embedded we can divine the relevant files_struct using container_of(). 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>
-rw-r--r--fs/file.c27
-rw-r--r--include/linux/file.h3
-rw-r--r--include/linux/init_task.h1
-rw-r--r--kernel/exit.c6
-rw-r--r--kernel/fork.c1
5 files changed, 11 insertions, 27 deletions
diff --git a/fs/file.c b/fs/file.c
index fb3d2038dc21..17e6a55521e2 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -91,7 +91,7 @@ static void free_fdtable_work(struct work_struct *work)
91 } 91 }
92} 92}
93 93
94static void free_fdtable_rcu(struct rcu_head *rcu) 94void free_fdtable_rcu(struct rcu_head *rcu)
95{ 95{
96 struct fdtable *fdt = container_of(rcu, struct fdtable, rcu); 96 struct fdtable *fdt = container_of(rcu, struct fdtable, rcu);
97 int fdset_size, fdarray_size; 97 int fdset_size, fdarray_size;
@@ -101,20 +101,15 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
101 fdset_size = fdt->max_fds / 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->max_fds <= NR_OPEN_DEFAULT) {
105 /* 105 /*
106 * The this fdtable was embedded in the files structure 106 * This fdtable is embedded in the files structure and that
107 * and the files structure itself was getting destroyed. 107 * structure itself is getting destroyed.
108 * It is now safe to free the files structure.
109 */ 108 */
110 kmem_cache_free(files_cachep, fdt->free_files); 109 kmem_cache_free(files_cachep,
110 container_of(fdt, struct files_struct, fdtab));
111 return; 111 return;
112 } 112 }
113 if (fdt->max_fds <= NR_OPEN_DEFAULT)
114 /*
115 * The fdtable was embedded
116 */
117 return;
118 if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) { 113 if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) {
119 kfree(fdt->open_fds); 114 kfree(fdt->open_fds);
120 kfree(fdt->close_on_exec); 115 kfree(fdt->close_on_exec);
@@ -132,12 +127,6 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
132 } 127 }
133} 128}
134 129
135void free_fdtable(struct fdtable *fdt)
136{
137 if (fdt->free_files || fdt->max_fds > NR_OPEN_DEFAULT)
138 call_rcu(&fdt->rcu, free_fdtable_rcu);
139}
140
141/* 130/*
142 * Expand the fdset in the files_struct. Called with the files spinlock 131 * Expand the fdset in the files_struct. Called with the files spinlock
143 * held for write. 132 * held for write.
@@ -247,7 +236,6 @@ static struct fdtable *alloc_fdtable(int nr)
247 goto out; 236 goto out;
248 fdt->fd = new_fds; 237 fdt->fd = new_fds;
249 fdt->max_fds = nfds; 238 fdt->max_fds = nfds;
250 fdt->free_files = NULL;
251 return fdt; 239 return fdt;
252out: 240out:
253 free_fdset(new_openset, nfds); 241 free_fdset(new_openset, nfds);
@@ -283,7 +271,8 @@ static int expand_fdtable(struct files_struct *files, int nr)
283 /* Continue as planned */ 271 /* Continue as planned */
284 copy_fdtable(new_fdt, cur_fdt); 272 copy_fdtable(new_fdt, cur_fdt);
285 rcu_assign_pointer(files->fdt, new_fdt); 273 rcu_assign_pointer(files->fdt, new_fdt);
286 free_fdtable(cur_fdt); 274 if (cur_fdt->max_fds > NR_OPEN_DEFAULT)
275 call_rcu(&cur_fdt->rcu, free_fdtable_rcu);
287 } else { 276 } else {
288 /* Somebody else expanded, so undo our attempt */ 277 /* Somebody else expanded, so undo our attempt */
289 __free_fdtable(new_fdt); 278 __free_fdtable(new_fdt);
diff --git a/include/linux/file.h b/include/linux/file.h
index 02be4012225b..319118f275b0 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -32,7 +32,6 @@ struct fdtable {
32 fd_set *close_on_exec; 32 fd_set *close_on_exec;
33 fd_set *open_fds; 33 fd_set *open_fds;
34 struct rcu_head rcu; 34 struct rcu_head rcu;
35 struct files_struct *free_files;
36 struct fdtable *next; 35 struct fdtable *next;
37}; 36};
38 37
@@ -84,7 +83,7 @@ extern fd_set *alloc_fdset(int);
84extern void free_fdset(fd_set *, int); 83extern void free_fdset(fd_set *, int);
85 84
86extern int expand_files(struct files_struct *, int nr); 85extern int expand_files(struct files_struct *, int nr);
87extern void free_fdtable(struct fdtable *fdt); 86extern void free_fdtable_rcu(struct rcu_head *rcu);
88extern void __init files_defer_init(void); 87extern void __init files_defer_init(void);
89 88
90static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd) 89static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 58c18daab65d..b5315150199e 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -16,7 +16,6 @@
16 .close_on_exec = (fd_set *)&init_files.close_on_exec_init, \ 16 .close_on_exec = (fd_set *)&init_files.close_on_exec_init, \
17 .open_fds = (fd_set *)&init_files.open_fds_init, \ 17 .open_fds = (fd_set *)&init_files.open_fds_init, \
18 .rcu = RCU_HEAD_INIT, \ 18 .rcu = RCU_HEAD_INIT, \
19 .free_files = NULL, \
20 .next = NULL, \ 19 .next = NULL, \
21} 20}
22 21
diff --git a/kernel/exit.c b/kernel/exit.c
index 5f77e76b4f97..122fadb972fc 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -466,11 +466,9 @@ void fastcall put_files_struct(struct files_struct *files)
466 * you can free files immediately. 466 * you can free files immediately.
467 */ 467 */
468 fdt = files_fdtable(files); 468 fdt = files_fdtable(files);
469 if (fdt == &files->fdtab) 469 if (fdt != &files->fdtab)
470 fdt->free_files = files;
471 else
472 kmem_cache_free(files_cachep, files); 470 kmem_cache_free(files_cachep, files);
473 free_fdtable(fdt); 471 call_rcu(&fdt->rcu, free_fdtable_rcu);
474 } 472 }
475} 473}
476 474
diff --git a/kernel/fork.c b/kernel/fork.c
index aba595424f78..d16c566eb645 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -645,7 +645,6 @@ static struct files_struct *alloc_files(void)
645 fdt->open_fds = (fd_set *)&newf->open_fds_init; 645 fdt->open_fds = (fd_set *)&newf->open_fds_init;
646 fdt->fd = &newf->fd_array[0]; 646 fdt->fd = &newf->fd_array[0];
647 INIT_RCU_HEAD(&fdt->rcu); 647 INIT_RCU_HEAD(&fdt->rcu);
648 fdt->free_files = NULL;
649 fdt->next = NULL; 648 fdt->next = NULL;
650 rcu_assign_pointer(newf->fdt, fdt); 649 rcu_assign_pointer(newf->fdt, fdt);
651out: 650out: