forked from mirrors/linux
		
	get rid of the magic around f_count in aio
__aio_put_req() plays sick games with file refcount. What it wants is fput() from atomic context; it's almost always done with f_count > 1, so they only have to deal with delayed work in rare cases when their reference happens to be the last one. Current code decrements f_count and if it hasn't hit 0, everything is fine. Otherwise it keeps a pointer to struct file (with zero f_count!) around and has delayed work do __fput() on it. Better way to do it: use atomic_long_add_unless( , -1, 1) instead of !atomic_long_dec_and_test(). IOW, decrement it only if it's not the last reference, leave refcount alone if it was. And use normal fput() in delayed work. I've made that atomic_long_add_unless call a new helper - fput_atomic(). Drops a reference to file if it's safe to do in atomic (i.e. if that's not the last one), tells if it had been able to do that. aio.c converted to it, __fput() use is gone. req->ki_file *always* contributes to refcount now. And __fput() became static. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									176306f59a
								
							
						
					
					
						commit
						d7065da038
					
				
					 4 changed files with 14 additions and 15 deletions
				
			
		
							
								
								
									
										6
									
								
								fs/aio.c
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								fs/aio.c
									
									
									
									
									
								
							|  | @ -527,7 +527,7 @@ static void aio_fput_routine(struct work_struct *data) | ||||||
| 
 | 
 | ||||||
| 		/* Complete the fput(s) */ | 		/* Complete the fput(s) */ | ||||||
| 		if (req->ki_filp != NULL) | 		if (req->ki_filp != NULL) | ||||||
| 			__fput(req->ki_filp); | 			fput(req->ki_filp); | ||||||
| 
 | 
 | ||||||
| 		/* Link the iocb into the context's free list */ | 		/* Link the iocb into the context's free list */ | ||||||
| 		spin_lock_irq(&ctx->ctx_lock); | 		spin_lock_irq(&ctx->ctx_lock); | ||||||
|  | @ -560,11 +560,11 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Try to optimize the aio and eventfd file* puts, by avoiding to | 	 * Try to optimize the aio and eventfd file* puts, by avoiding to | ||||||
| 	 * schedule work in case it is not __fput() time. In normal cases, | 	 * schedule work in case it is not final fput() time. In normal cases, | ||||||
| 	 * we would not be holding the last reference to the file*, so | 	 * we would not be holding the last reference to the file*, so | ||||||
| 	 * this function will be executed w/out any aio kthread wakeup. | 	 * this function will be executed w/out any aio kthread wakeup. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) { | 	if (unlikely(!fput_atomic(req->ki_filp))) { | ||||||
| 		get_ioctx(ctx); | 		get_ioctx(ctx); | ||||||
| 		spin_lock(&fput_lock); | 		spin_lock(&fput_lock); | ||||||
| 		list_add(&req->ki_list, &fput_head); | 		list_add(&req->ki_list, &fput_head); | ||||||
|  |  | ||||||
|  | @ -194,14 +194,6 @@ struct file *alloc_file(struct path *path, fmode_t mode, | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(alloc_file); | EXPORT_SYMBOL(alloc_file); | ||||||
| 
 | 
 | ||||||
| void fput(struct file *file) |  | ||||||
| { |  | ||||||
| 	if (atomic_long_dec_and_test(&file->f_count)) |  | ||||||
| 		__fput(file); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| EXPORT_SYMBOL(fput); |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * drop_file_write_access - give up ability to write to a file |  * drop_file_write_access - give up ability to write to a file | ||||||
|  * @file: the file to which we will stop writing |  * @file: the file to which we will stop writing | ||||||
|  | @ -227,10 +219,9 @@ void drop_file_write_access(struct file *file) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(drop_file_write_access); | EXPORT_SYMBOL_GPL(drop_file_write_access); | ||||||
| 
 | 
 | ||||||
| /* __fput is called from task context when aio completion releases the last
 | /* the real guts of fput() - releasing the last reference to file
 | ||||||
|  * last use of a struct file *.  Do not use otherwise. |  | ||||||
|  */ |  */ | ||||||
| void __fput(struct file *file) | static void __fput(struct file *file) | ||||||
| { | { | ||||||
| 	struct dentry *dentry = file->f_path.dentry; | 	struct dentry *dentry = file->f_path.dentry; | ||||||
| 	struct vfsmount *mnt = file->f_path.mnt; | 	struct vfsmount *mnt = file->f_path.mnt; | ||||||
|  | @ -268,6 +259,14 @@ void __fput(struct file *file) | ||||||
| 	mntput(mnt); | 	mntput(mnt); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void fput(struct file *file) | ||||||
|  | { | ||||||
|  | 	if (atomic_long_dec_and_test(&file->f_count)) | ||||||
|  | 		__fput(file); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | EXPORT_SYMBOL(fput); | ||||||
|  | 
 | ||||||
| struct file *fget(unsigned int fd) | struct file *fget(unsigned int fd) | ||||||
| { | { | ||||||
| 	struct file *file; | 	struct file *file; | ||||||
|  |  | ||||||
|  | @ -11,7 +11,6 @@ | ||||||
| 
 | 
 | ||||||
| struct file; | struct file; | ||||||
| 
 | 
 | ||||||
| extern void __fput(struct file *); |  | ||||||
| extern void fput(struct file *); | extern void fput(struct file *); | ||||||
| extern void drop_file_write_access(struct file *file); | extern void drop_file_write_access(struct file *file); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -954,6 +954,7 @@ extern spinlock_t files_lock; | ||||||
| #define file_list_unlock() spin_unlock(&files_lock); | #define file_list_unlock() spin_unlock(&files_lock); | ||||||
| 
 | 
 | ||||||
| #define get_file(x)	atomic_long_inc(&(x)->f_count) | #define get_file(x)	atomic_long_inc(&(x)->f_count) | ||||||
|  | #define fput_atomic(x)	atomic_long_add_unless(&(x)->f_count, -1, 1) | ||||||
| #define file_count(x)	atomic_long_read(&(x)->f_count) | #define file_count(x)	atomic_long_read(&(x)->f_count) | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_DEBUG_WRITECOUNT | #ifdef CONFIG_DEBUG_WRITECOUNT | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Al Viro
						Al Viro