Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os 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>

Al Viro d7065da0 176306f5

+14 -15
+3 -3
fs/aio.c
··· 527 527 528 528 /* Complete the fput(s) */ 529 529 if (req->ki_filp != NULL) 530 - __fput(req->ki_filp); 530 + fput(req->ki_filp); 531 531 532 532 /* Link the iocb into the context's free list */ 533 533 spin_lock_irq(&ctx->ctx_lock); ··· 560 560 561 561 /* 562 562 * Try to optimize the aio and eventfd file* puts, by avoiding to 563 - * schedule work in case it is not __fput() time. In normal cases, 563 + * schedule work in case it is not final fput() time. In normal cases, 564 564 * we would not be holding the last reference to the file*, so 565 565 * this function will be executed w/out any aio kthread wakeup. 566 566 */ 567 - if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) { 567 + if (unlikely(!fput_atomic(req->ki_filp))) { 568 568 get_ioctx(ctx); 569 569 spin_lock(&fput_lock); 570 570 list_add(&req->ki_list, &fput_head);
+10 -11
fs/file_table.c
··· 194 194 } 195 195 EXPORT_SYMBOL(alloc_file); 196 196 197 - void fput(struct file *file) 198 - { 199 - if (atomic_long_dec_and_test(&file->f_count)) 200 - __fput(file); 201 - } 202 - 203 - EXPORT_SYMBOL(fput); 204 - 205 197 /** 206 198 * drop_file_write_access - give up ability to write to a file 207 199 * @file: the file to which we will stop writing ··· 219 227 } 220 228 EXPORT_SYMBOL_GPL(drop_file_write_access); 221 229 222 - /* __fput is called from task context when aio completion releases the last 223 - * last use of a struct file *. Do not use otherwise. 230 + /* the real guts of fput() - releasing the last reference to file 224 231 */ 225 - void __fput(struct file *file) 232 + static void __fput(struct file *file) 226 233 { 227 234 struct dentry *dentry = file->f_path.dentry; 228 235 struct vfsmount *mnt = file->f_path.mnt; ··· 258 267 dput(dentry); 259 268 mntput(mnt); 260 269 } 270 + 271 + void fput(struct file *file) 272 + { 273 + if (atomic_long_dec_and_test(&file->f_count)) 274 + __fput(file); 275 + } 276 + 277 + EXPORT_SYMBOL(fput); 261 278 262 279 struct file *fget(unsigned int fd) 263 280 {
-1
include/linux/file.h
··· 11 11 12 12 struct file; 13 13 14 - extern void __fput(struct file *); 15 14 extern void fput(struct file *); 16 15 extern void drop_file_write_access(struct file *file); 17 16
+1
include/linux/fs.h
··· 954 954 #define file_list_unlock() spin_unlock(&files_lock); 955 955 956 956 #define get_file(x) atomic_long_inc(&(x)->f_count) 957 + #define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1) 957 958 #define file_count(x) atomic_long_read(&(x)->f_count) 958 959 959 960 #ifdef CONFIG_DEBUG_WRITECOUNT