diff options
Diffstat (limited to 'fs/file_table.c')
| -rw-r--r-- | fs/file_table.c | 320 |
1 files changed, 144 insertions, 176 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index 986ff4ed0a7..385bfd31512 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -8,6 +8,7 @@ #include <linux/string.h> #include <linux/slab.h> #include <linux/file.h> +#include <linux/fdtable.h> #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> @@ -19,23 +20,32 @@ #include <linux/cdev.h> #include <linux/fsnotify.h> #include <linux/sysctl.h> +#include <linux/lglock.h> #include <linux/percpu_counter.h> +#include <linux/percpu.h> +#include <linux/hardirq.h> +#include <linux/task_work.h> +#include <linux/ima.h> -#include <asm/atomic.h> +#include <linux/atomic.h> + +#include "internal.h" /* sysctl tunables... */ struct files_stat_struct files_stat = { .max_files = NR_FILE }; -/* public. Not pretty! */ -__cacheline_aligned_in_smp DEFINE_SPINLOCK(files_lock); +/* SLAB cache for file structures */ +static struct kmem_cache *filp_cachep __read_mostly; static struct percpu_counter nr_files __cacheline_aligned_in_smp; -static inline void file_free_rcu(struct rcu_head *head) +static void file_free_rcu(struct rcu_head *head) { - struct file *f = container_of(head, struct file, f_u.fu_rcuhead); + struct file *f = container_of(head, struct file, f_u.fu_rcuhead); + + put_cred(f->f_cred); kmem_cache_free(filp_cachep, f); } @@ -48,7 +58,7 @@ static inline void file_free(struct file *f) /* * Return the total number of open files in the system */ -static int get_nr_files(void) +static long get_nr_files(void) { return percpu_counter_read_positive(&nr_files); } @@ -56,7 +66,7 @@ static int get_nr_files(void) /* * Return the maximum number of open files in the system */ -int get_max_files(void) +unsigned long get_max_files(void) { return files_stat.max_files; } @@ -66,14 +76,14 @@ EXPORT_SYMBOL_GPL(get_max_files); * Handle nr_files sysctl */ #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) -int proc_nr_files(ctl_table *table, int write, struct file *filp, +int proc_nr_files(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { files_stat.nr_files = get_nr_files(); - return proc_dointvec(table, write, filp, buffer, lenp, ppos); + return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); } #else -int proc_nr_files(ctl_table *table, int write, struct file *filp, +int proc_nr_files(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { return -ENOSYS; @@ -81,8 +91,8 @@ int proc_nr_files(ctl_table *table, int write, struct file *filp, #endif /* Find an unused file structure and return a pointer to it. - * Returns NULL, if there are no more free file structures or - * we run out of memory. + * Returns an error pointer if some error happend e.g. we over file + * structures limit, run out of memory or operation is not permitted. * * Be very careful using this. You are responsible for * getting write access to any mount that you might assign @@ -92,9 +102,10 @@ int proc_nr_files(ctl_table *table, int write, struct file *filp, */ struct file *get_empty_filp(void) { - struct task_struct *tsk; - static int old_max; - struct file * f; + const struct cred *cred = current_cred(); + static long old_max; + struct file *f; + int error; /* * Privileged users can go above max_files @@ -109,19 +120,21 @@ struct file *get_empty_filp(void) } f = kmem_cache_zalloc(filp_cachep, GFP_KERNEL); - if (f == NULL) - goto fail; + if (unlikely(!f)) + return ERR_PTR(-ENOMEM); percpu_counter_inc(&nr_files); - if (security_file_alloc(f)) - goto fail_sec; + f->f_cred = get_cred(cred); + error = security_file_alloc(f); + if (unlikely(error)) { + file_free(f); + return ERR_PTR(error); + } - tsk = current; - INIT_LIST_HEAD(&f->f_u.fu_list); - atomic_set(&f->f_count, 1); + atomic_long_set(&f->f_count, 1); rwlock_init(&f->f_owner.lock); - f->f_uid = tsk->fsuid; - f->f_gid = tsk->fsgid; + spin_lock_init(&f->f_lock); + mutex_init(&f->f_pos_lock); eventpoll_init_file(f); /* f->f_version: 0 */ return f; @@ -129,20 +142,12 @@ struct file *get_empty_filp(void) over: /* Ran out of filps - report that */ if (get_nr_files() > old_max) { - printk(KERN_INFO "VFS: file-max limit %d reached\n", - get_max_files()); + pr_info("VFS: file-max limit %lu reached\n", get_max_files()); old_max = get_nr_files(); } - goto fail; - -fail_sec: - file_free(f); -fail: - return NULL; + return ERR_PTR(-ENFILE); } -EXPORT_SYMBOL(get_empty_filp); - /** * alloc_file - allocate and initialize a 'struct file' * @mnt: the vfsmount on which the file will reside @@ -158,67 +163,39 @@ EXPORT_SYMBOL(get_empty_filp); * If all the callers of init_file() are eliminated, its * code should be moved into this function. */ -struct file *alloc_file(struct vfsmount *mnt, struct dentry *dentry, - mode_t mode, const struct file_operations *fop) +struct file *alloc_file(struct path *path, fmode_t mode, + const struct file_operations *fop) { struct file *file; - struct path; file = get_empty_filp(); - if (!file) - return NULL; - - init_file(file, mnt, dentry, mode, fop); - return file; -} -EXPORT_SYMBOL(alloc_file); - -/** - * init_file - initialize a 'struct file' - * @file: the already allocated 'struct file' to initialized - * @mnt: the vfsmount on which the file resides - * @dentry: the dentry representing this file - * @mode: the mode the file is opened with - * @fop: the 'struct file_operations' for this file - * - * Use this instead of setting the members directly. Doing so - * avoids making mistakes like forgetting the mntget() or - * forgetting to take a write on the mnt. - * - * Note: This is a crappy interface. It is here to make - * merging with the existing users of get_empty_filp() - * who have complex failure logic easier. All users - * of this should be moving to alloc_file(). - */ -int init_file(struct file *file, struct vfsmount *mnt, struct dentry *dentry, - mode_t mode, const struct file_operations *fop) -{ - int error = 0; - file->f_path.dentry = dentry; - file->f_path.mnt = mntget(mnt); - file->f_mapping = dentry->d_inode->i_mapping; + if (IS_ERR(file)) + return file; + + file->f_path = *path; + file->f_inode = path->dentry->d_inode; + file->f_mapping = path->dentry->d_inode->i_mapping; + if ((mode & FMODE_READ) && + likely(fop->read || fop->aio_read || fop->read_iter)) + mode |= FMODE_CAN_READ; + if ((mode & FMODE_WRITE) && + likely(fop->write || fop->aio_write || fop->write_iter)) + mode |= FMODE_CAN_WRITE; file->f_mode = mode; file->f_op = fop; - return error; -} -EXPORT_SYMBOL(init_file); - -void fput(struct file *file) -{ - if (atomic_dec_and_test(&file->f_count)) - __fput(file); + if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) + i_readcount_inc(path->dentry->d_inode); + return file; } +EXPORT_SYMBOL(alloc_file); -EXPORT_SYMBOL(fput); - -/* __fput is called from task context when aio completion releases the last - * last use of a struct file *. Do not use otherwise. +/* the real guts of fput() - releasing the last reference to file */ -void __fput(struct file *file) +static void __fput(struct file *file) { struct dentry *dentry = file->f_path.dentry; struct vfsmount *mnt = file->f_path.mnt; - struct inode *inode = dentry->d_inode; + struct inode *inode = file->f_inode; might_sleep(); @@ -228,140 +205,131 @@ void __fput(struct file *file) * in the file cleanup chain. */ eventpoll_release(file); - locks_remove_flock(file); + locks_remove_file(file); - if (file->f_op && file->f_op->release) + if (unlikely(file->f_flags & FASYNC)) { + if (file->f_op->fasync) + file->f_op->fasync(-1, file, 0); + } + ima_file_free(file); + if (file->f_op->release) file->f_op->release(inode, file); security_file_free(file); - if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL)) + if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL && + !(file->f_mode & FMODE_PATH))) { cdev_put(inode->i_cdev); + } fops_put(file->f_op); - if (file->f_mode & FMODE_WRITE) - put_write_access(inode); put_pid(file->f_owner.pid); - file_kill(file); + if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) + i_readcount_dec(inode); + if (file->f_mode & FMODE_WRITER) { + put_write_access(inode); + __mnt_drop_write(mnt); + } file->f_path.dentry = NULL; file->f_path.mnt = NULL; + file->f_inode = NULL; file_free(file); dput(dentry); mntput(mnt); } -struct file *fget(unsigned int fd) +static LLIST_HEAD(delayed_fput_list); +static void delayed_fput(struct work_struct *unused) { - struct file *file; - struct files_struct *files = current->files; - - rcu_read_lock(); - file = fcheck_files(files, fd); - if (file) { - if (!atomic_inc_not_zero(&file->f_count)) { - /* File object ref couldn't be taken */ - rcu_read_unlock(); - return NULL; - } - } - rcu_read_unlock(); + struct llist_node *node = llist_del_all(&delayed_fput_list); + struct llist_node *next; - return file; + for (; node; node = next) { + next = llist_next(node); + __fput(llist_entry(node, struct file, f_u.fu_llist)); + } } -EXPORT_SYMBOL(fget); +static void ____fput(struct callback_head *work) +{ + __fput(container_of(work, struct file, f_u.fu_rcuhead)); +} /* - * Lightweight file lookup - no refcnt increment if fd table isn't shared. - * You can use this only if it is guranteed that the current task already - * holds a refcnt to that file. That check has to be done at fget() only - * and a flag is returned to be passed to the corresponding fput_light(). - * There must not be a cloning between an fget_light/fput_light pair. + * If kernel thread really needs to have the final fput() it has done + * to complete, call this. The only user right now is the boot - we + * *do* need to make sure our writes to binaries on initramfs has + * not left us with opened struct file waiting for __fput() - execve() + * won't work without that. Please, don't add more callers without + * very good reasons; in particular, never call that with locks + * held and never call that from a thread that might need to do + * some work on any kind of umount. */ -struct file *fget_light(unsigned int fd, int *fput_needed) +void flush_delayed_fput(void) { - struct file *file; - struct files_struct *files = current->files; - - *fput_needed = 0; - if (likely((atomic_read(&files->count) == 1))) { - file = fcheck_files(files, fd); - } else { - rcu_read_lock(); - file = fcheck_files(files, fd); - if (file) { - if (atomic_inc_not_zero(&file->f_count)) - *fput_needed = 1; - else - /* Didn't get the reference, someone's freed */ - file = NULL; - } - rcu_read_unlock(); - } - - return file; + delayed_fput(NULL); } +static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); -void put_filp(struct file *file) +void fput(struct file *file) { - if (atomic_dec_and_test(&file->f_count)) { - security_file_free(file); - file_kill(file); - file_free(file); - } -} + if (atomic_long_dec_and_test(&file->f_count)) { + struct task_struct *task = current; + + if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) { + init_task_work(&file->f_u.fu_rcuhead, ____fput); + if (!task_work_add(task, &file->f_u.fu_rcuhead, true)) + return; + /* + * After this task has run exit_task_work(), + * task_work_add() will fail. Fall through to delayed + * fput to avoid leaking *file. + */ + } -void file_move(struct file *file, struct list_head *list) -{ - if (!list) - return; - file_list_lock(); - list_move(&file->f_u.fu_list, list); - file_list_unlock(); + if (llist_add(&file->f_u.fu_llist, &delayed_fput_list)) + schedule_delayed_work(&delayed_fput_work, 1); + } } -void file_kill(struct file *file) +/* + * synchronous analog of fput(); for kernel threads that might be needed + * in some umount() (and thus can't use flush_delayed_fput() without + * risking deadlocks), need to wait for completion of __fput() and know + * for this specific struct file it won't involve anything that would + * need them. Use only if you really need it - at the very least, + * don't blindly convert fput() by kernel thread to that. + */ +void __fput_sync(struct file *file) { - if (!list_empty(&file->f_u.fu_list)) { - file_list_lock(); - list_del_init(&file->f_u.fu_list); - file_list_unlock(); + if (atomic_long_dec_and_test(&file->f_count)) { + struct task_struct *task = current; + BUG_ON(!(task->flags & PF_KTHREAD)); + __fput(file); } } -int fs_may_remount_ro(struct super_block *sb) -{ - struct file *file; - - /* Check that no files are currently opened for writing. */ - file_list_lock(); - list_for_each_entry(file, &sb->s_files, f_u.fu_list) { - struct inode *inode = file->f_path.dentry->d_inode; - - /* File with pending delete? */ - if (inode->i_nlink == 0) - goto too_bad; +EXPORT_SYMBOL(fput); - /* Writeable file? */ - if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE)) - goto too_bad; +void put_filp(struct file *file) +{ + if (atomic_long_dec_and_test(&file->f_count)) { + security_file_free(file); + file_free(file); } - file_list_unlock(); - return 1; /* Tis' cool bro. */ -too_bad: - file_list_unlock(); - return 0; } void __init files_init(unsigned long mempages) { - int n; - /* One file with associated inode and dcache is very roughly 1K. + unsigned long n; + + filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, + SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); + + /* + * One file with associated inode and dcache is very roughly 1K. * Per default don't use more than 10% of our memory for files. */ n = (mempages * (PAGE_SIZE / 1024)) / 10; - files_stat.max_files = n; - if (files_stat.max_files < NR_FILE) - files_stat.max_files = NR_FILE; - files_defer_init(); + files_stat.max_files = max_t(unsigned long, n, NR_FILE); percpu_counter_init(&nr_files, 0); } |
