diff mbox series

[v2,(resend)] fput: Allow calling __fput_sync() from !PF_KTHREAD thread.

Message ID 2eaf00e5-df91-a0be-8d00-801fb1823f7b@i-love.sakura.ne.jp (mailing list archive)
State New, archived
Headers show
Series [v2,(resend)] fput: Allow calling __fput_sync() from !PF_KTHREAD thread. | expand

Commit Message

Tetsuo Handa Aug. 19, 2020, 12:42 p.m. UTC
__fput_sync() was introduced by commit 4a9d4b024a3102fc ("switch fput to
task_work_add") with BUG_ON(!(current->flags & PF_KTHREAD)) check, and
the only user of __fput_sync() was introduced by commit 17c0a5aaffa63da6
("make acct_kill() wait for file closing."). However, the latter commit is
effectively calling __fput_sync() from !PF_KTHREAD thread because of
schedule_work() call followed by immediate wait_for_completion() call.
That is, there is no need to defer close_work() to a WQ context. I guess
that the reason to defer was nothing but to bypass this BUG_ON() check.
While we need to remain careful about calling __fput_sync(), we can remove
bypassable BUG_ON() check from __fput_sync().

If this change is accepted, racy fput()+flush_delayed_fput() introduced
by commit e2dc9bf3f5275ca3 ("umd: Transform fork_usermode_blob into
fork_usermode_driver") will be replaced by this raceless __fput_sync().

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
 fs/file_table.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

Comments

Tetsuo Handa Sept. 9, 2020, 9:59 p.m. UTC | #1
Ping?

On 2020/08/19 21:42, Tetsuo Handa wrote:
> __fput_sync() was introduced by commit 4a9d4b024a3102fc ("switch fput to
> task_work_add") with BUG_ON(!(current->flags & PF_KTHREAD)) check, and
> the only user of __fput_sync() was introduced by commit 17c0a5aaffa63da6
> ("make acct_kill() wait for file closing."). However, the latter commit is
> effectively calling __fput_sync() from !PF_KTHREAD thread because of
> schedule_work() call followed by immediate wait_for_completion() call.
> That is, there is no need to defer close_work() to a WQ context. I guess
> that the reason to defer was nothing but to bypass this BUG_ON() check.
> While we need to remain careful about calling __fput_sync(), we can remove
> bypassable BUG_ON() check from __fput_sync().
> 
> If this change is accepted, racy fput()+flush_delayed_fput() introduced
> by commit e2dc9bf3f5275ca3 ("umd: Transform fork_usermode_blob into
> fork_usermode_driver") will be replaced by this raceless __fput_sync().
> 
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> ---
>  fs/file_table.c | 15 +++++----------
>  1 file changed, 5 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/file_table.c b/fs/file_table.c
> index 656647f..7c41251 100644
> --- a/fs/file_table.c
> +++ b/fs/file_table.c
> @@ -359,20 +359,15 @@ void fput(struct file *file)
>  }
>  
>  /*
> - * synchronous analog of fput(); for kernel threads that might be needed
> - * in some umount() (and thus can't use flush_delayed_fput() without
> - * risking deadlocks), need to wait for completion of __fput() and know
> - * for this specific struct file it won't involve anything that would
> - * need them.  Use only if you really need it - at the very least,
> - * don't blindly convert fput() by kernel thread to that.
> + * synchronous analog of fput(); for threads that need to wait for completion
> + * of __fput() and know for this specific struct file it won't involve anything
> + * that would need them.  Use only if you really need it - at the very least,
> + * don't blindly convert fput() to __fput_sync().
>   */
>  void __fput_sync(struct file *file)
>  {
> -	if (atomic_long_dec_and_test(&file->f_count)) {
> -		struct task_struct *task = current;
> -		BUG_ON(!(task->flags & PF_KTHREAD));
> +	if (atomic_long_dec_and_test(&file->f_count))
>  		__fput(file);
> -	}
>  }
>  
>  EXPORT_SYMBOL(fput);
>
diff mbox series

Patch

diff --git a/fs/file_table.c b/fs/file_table.c
index 656647f..7c41251 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -359,20 +359,15 @@  void fput(struct file *file)
 }
 
 /*
- * synchronous analog of fput(); for kernel threads that might be needed
- * in some umount() (and thus can't use flush_delayed_fput() without
- * risking deadlocks), need to wait for completion of __fput() and know
- * for this specific struct file it won't involve anything that would
- * need them.  Use only if you really need it - at the very least,
- * don't blindly convert fput() by kernel thread to that.
+ * synchronous analog of fput(); for threads that need to wait for completion
+ * of __fput() and know for this specific struct file it won't involve anything
+ * that would need them.  Use only if you really need it - at the very least,
+ * don't blindly convert fput() to __fput_sync().
  */
 void __fput_sync(struct file *file)
 {
-	if (atomic_long_dec_and_test(&file->f_count)) {
-		struct task_struct *task = current;
-		BUG_ON(!(task->flags & PF_KTHREAD));
+	if (atomic_long_dec_and_test(&file->f_count))
 		__fput(file);
-	}
 }
 
 EXPORT_SYMBOL(fput);