[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>
This commit is contained in:
parent
bbea9f6966
commit
4fd45812cb
27
fs/file.c
27
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);
|
struct fdtable *fdt = container_of(rcu, struct fdtable, rcu);
|
||||||
int fdset_size, fdarray_size;
|
int fdset_size, fdarray_size;
|
||||||
|
@ -101,20 +101,15 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
|
||||||
fdset_size = fdt->max_fds / 8;
|
fdset_size = fdt->max_fds / 8;
|
||||||
fdarray_size = fdt->max_fds * sizeof(struct file *);
|
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
|
* This fdtable is embedded in the files structure and that
|
||||||
* and the files structure itself was getting destroyed.
|
* structure itself is getting destroyed.
|
||||||
* It is now safe to free the files structure.
|
|
||||||
*/
|
*/
|
||||||
kmem_cache_free(files_cachep, fdt->free_files);
|
kmem_cache_free(files_cachep,
|
||||||
|
container_of(fdt, struct files_struct, fdtab));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fdt->max_fds <= NR_OPEN_DEFAULT)
|
|
||||||
/*
|
|
||||||
* The fdtable was embedded
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) {
|
if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) {
|
||||||
kfree(fdt->open_fds);
|
kfree(fdt->open_fds);
|
||||||
kfree(fdt->close_on_exec);
|
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
|
* Expand the fdset in the files_struct. Called with the files spinlock
|
||||||
* held for write.
|
* held for write.
|
||||||
|
@ -247,7 +236,6 @@ static struct fdtable *alloc_fdtable(int nr)
|
||||||
goto out;
|
goto out;
|
||||||
fdt->fd = new_fds;
|
fdt->fd = new_fds;
|
||||||
fdt->max_fds = nfds;
|
fdt->max_fds = nfds;
|
||||||
fdt->free_files = NULL;
|
|
||||||
return fdt;
|
return fdt;
|
||||||
out:
|
out:
|
||||||
free_fdset(new_openset, nfds);
|
free_fdset(new_openset, nfds);
|
||||||
|
@ -283,7 +271,8 @@ static int expand_fdtable(struct files_struct *files, int nr)
|
||||||
/* Continue as planned */
|
/* Continue as planned */
|
||||||
copy_fdtable(new_fdt, cur_fdt);
|
copy_fdtable(new_fdt, cur_fdt);
|
||||||
rcu_assign_pointer(files->fdt, new_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 {
|
} else {
|
||||||
/* Somebody else expanded, so undo our attempt */
|
/* Somebody else expanded, so undo our attempt */
|
||||||
__free_fdtable(new_fdt);
|
__free_fdtable(new_fdt);
|
||||||
|
|
|
@ -32,7 +32,6 @@ struct fdtable {
|
||||||
fd_set *close_on_exec;
|
fd_set *close_on_exec;
|
||||||
fd_set *open_fds;
|
fd_set *open_fds;
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
struct files_struct *free_files;
|
|
||||||
struct fdtable *next;
|
struct fdtable *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ extern fd_set *alloc_fdset(int);
|
||||||
extern void free_fdset(fd_set *, int);
|
extern void free_fdset(fd_set *, int);
|
||||||
|
|
||||||
extern int expand_files(struct files_struct *, int nr);
|
extern int expand_files(struct files_struct *, int nr);
|
||||||
extern void free_fdtable(struct fdtable *fdt);
|
extern void free_fdtable_rcu(struct rcu_head *rcu);
|
||||||
extern void __init files_defer_init(void);
|
extern void __init files_defer_init(void);
|
||||||
|
|
||||||
static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
|
static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
.close_on_exec = (fd_set *)&init_files.close_on_exec_init, \
|
.close_on_exec = (fd_set *)&init_files.close_on_exec_init, \
|
||||||
.open_fds = (fd_set *)&init_files.open_fds_init, \
|
.open_fds = (fd_set *)&init_files.open_fds_init, \
|
||||||
.rcu = RCU_HEAD_INIT, \
|
.rcu = RCU_HEAD_INIT, \
|
||||||
.free_files = NULL, \
|
|
||||||
.next = NULL, \
|
.next = NULL, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -466,11 +466,9 @@ void fastcall put_files_struct(struct files_struct *files)
|
||||||
* you can free files immediately.
|
* you can free files immediately.
|
||||||
*/
|
*/
|
||||||
fdt = files_fdtable(files);
|
fdt = files_fdtable(files);
|
||||||
if (fdt == &files->fdtab)
|
if (fdt != &files->fdtab)
|
||||||
fdt->free_files = files;
|
|
||||||
else
|
|
||||||
kmem_cache_free(files_cachep, files);
|
kmem_cache_free(files_cachep, files);
|
||||||
free_fdtable(fdt);
|
call_rcu(&fdt->rcu, free_fdtable_rcu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -645,7 +645,6 @@ static struct files_struct *alloc_files(void)
|
||||||
fdt->open_fds = (fd_set *)&newf->open_fds_init;
|
fdt->open_fds = (fd_set *)&newf->open_fds_init;
|
||||||
fdt->fd = &newf->fd_array[0];
|
fdt->fd = &newf->fd_array[0];
|
||||||
INIT_RCU_HEAD(&fdt->rcu);
|
INIT_RCU_HEAD(&fdt->rcu);
|
||||||
fdt->free_files = NULL;
|
|
||||||
fdt->next = NULL;
|
fdt->next = NULL;
|
||||||
rcu_assign_pointer(newf->fdt, fdt);
|
rcu_assign_pointer(newf->fdt, fdt);
|
||||||
out:
|
out:
|
||||||
|
|
Loading…
Reference in New Issue