Skip to content

Commit 91ec6c8

Browse files
author
Miklos Szeredi
committed
Revert "fuse: in fuse_flush only wait if someone wants the return code"
This reverts commit 5a8bee6. Jürg Billeter reports the following regression: Since v6.3-rc1 commit 5a8bee6 ("fuse: in fuse_flush only wait if someone wants the return code") `fput()` is called asynchronously if a file is closed as part of a process exiting, i.e., if there was no explicit `close()` before exit. If the file was open for writing, also `put_write_access()` is called asynchronously as part of the async `fput()`. If that newly written file is an executable, attempting to `execve()` the new file can fail with `ETXTBSY` if it's called after the writer process exited but before the async `fput()` has run. Reported-and-tested-by: "Jürg Billeter" <[email protected]> Cc: <[email protected]> # v6.3 Link: https://lore.kernel.org/all/[email protected]/ Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 2ccdd1b commit 91ec6c8

File tree

1 file changed

+26
-63
lines changed

1 file changed

+26
-63
lines changed

fs/fuse/file.c

Lines changed: 26 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include <linux/uio.h>
2020
#include <linux/fs.h>
2121
#include <linux/filelock.h>
22-
#include <linux/file.h>
2322

2423
static int fuse_send_open(struct fuse_mount *fm, u64 nodeid,
2524
unsigned int open_flags, int opcode,
@@ -479,36 +478,48 @@ static void fuse_sync_writes(struct inode *inode)
479478
fuse_release_nowrite(inode);
480479
}
481480

482-
struct fuse_flush_args {
483-
struct fuse_args args;
484-
struct fuse_flush_in inarg;
485-
struct work_struct work;
486-
struct file *file;
487-
};
488-
489-
static int fuse_do_flush(struct fuse_flush_args *fa)
481+
static int fuse_flush(struct file *file, fl_owner_t id)
490482
{
491-
int err;
492-
struct inode *inode = file_inode(fa->file);
483+
struct inode *inode = file_inode(file);
493484
struct fuse_mount *fm = get_fuse_mount(inode);
485+
struct fuse_file *ff = file->private_data;
486+
struct fuse_flush_in inarg;
487+
FUSE_ARGS(args);
488+
int err;
489+
490+
if (fuse_is_bad(inode))
491+
return -EIO;
492+
493+
if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache)
494+
return 0;
494495

495496
err = write_inode_now(inode, 1);
496497
if (err)
497-
goto out;
498+
return err;
498499

499500
inode_lock(inode);
500501
fuse_sync_writes(inode);
501502
inode_unlock(inode);
502503

503-
err = filemap_check_errors(fa->file->f_mapping);
504+
err = filemap_check_errors(file->f_mapping);
504505
if (err)
505-
goto out;
506+
return err;
506507

507508
err = 0;
508509
if (fm->fc->no_flush)
509510
goto inval_attr_out;
510511

511-
err = fuse_simple_request(fm, &fa->args);
512+
memset(&inarg, 0, sizeof(inarg));
513+
inarg.fh = ff->fh;
514+
inarg.lock_owner = fuse_lock_owner_id(fm->fc, id);
515+
args.opcode = FUSE_FLUSH;
516+
args.nodeid = get_node_id(inode);
517+
args.in_numargs = 1;
518+
args.in_args[0].size = sizeof(inarg);
519+
args.in_args[0].value = &inarg;
520+
args.force = true;
521+
522+
err = fuse_simple_request(fm, &args);
512523
if (err == -ENOSYS) {
513524
fm->fc->no_flush = 1;
514525
err = 0;
@@ -521,57 +532,9 @@ static int fuse_do_flush(struct fuse_flush_args *fa)
521532
*/
522533
if (!err && fm->fc->writeback_cache)
523534
fuse_invalidate_attr_mask(inode, STATX_BLOCKS);
524-
525-
out:
526-
fput(fa->file);
527-
kfree(fa);
528535
return err;
529536
}
530537

531-
static void fuse_flush_async(struct work_struct *work)
532-
{
533-
struct fuse_flush_args *fa = container_of(work, typeof(*fa), work);
534-
535-
fuse_do_flush(fa);
536-
}
537-
538-
static int fuse_flush(struct file *file, fl_owner_t id)
539-
{
540-
struct fuse_flush_args *fa;
541-
struct inode *inode = file_inode(file);
542-
struct fuse_mount *fm = get_fuse_mount(inode);
543-
struct fuse_file *ff = file->private_data;
544-
545-
if (fuse_is_bad(inode))
546-
return -EIO;
547-
548-
if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache)
549-
return 0;
550-
551-
fa = kzalloc(sizeof(*fa), GFP_KERNEL);
552-
if (!fa)
553-
return -ENOMEM;
554-
555-
fa->inarg.fh = ff->fh;
556-
fa->inarg.lock_owner = fuse_lock_owner_id(fm->fc, id);
557-
fa->args.opcode = FUSE_FLUSH;
558-
fa->args.nodeid = get_node_id(inode);
559-
fa->args.in_numargs = 1;
560-
fa->args.in_args[0].size = sizeof(fa->inarg);
561-
fa->args.in_args[0].value = &fa->inarg;
562-
fa->args.force = true;
563-
fa->file = get_file(file);
564-
565-
/* Don't wait if the task is exiting */
566-
if (current->flags & PF_EXITING) {
567-
INIT_WORK(&fa->work, fuse_flush_async);
568-
schedule_work(&fa->work);
569-
return 0;
570-
}
571-
572-
return fuse_do_flush(fa);
573-
}
574-
575538
int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
576539
int datasync, int opcode)
577540
{

0 commit comments

Comments
 (0)