diff options
author | shao mingyin <shao.mingyin@zte.com.cn> | 2024-10-23 13:58:50 +0800 |
---|---|---|
committer | Christian Brauner <brauner@kernel.org> | 2024-12-22 11:29:52 +0100 |
commit | 9b7da575f85962c44abe7dc245b0a58179ad2c45 (patch) | |
tree | 0af1b027ad166f652ec8f58596c04fef1d9dc4df | |
parent | 1197867a5dc8924d83ce484b6fd361ca32423dac (diff) |
file: flush delayed work in delayed fput()
The fput() of file rcS might not have completed causing issues when
executing the file.
rcS is opened in do_populate_rootfs before executed. At the end of
do_populate_rootfs() flush_delayed_fput() is called. Now
do_populate_rootfs() assumes that all fput()s caused by
do_populate_rootfs() have completed.
But flush_delayed_fput() can only ensure that fput() on the current
delayed_fput_list has finished. Any file that has been removed from
delayed_fput_list asynchronously in the meantime might not have
completed causing the exec to fail.
do_populate_rootfs delayed_fput_list delayed_fput execve
fput() a
fput() a->b
fput() a->b->rcS
__fput(a)
fput() c
fput() c->d
__fput(b)
flush_delayed_fput
__fput(c)
__fput(d)
__fput(b)
__fput(b) execve(rcS)
Ensure that all delayed work is done by calling flush_delayed_work() in
flush_delayed_fput() explicitly.
Signed-off-by: Chen Lin <chen.lin5@zte.com.cn>
Signed-off-by: Shao Mingyin <shao.mingyin@zte.com.cn>
Link: https://lore.kernel.org/r/20241023135850067m3w2R0UXESiVCYz_wdAoT@zte.com.cn
Cc: Yang Yang <yang.yang29@zte.com.cn>
Cc: Yang Tao <yang.tao172@zte.com.cn>
Cc: Xu Xin <xu.xin16@zte.com.cn>
[brauner: rewrite commit message]
Signed-off-by: Christian Brauner <brauner@kernel.org>
-rw-r--r-- | fs/file_table.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/fs/file_table.c b/fs/file_table.c index 502b81f614d9..a32171d2b83f 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -478,6 +478,8 @@ static void ____fput(struct callback_head *work) __fput(container_of(work, struct file, f_task_work)); } +static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); + /* * If kernel thread really needs to have the final fput() it has done * to complete, call this. The only user right now is the boot - we @@ -491,11 +493,10 @@ static void ____fput(struct callback_head *work) void flush_delayed_fput(void) { delayed_fput(NULL); + flush_delayed_work(&delayed_fput_work); } EXPORT_SYMBOL_GPL(flush_delayed_fput); -static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); - void fput(struct file *file) { if (file_ref_put(&file->f_ref)) { |