Commit 4cac8a28 authored by Andrew Morton's avatar Andrew Morton Committed by Dave Jones

[PATCH] file_table: remove the private freelist

- Remove the private freelist.  There's no point in special-casing file
  structure allocations in this way.

- Hence the freeing of files can be moved outside file_list_lock()

- Replace euid test with capable(CAP_SYS_ADMIN).

- Tidy various other things up.
parent d684d33e
...@@ -22,8 +22,6 @@ struct files_stat_struct files_stat = { ...@@ -22,8 +22,6 @@ struct files_stat_struct files_stat = {
.max_files = NR_FILE .max_files = NR_FILE
}; };
/* list of free filps for root */
static LIST_HEAD(free_list);
/* public *and* exported. Not pretty! */ /* public *and* exported. Not pretty! */
spinlock_t __cacheline_aligned_in_smp files_lock = SPIN_LOCK_UNLOCKED; spinlock_t __cacheline_aligned_in_smp files_lock = SPIN_LOCK_UNLOCKED;
...@@ -52,41 +50,34 @@ void filp_dtor(void * objp, struct kmem_cache_s *cachep, unsigned long dflags) ...@@ -52,41 +50,34 @@ void filp_dtor(void * objp, struct kmem_cache_s *cachep, unsigned long dflags)
spin_unlock_irqrestore(&filp_count_lock, flags); spin_unlock_irqrestore(&filp_count_lock, flags);
} }
static inline void file_free(struct file* f) static inline void file_free(struct file *f)
{ {
if (files_stat.nr_free_files <= NR_RESERVED_FILES) {
list_add(&f->f_list, &free_list);
files_stat.nr_free_files++;
} else {
kmem_cache_free(filp_cachep, f); kmem_cache_free(filp_cachep, f);
}
} }
/* Find an unused file structure and return a pointer to it. /* Find an unused file structure and return a pointer to it.
* Returns NULL, if there are no more free file structures or * Returns NULL, if there are no more free file structures or
* we run out of memory. * we run out of memory.
*
* SMP-safe.
*/ */
struct file * get_empty_filp(void) struct file *get_empty_filp(void)
{ {
static int old_max = 0; static int old_max = 0;
struct file * f; struct file * f;
if (likely(files_stat.nr_files < files_stat.max_files)) { /*
* Privileged users can go above max_files
*/
if (files_stat.nr_files < files_stat.max_files ||
capable(CAP_SYS_ADMIN)) {
f = kmem_cache_alloc(filp_cachep, GFP_KERNEL); f = kmem_cache_alloc(filp_cachep, GFP_KERNEL);
if (f) { if (f) {
got_one:
memset(f, 0, sizeof(*f)); memset(f, 0, sizeof(*f));
if (security_file_alloc(f)) { if (security_file_alloc(f)) {
file_list_lock();
file_free(f); file_free(f);
file_list_unlock(); goto fail;
return NULL;
} }
eventpoll_init_file(f); eventpoll_init_file(f);
atomic_set(&f->f_count,1); atomic_set(&f->f_count, 1);
f->f_uid = current->fsuid; f->f_uid = current->fsuid;
f->f_gid = current->fsgid; f->f_gid = current->fsgid;
f->f_owner.lock = RW_LOCK_UNLOCKED; f->f_owner.lock = RW_LOCK_UNLOCKED;
...@@ -95,24 +86,17 @@ static int old_max = 0; ...@@ -95,24 +86,17 @@ static int old_max = 0;
return f; return f;
} }
} }
/* Use a reserved one if we're the superuser */
file_list_lock();
if (files_stat.nr_free_files && !current->euid) {
f = list_entry(free_list.next, struct file, f_list);
list_del(&f->f_list);
files_stat.nr_free_files--;
file_list_unlock();
goto got_one;
}
file_list_unlock();
/* Ran out of filps - report that */ /* Ran out of filps - report that */
if (files_stat.max_files > old_max) { if (files_stat.max_files >= old_max) {
printk(KERN_INFO "VFS: file-max limit %d reached\n", files_stat.max_files); printk(KERN_INFO "VFS: file-max limit %d reached\n",
files_stat.max_files);
old_max = files_stat.max_files; old_max = files_stat.max_files;
} else { } else {
/* Big problems... */ /* Big problems... */
printk(KERN_WARNING "VFS: filp allocation failed\n"); printk(KERN_WARNING "VFS: filp allocation failed\n");
} }
fail:
return NULL; return NULL;
} }
...@@ -166,11 +150,11 @@ void fput(struct file * file) ...@@ -166,11 +150,11 @@ void fput(struct file * file)
/* __fput is called from task context when aio completion releases the last /* __fput is called from task context when aio completion releases the last
* last use of a struct file *. Do not use otherwise. * last use of a struct file *. Do not use otherwise.
*/ */
void __fput(struct file * file) void __fput(struct file *file)
{ {
struct dentry * dentry = file->f_dentry; struct dentry *dentry = file->f_dentry;
struct vfsmount * mnt = file->f_vfsmnt; struct vfsmount *mnt = file->f_vfsmnt;
struct inode * inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
/* /*
* The function eventpoll_release() should be the first called * The function eventpoll_release() should be the first called
...@@ -189,15 +173,15 @@ void __fput(struct file * file) ...@@ -189,15 +173,15 @@ void __fput(struct file * file)
file->f_dentry = NULL; file->f_dentry = NULL;
file->f_vfsmnt = NULL; file->f_vfsmnt = NULL;
list_del(&file->f_list); list_del(&file->f_list);
file_free(file);
file_list_unlock(); file_list_unlock();
file_free(file);
dput(dentry); dput(dentry);
mntput(mnt); mntput(mnt);
} }
struct file * fget(unsigned int fd) struct file *fget(unsigned int fd)
{ {
struct file * file; struct file *file;
struct files_struct *files = current->files; struct files_struct *files = current->files;
read_lock(&files->file_lock); read_lock(&files->file_lock);
...@@ -208,16 +192,14 @@ struct file * fget(unsigned int fd) ...@@ -208,16 +192,14 @@ struct file * fget(unsigned int fd)
return file; return file;
} }
/* Here. put_filp() is SMP-safe now. */
void put_filp(struct file *file) void put_filp(struct file *file)
{ {
if(atomic_dec_and_test(&file->f_count)) { if (atomic_dec_and_test(&file->f_count)) {
security_file_free(file); security_file_free(file);
file_list_lock(); file_list_lock();
list_del(&file->f_list); list_del(&file->f_list);
file_free(file);
file_list_unlock(); file_list_unlock();
file_free(file);
} }
} }
...@@ -251,7 +233,7 @@ int fs_may_remount_ro(struct super_block *sb) ...@@ -251,7 +233,7 @@ int fs_may_remount_ro(struct super_block *sb)
if (inode->i_nlink == 0) if (inode->i_nlink == 0)
goto too_bad; goto too_bad;
/* Writable file? */ /* Writeable file? */
if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
goto too_bad; goto too_bad;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment