Commit 4fd45812cbe875a620c86a096a5d46c742694b7e

Authored by Vadim Lobanov
Committed by Linus Torvalds
1 parent bbea9f6966

[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>

Showing 5 changed files with 11 additions and 27 deletions Side-by-side Diff

... ... @@ -91,7 +91,7 @@
91 91 }
92 92 }
93 93  
94   -static void free_fdtable_rcu(struct rcu_head *rcu)
  94 +void free_fdtable_rcu(struct rcu_head *rcu)
95 95 {
96 96 struct fdtable *fdt = container_of(rcu, struct fdtable, rcu);
97 97 int fdset_size, fdarray_size;
98 98  
99 99  
100 100  
... ... @@ -101,20 +101,15 @@
101 101 fdset_size = fdt->max_fds / 8;
102 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
107   - * and the files structure itself was getting destroyed.
108   - * It is now safe to free the files structure.
  106 + * This fdtable is embedded in the files structure and that
  107 + * structure itself is getting destroyed.
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 111 return;
112 112 }
113   - if (fdt->max_fds <= NR_OPEN_DEFAULT)
114   - /*
115   - * The fdtable was embedded
116   - */
117   - return;
118 113 if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) {
119 114 kfree(fdt->open_fds);
120 115 kfree(fdt->close_on_exec);
... ... @@ -132,12 +127,6 @@
132 127 }
133 128 }
134 129  
135   -void 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 131 * Expand the fdset in the files_struct. Called with the files spinlock
143 132 * held for write.
... ... @@ -247,7 +236,6 @@
247 236 goto out;
248 237 fdt->fd = new_fds;
249 238 fdt->max_fds = nfds;
250   - fdt->free_files = NULL;
251 239 return fdt;
252 240 out:
253 241 free_fdset(new_openset, nfds);
... ... @@ -283,7 +271,8 @@
283 271 /* Continue as planned */
284 272 copy_fdtable(new_fdt, cur_fdt);
285 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 276 } else {
288 277 /* Somebody else expanded, so undo our attempt */
289 278 __free_fdtable(new_fdt);
include/linux/file.h
... ... @@ -32,7 +32,6 @@
32 32 fd_set *close_on_exec;
33 33 fd_set *open_fds;
34 34 struct rcu_head rcu;
35   - struct files_struct *free_files;
36 35 struct fdtable *next;
37 36 };
38 37  
... ... @@ -84,7 +83,7 @@
84 83 extern void free_fdset(fd_set *, int);
85 84  
86 85 extern int expand_files(struct files_struct *, int nr);
87   -extern void free_fdtable(struct fdtable *fdt);
  86 +extern void free_fdtable_rcu(struct rcu_head *rcu);
88 87 extern void __init files_defer_init(void);
89 88  
90 89 static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
include/linux/init_task.h
... ... @@ -16,7 +16,6 @@
16 16 .close_on_exec = (fd_set *)&init_files.close_on_exec_init, \
17 17 .open_fds = (fd_set *)&init_files.open_fds_init, \
18 18 .rcu = RCU_HEAD_INIT, \
19   - .free_files = NULL, \
20 19 .next = NULL, \
21 20 }
22 21  
... ... @@ -466,11 +466,9 @@
466 466 * you can free files immediately.
467 467 */
468 468 fdt = files_fdtable(files);
469   - if (fdt == &files->fdtab)
470   - fdt->free_files = files;
471   - else
  469 + if (fdt != &files->fdtab)
472 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  
... ... @@ -645,7 +645,6 @@
645 645 fdt->open_fds = (fd_set *)&newf->open_fds_init;
646 646 fdt->fd = &newf->fd_array[0];
647 647 INIT_RCU_HEAD(&fdt->rcu);
648   - fdt->free_files = NULL;
649 648 fdt->next = NULL;
650 649 rcu_assign_pointer(newf->fdt, fdt);
651 650 out: