diff options
| author | Herbert Xu <herbert@gondor.apana.org.au> | 2013-09-07 12:53:35 +1000 |
|---|---|---|
| committer | Herbert Xu <herbert@gondor.apana.org.au> | 2013-09-07 12:53:35 +1000 |
| commit | eeca9fad52fc4bfdf42c38bfcf383e932eb3e9d6 (patch) | |
| tree | cc51c880459d41c0e8d7576405bef4c987bc7aa0 /fs/file_table.c | |
| parent | ff6f83fc9d44db09997937c3475d525a6866fbb4 (diff) | |
| parent | b48a97be8e6c2afdba2f3b61fd88c3c7743fbd73 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
Merge upstream tree in order to reinstate crct10dif.
Diffstat (limited to 'fs/file_table.c')
| -rw-r--r-- | fs/file_table.c | 31 |
1 files changed, 16 insertions, 15 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index 08e719b884ca..b44e4c559786 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -265,18 +265,15 @@ static void __fput(struct file *file) mntput(mnt); } -static DEFINE_SPINLOCK(delayed_fput_lock); -static LIST_HEAD(delayed_fput_list); +static LLIST_HEAD(delayed_fput_list); static void delayed_fput(struct work_struct *unused) { - LIST_HEAD(head); - spin_lock_irq(&delayed_fput_lock); - list_splice_init(&delayed_fput_list, &head); - spin_unlock_irq(&delayed_fput_lock); - while (!list_empty(&head)) { - struct file *f = list_first_entry(&head, struct file, f_u.fu_list); - list_del_init(&f->f_u.fu_list); - __fput(f); + struct llist_node *node = llist_del_all(&delayed_fput_list); + struct llist_node *next; + + for (; node; node = next) { + next = llist_next(node); + __fput(llist_entry(node, struct file, f_u.fu_llist)); } } @@ -306,18 +303,22 @@ void fput(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { struct task_struct *task = current; - unsigned long flags; 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)) return; + /* + * After this task has run exit_task_work(), + * task_work_add() will fail. free_ipc_ns()-> + * shm_destroy() can do this. Fall through to delayed + * fput to avoid leaking *file. + */ } - spin_lock_irqsave(&delayed_fput_lock, flags); - list_add(&file->f_u.fu_list, &delayed_fput_list); - schedule_work(&delayed_fput_work); - spin_unlock_irqrestore(&delayed_fput_lock, flags); + + if (llist_add(&file->f_u.fu_llist, &delayed_fput_list)) + schedule_work(&delayed_fput_work); } } |
