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) */ | ||||
| 		if (req->ki_filp != NULL) | ||||
| 			__fput(req->ki_filp); | ||||
| 			fput(req->ki_filp); | ||||
| 
 | ||||
| 		/* Link the iocb into the context's free list */ | ||||
| 		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 | ||||
| 	 * 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 | ||||
| 	 * 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); | ||||
| 		spin_lock(&fput_lock); | ||||
| 		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); | ||||
| 
 | ||||
| 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 | ||||
|  * @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); | ||||
| 
 | ||||
| /* __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; | ||||
|  | @ -268,6 +259,14 @@ void __fput(struct file *file) | |||
| 	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 *file; | ||||
|  |  | |||
|  | @ -11,7 +11,6 @@ | |||
| 
 | ||||
| struct file; | ||||
| 
 | ||||
| extern void __fput(struct file *); | ||||
| extern void fput(struct 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 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) | ||||
| 
 | ||||
| #ifdef CONFIG_DEBUG_WRITECOUNT | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Al Viro
						Al Viro