From 4fd45812cbe875a620c86a096a5d46c742694b7e Mon Sep 17 00:00:00 2001 From: Vadim Lobanov Date: Sun, 10 Dec 2006 02:21:17 -0800 Subject: [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 Cc: Christoph Hellwig Cc: Al Viro Cc: Dipankar Sarma Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/file.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) (limited to 'fs/file.c') diff --git a/fs/file.c b/fs/file.c index fb3d2038dc2..17e6a55521e 100644 --- a/fs/file.c +++ b/fs/file.c @@ -91,7 +91,7 @@ static void free_fdtable_work(struct work_struct *work) } } -static void free_fdtable_rcu(struct rcu_head *rcu) +void free_fdtable_rcu(struct rcu_head *rcu) { struct fdtable *fdt = container_of(rcu, struct fdtable, rcu); int fdset_size, fdarray_size; @@ -101,20 +101,15 @@ static void free_fdtable_rcu(struct rcu_head *rcu) fdset_size = fdt->max_fds / 8; fdarray_size = fdt->max_fds * sizeof(struct file *); - if (fdt->free_files) { + if (fdt->max_fds <= NR_OPEN_DEFAULT) { /* - * The this fdtable was embedded in the files structure - * and the files structure itself was getting destroyed. - * It is now safe to free the files structure. + * This fdtable is embedded in the files structure and that + * structure itself is getting destroyed. */ - kmem_cache_free(files_cachep, fdt->free_files); + kmem_cache_free(files_cachep, + container_of(fdt, struct files_struct, fdtab)); return; } - if (fdt->max_fds <= NR_OPEN_DEFAULT) - /* - * The fdtable was embedded - */ - return; if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) { kfree(fdt->open_fds); kfree(fdt->close_on_exec); @@ -132,12 +127,6 @@ static void free_fdtable_rcu(struct rcu_head *rcu) } } -void free_fdtable(struct fdtable *fdt) -{ - if (fdt->free_files || fdt->max_fds > NR_OPEN_DEFAULT) - call_rcu(&fdt->rcu, free_fdtable_rcu); -} - /* * Expand the fdset in the files_struct. Called with the files spinlock * held for write. @@ -247,7 +236,6 @@ static struct fdtable *alloc_fdtable(int nr) goto out; fdt->fd = new_fds; fdt->max_fds = nfds; - fdt->free_files = NULL; return fdt; out: free_fdset(new_openset, nfds); @@ -283,7 +271,8 @@ static int expand_fdtable(struct files_struct *files, int nr) /* Continue as planned */ copy_fdtable(new_fdt, cur_fdt); rcu_assign_pointer(files->fdt, new_fdt); - free_fdtable(cur_fdt); + if (cur_fdt->max_fds > NR_OPEN_DEFAULT) + call_rcu(&cur_fdt->rcu, free_fdtable_rcu); } else { /* Somebody else expanded, so undo our attempt */ __free_fdtable(new_fdt); -- cgit v1.2.3