Skip to content

Commit d7065da

Browse files
author
Al Viro
committed
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 <[email protected]>
1 parent 176306f commit d7065da

File tree

4 files changed

+14
-15
lines changed

4 files changed

+14
-15
lines changed

fs/aio.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ static void aio_fput_routine(struct work_struct *data)
527527

528528
/* Complete the fput(s) */
529529
if (req->ki_filp != NULL)
530-
__fput(req->ki_filp);
530+
fput(req->ki_filp);
531531

532532
/* Link the iocb into the context's free list */
533533
spin_lock_irq(&ctx->ctx_lock);
@@ -560,11 +560,11 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
560560

561561
/*
562562
* 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,
564564
* we would not be holding the last reference to the file*, so
565565
* this function will be executed w/out any aio kthread wakeup.
566566
*/
567-
if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) {
567+
if (unlikely(!fput_atomic(req->ki_filp))) {
568568
get_ioctx(ctx);
569569
spin_lock(&fput_lock);
570570
list_add(&req->ki_list, &fput_head);

fs/file_table.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,6 @@ struct file *alloc_file(struct path *path, fmode_t mode,
194194
}
195195
EXPORT_SYMBOL(alloc_file);
196196

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-
205197
/**
206198
* drop_file_write_access - give up ability to write to a file
207199
* @file: the file to which we will stop writing
@@ -227,10 +219,9 @@ void drop_file_write_access(struct file *file)
227219
}
228220
EXPORT_SYMBOL_GPL(drop_file_write_access);
229221

230-
/* __fput is called from task context when aio completion releases the last
231-
* last use of a struct file *. Do not use otherwise.
222+
/* the real guts of fput() - releasing the last reference to file
232223
*/
233-
void __fput(struct file *file)
224+
static void __fput(struct file *file)
234225
{
235226
struct dentry *dentry = file->f_path.dentry;
236227
struct vfsmount *mnt = file->f_path.mnt;
@@ -268,6 +259,14 @@ void __fput(struct file *file)
268259
mntput(mnt);
269260
}
270261

262+
void fput(struct file *file)
263+
{
264+
if (atomic_long_dec_and_test(&file->f_count))
265+
__fput(file);
266+
}
267+
268+
EXPORT_SYMBOL(fput);
269+
271270
struct file *fget(unsigned int fd)
272271
{
273272
struct file *file;

include/linux/file.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
struct file;
1313

14-
extern void __fput(struct file *);
1514
extern void fput(struct file *);
1615
extern void drop_file_write_access(struct file *file);
1716

include/linux/fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,7 @@ extern spinlock_t files_lock;
954954
#define file_list_unlock() spin_unlock(&files_lock);
955955

956956
#define get_file(x) atomic_long_inc(&(x)->f_count)
957+
#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1)
957958
#define file_count(x) atomic_long_read(&(x)->f_count)
958959

959960
#ifdef CONFIG_DEBUG_WRITECOUNT

0 commit comments

Comments
 (0)