From: Miklos Szeredi <miklos@xxxxxxxxxx> atomic_open() will do an open-by-name or create-and-open depending on the flags. If file was created, then the old positive dentry is obviously stale, so it will be invalidated and a new one will be allocated. If not created, then check whether it's the same inode (same as in ->d_revalidate()) and if not, invalidate & allocate new dentry. This only works with O_CREAT, without O_CREAT open_last_lookups will call into lookup_fast and then return the dentry via finish_lookup - lookup_open is never called. This is going to be addressed in the next commit. Another included change is the introduction of an enum as d_revalidate return code. Co-developed-by: Bernd Schubert <bschubert@xxxxxxx> Signed-off-by: Bernd Schubert <bschubert@xxxxxxx> Signed-off-by: Miklos Szeredi <miklos@xxxxxxxxxx> Cc: Christian Brauner <brauner@xxxxxxxxxx> Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> Cc: Dharmendra Singh <dsingh@xxxxxxx> Cc: Amir Goldstein <amir73il@xxxxxxxxx> Cc: linux-fsdevel@xxxxxxxxxxxxxxx --- fs/namei.c | 11 ++++++----- include/linux/namei.h | 7 +++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 567ee547492b..ff913e6b12b4 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -860,7 +860,7 @@ static inline int d_revalidate(struct dentry *dentry, unsigned int flags) if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) return dentry->d_op->d_revalidate(dentry, flags); else - return 1; + return D_REVALIDATE_VALID; } /** @@ -3330,8 +3330,9 @@ static int may_o_create(struct mnt_idmap *idmap, } /* - * Attempt to atomically look up, create and open a file from a negative - * dentry. + * Attempt to atomically look up, create and open a file from a + * dentry. Unless the file system returns D_REVALIDATE_ATOMIC in ->d_revalidate, + * the dentry is always negative. * * Returns 0 if successful. The file will have been created and attached to * @file by the filesystem calling finish_open(). @@ -3406,7 +3407,7 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, struct inode *dir_inode = dir->d_inode; int open_flag = op->open_flag; struct dentry *dentry; - int error, create_error = 0; + int error = 0, create_error = 0; umode_t mode = op->mode; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); @@ -3433,7 +3434,7 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, dput(dentry); dentry = NULL; } - if (dentry->d_inode) { + if (dentry->d_inode && error != D_REVALIDATE_ATOMIC) { /* Cached positive dentry: will open in f_op->open */ return dentry; } diff --git a/include/linux/namei.h b/include/linux/namei.h index 1463cbda4888..a70e87d2b2a9 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -47,6 +47,13 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; /* LOOKUP_* flags which do scope-related checks based on the dirfd. */ #define LOOKUP_IS_SCOPED (LOOKUP_BENEATH | LOOKUP_IN_ROOT) +/* ->d_revalidate return codes */ +enum { + D_REVALIDATE_INVALID = 0, /* invalid dentry */ + D_REVALIDATE_VALID = 1, /* valid dentry */ + D_REVALIDATE_ATOMIC = 2, /* atomic_open will revalidate */ +}; + extern int path_pts(struct path *path); extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); -- 2.39.2