diff options
Diffstat (limited to 'fs/file_table.c')
| -rw-r--r-- | fs/file_table.c | 189 | 
1 files changed, 18 insertions, 171 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index abdd15ad13c..385bfd31512 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -36,8 +36,6 @@ struct files_stat_struct files_stat = {  	.max_files = NR_FILE  }; -DEFINE_STATIC_LGLOCK(files_lglock); -  /* SLAB cache for file structures */  static struct kmem_cache *filp_cachep __read_mostly; @@ -54,7 +52,6 @@ static void file_free_rcu(struct rcu_head *head)  static inline void file_free(struct file *f)  {  	percpu_counter_dec(&nr_files); -	file_check_state(f);  	call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);  } @@ -79,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, +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_doulongvec_minmax(table, write, buffer, lenp, ppos);  }  #else -int proc_nr_files(ctl_table *table, int write, +int proc_nr_files(struct ctl_table *table, int write,                       void __user *buffer, size_t *lenp, loff_t *ppos)  {  	return -ENOSYS; @@ -134,10 +131,10 @@ struct file *get_empty_filp(void)  		return ERR_PTR(error);  	} -	INIT_LIST_HEAD(&f->f_u.fu_list);  	atomic_long_set(&f->f_count, 1);  	rwlock_init(&f->f_owner.lock);  	spin_lock_init(&f->f_lock); +	mutex_init(&f->f_pos_lock);  	eventpoll_init_file(f);  	/* f->f_version: 0 */  	return f; @@ -178,49 +175,20 @@ struct file *alloc_file(struct path *path, fmode_t mode,  	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; - -	/* -	 * These mounts don't really matter in practice -	 * for r/o bind mounts.  They aren't userspace- -	 * visible.  We do this for consistency, and so -	 * that we can do debugging checks at __fput() -	 */ -	if ((mode & FMODE_WRITE) && !special_file(path->dentry->d_inode->i_mode)) { -		file_take_write(file); -		WARN_ON(mnt_clone_write(path->mnt)); -	}  	if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)  		i_readcount_inc(path->dentry->d_inode);  	return file;  }  EXPORT_SYMBOL(alloc_file); -/** - * drop_file_write_access - give up ability to write to a file - * @file: the file to which we will stop writing - * - * This is a central place which will give up the ability - * to write to @file, along with access to write through - * its vfsmount. - */ -static void drop_file_write_access(struct file *file) -{ -	struct vfsmount *mnt = file->f_path.mnt; -	struct dentry *dentry = file->f_path.dentry; -	struct inode *inode = dentry->d_inode; - -	put_write_access(inode); - -	if (special_file(inode->i_mode)) -		return; -	if (file_check_writeable(file) != 0) -		return; -	__mnt_drop_write(mnt); -	file_release_write(file); -} -  /* the real guts of fput() - releasing the last reference to file   */  static void __fput(struct file *file) @@ -237,14 +205,14 @@ static void __fput(struct file *file)  	 * in the file cleanup chain.  	 */  	eventpoll_release(file); -	locks_remove_flock(file); +	locks_remove_file(file);  	if (unlikely(file->f_flags & FASYNC)) { -		if (file->f_op && file->f_op->fasync) +		if (file->f_op->fasync)  			file->f_op->fasync(-1, file, 0);  	}  	ima_file_free(file); -	if (file->f_op && file->f_op->release) +	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 && @@ -255,8 +223,10 @@ static void __fput(struct file *file)  	put_pid(file->f_owner.pid);  	if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)  		i_readcount_dec(inode); -	if (file->f_mode & FMODE_WRITE) -		drop_file_write_access(file); +	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; @@ -297,14 +267,13 @@ void flush_delayed_fput(void)  	delayed_fput(NULL);  } -static DECLARE_WORK(delayed_fput_work, delayed_fput); +static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput);  void fput(struct file *file)  {  	if (atomic_long_dec_and_test(&file->f_count)) {  		struct task_struct *task = current; -		file_sb_list_del(file);  		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)) @@ -317,7 +286,7 @@ void fput(struct file *file)  		}  		if (llist_add(&file->f_u.fu_llist, &delayed_fput_list)) -			schedule_work(&delayed_fput_work); +			schedule_delayed_work(&delayed_fput_work, 1);  	}  } @@ -333,7 +302,6 @@ void __fput_sync(struct file *file)  {  	if (atomic_long_dec_and_test(&file->f_count)) {  		struct task_struct *task = current; -		file_sb_list_del(file);  		BUG_ON(!(task->flags & PF_KTHREAD));  		__fput(file);  	} @@ -345,129 +313,10 @@ void put_filp(struct file *file)  {  	if (atomic_long_dec_and_test(&file->f_count)) {  		security_file_free(file); -		file_sb_list_del(file);  		file_free(file);  	}  } -static inline int file_list_cpu(struct file *file) -{ -#ifdef CONFIG_SMP -	return file->f_sb_list_cpu; -#else -	return smp_processor_id(); -#endif -} - -/* helper for file_sb_list_add to reduce ifdefs */ -static inline void __file_sb_list_add(struct file *file, struct super_block *sb) -{ -	struct list_head *list; -#ifdef CONFIG_SMP -	int cpu; -	cpu = smp_processor_id(); -	file->f_sb_list_cpu = cpu; -	list = per_cpu_ptr(sb->s_files, cpu); -#else -	list = &sb->s_files; -#endif -	list_add(&file->f_u.fu_list, list); -} - -/** - * file_sb_list_add - add a file to the sb's file list - * @file: file to add - * @sb: sb to add it to - * - * Use this function to associate a file with the superblock of the inode it - * refers to. - */ -void file_sb_list_add(struct file *file, struct super_block *sb) -{ -	if (likely(!(file->f_mode & FMODE_WRITE))) -		return; -	if (!S_ISREG(file_inode(file)->i_mode)) -		return; -	lg_local_lock(&files_lglock); -	__file_sb_list_add(file, sb); -	lg_local_unlock(&files_lglock); -} - -/** - * file_sb_list_del - remove a file from the sb's file list - * @file: file to remove - * @sb: sb to remove it from - * - * Use this function to remove a file from its superblock. - */ -void file_sb_list_del(struct file *file) -{ -	if (!list_empty(&file->f_u.fu_list)) { -		lg_local_lock_cpu(&files_lglock, file_list_cpu(file)); -		list_del_init(&file->f_u.fu_list); -		lg_local_unlock_cpu(&files_lglock, file_list_cpu(file)); -	} -} - -#ifdef CONFIG_SMP - -/* - * These macros iterate all files on all CPUs for a given superblock. - * files_lglock must be held globally. - */ -#define do_file_list_for_each_entry(__sb, __file)		\ -{								\ -	int i;							\ -	for_each_possible_cpu(i) {				\ -		struct list_head *list;				\ -		list = per_cpu_ptr((__sb)->s_files, i);		\ -		list_for_each_entry((__file), list, f_u.fu_list) - -#define while_file_list_for_each_entry				\ -	}							\ -} - -#else - -#define do_file_list_for_each_entry(__sb, __file)		\ -{								\ -	struct list_head *list;					\ -	list = &(sb)->s_files;					\ -	list_for_each_entry((__file), list, f_u.fu_list) - -#define while_file_list_for_each_entry				\ -} - -#endif - -/** - *	mark_files_ro - mark all files read-only - *	@sb: superblock in question - * - *	All files are marked read-only.  We don't care about pending - *	delete files so this should be used in 'force' mode only. - */ -void mark_files_ro(struct super_block *sb) -{ -	struct file *f; - -	lg_global_lock(&files_lglock); -	do_file_list_for_each_entry(sb, f) { -		if (!file_count(f)) -			continue; -		if (!(f->f_mode & FMODE_WRITE)) -			continue; -		spin_lock(&f->f_lock); -		f->f_mode &= ~FMODE_WRITE; -		spin_unlock(&f->f_lock); -		if (file_check_writeable(f) != 0) -			continue; -		__mnt_drop_write(f->f_path.mnt); -		file_release_write(f); -	} while_file_list_for_each_entry; -	lg_global_unlock(&files_lglock); -} -  void __init files_init(unsigned long mempages)  {   	unsigned long n; @@ -482,7 +331,5 @@ void __init files_init(unsigned long mempages)  	n = (mempages * (PAGE_SIZE / 1024)) / 10;  	files_stat.max_files = max_t(unsigned long, n, NR_FILE); -	files_defer_init(); -	lg_lock_init(&files_lglock, "files_lglock");  	percpu_counter_init(&nr_files, 0);  }   | 
