aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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: