Skip to content

Commit 7d1cf5e

Browse files
neilbrownbrauner
authored andcommitted
vfs: generate FS_CREATE before FS_OPEN when ->atomic_open used.
When a file is opened and created with open(..., O_CREAT) we get both the CREATE and OPEN fsnotify events and would expect them in that order. For most filesystems we get them in that order because open_last_lookups() calls fsnofify_create() and then do_open() (from path_openat()) calls vfs_open()->do_dentry_open() which calls fsnotify_open(). However when ->atomic_open is used, the do_dentry_open() -> fsnotify_open() call happens from finish_open() which is called from the ->atomic_open handler in lookup_open() which is called *before* open_last_lookups() calls fsnotify_create. So we get the "open" notification before "create" - which is backwards. ltp testcase inotify02 tests this and reports the inconsistency. This patch lifts the fsnotify_open() call out of do_dentry_open() and places it higher up the call stack. There are three callers of do_dentry_open(). For vfs_open() and kernel_file_open() the fsnotify_open() is placed directly in that caller so there should be no behavioural change. For finish_open() there are two cases: - finish_open is used in ->atomic_open handlers. For these we add a call to fsnotify_open() at open_last_lookups() if FMODE_OPENED is set - which means do_dentry_open() has been called. - finish_open is used in ->tmpfile() handlers. For these a similar call to fsnotify_open() is added to vfs_tmpfile() With this patch NFSv3 is restored to its previous behaviour (before ->atomic_open support was added) of generating CREATE notifications before OPEN, and NFSv4 now has that same correct ordering that is has not had before. I haven't tested other filesystems. Fixes: 7c6c524 ("NFS: add atomic_open for NFSv3 to handle O_TRUNC correctly.") Reported-by: James Clark <james.clark@arm.com> Closes: https://lore.kernel.org/all/01c3bf2e-eb1f-4b7f-a54f-d2a05dd3d8c8@arm.com Signed-off-by: NeilBrown <neilb@suse.de> Link: https://lore.kernel.org/r/171817619547.14261.975798725161704336@noble.neil.brown.name Fixes: 7b8c9d7 ("fsnotify: move fsnotify_open() hook into do_dentry_open()") Tested-by: James Clark <james.clark@arm.com> Signed-off-by: Jan Kara <jack@suse.cz> Link: https://lore.kernel.org/r/20240617162303.1596-2-jack@suse.cz Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent 702eb71 commit 7d1cf5e

2 files changed

Lines changed: 23 additions & 9 deletions

File tree

fs/namei.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3572,8 +3572,12 @@ static const char *open_last_lookups(struct nameidata *nd,
35723572
else
35733573
inode_lock_shared(dir->d_inode);
35743574
dentry = lookup_open(nd, file, op, got_write);
3575-
if (!IS_ERR(dentry) && (file->f_mode & FMODE_CREATED))
3576-
fsnotify_create(dir->d_inode, dentry);
3575+
if (!IS_ERR(dentry)) {
3576+
if (file->f_mode & FMODE_CREATED)
3577+
fsnotify_create(dir->d_inode, dentry);
3578+
if (file->f_mode & FMODE_OPENED)
3579+
fsnotify_open(file);
3580+
}
35773581
if (open_flag & O_CREAT)
35783582
inode_unlock(dir->d_inode);
35793583
else
@@ -3700,6 +3704,8 @@ int vfs_tmpfile(struct mnt_idmap *idmap,
37003704
mode = vfs_prepare_mode(idmap, dir, mode, mode, mode);
37013705
error = dir->i_op->tmpfile(idmap, dir, file, mode);
37023706
dput(child);
3707+
if (file->f_mode & FMODE_OPENED)
3708+
fsnotify_open(file);
37033709
if (error)
37043710
return error;
37053711
/* Don't check for other permissions, the inode was just created */

fs/open.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,11 +1004,6 @@ static int do_dentry_open(struct file *f,
10041004
}
10051005
}
10061006

1007-
/*
1008-
* Once we return a file with FMODE_OPENED, __fput() will call
1009-
* fsnotify_close(), so we need fsnotify_open() here for symmetry.
1010-
*/
1011-
fsnotify_open(f);
10121007
return 0;
10131008

10141009
cleanup_all:
@@ -1085,8 +1080,19 @@ EXPORT_SYMBOL(file_path);
10851080
*/
10861081
int vfs_open(const struct path *path, struct file *file)
10871082
{
1083+
int ret;
1084+
10881085
file->f_path = *path;
1089-
return do_dentry_open(file, NULL);
1086+
ret = do_dentry_open(file, NULL);
1087+
if (!ret) {
1088+
/*
1089+
* Once we return a file with FMODE_OPENED, __fput() will call
1090+
* fsnotify_close(), so we need fsnotify_open() here for
1091+
* symmetry.
1092+
*/
1093+
fsnotify_open(file);
1094+
}
1095+
return ret;
10901096
}
10911097

10921098
struct file *dentry_open(const struct path *path, int flags,
@@ -1177,8 +1183,10 @@ struct file *kernel_file_open(const struct path *path, int flags,
11771183
error = do_dentry_open(f, NULL);
11781184
if (error) {
11791185
fput(f);
1180-
f = ERR_PTR(error);
1186+
return ERR_PTR(error);
11811187
}
1188+
1189+
fsnotify_open(f);
11821190
return f;
11831191
}
11841192
EXPORT_SYMBOL_GPL(kernel_file_open);

0 commit comments

Comments
 (0)