We handle it for the path resolution itself, but we should also factor it in for open_last_lookups() and tmpfile open. We don't allow RESOLVE_NONBLOCK with O_TRUNC, so that case we can safely ignore. Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> --- fs/namei.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 07a1aa874f65..1f976a213eef 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3127,6 +3127,7 @@ static const char *open_last_lookups(struct nameidata *nd, struct dentry *dir = nd->path.dentry; int open_flag = op->open_flag; bool got_write = false; + bool nonblock = nd->flags & LOOKUP_NONBLOCK; unsigned seq; struct inode *inode; struct dentry *dentry; @@ -3164,17 +3165,38 @@ static const char *open_last_lookups(struct nameidata *nd, } if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) { - got_write = !mnt_want_write(nd->path.mnt); + if (nonblock) { + got_write = !mnt_want_write_trylock(nd->path.mnt); + if (!got_write) + return ERR_PTR(-EAGAIN); + } else { + got_write = !mnt_want_write(nd->path.mnt); + } /* * do _not_ fail yet - we might not need that or fail with * a different error; let lookup_open() decide; we'll be * dropping this one anyway. */ } - if (open_flag & O_CREAT) - inode_lock(dir->d_inode); - else - inode_lock_shared(dir->d_inode); + if (open_flag & O_CREAT) { + if (nonblock) { + if (!inode_trylock(dir->d_inode)) { + dentry = ERR_PTR(-EAGAIN); + goto drop_write; + } + } else { + inode_lock(dir->d_inode); + } + } else { + if (nonblock) { + if (!inode_trylock_shared(dir->d_inode)) { + dentry = ERR_PTR(-EAGAIN); + goto drop_write; + } + } else { + inode_lock_shared(dir->d_inode); + } + } dentry = lookup_open(nd, file, op, got_write); if (!IS_ERR(dentry) && (file->f_mode & FMODE_CREATED)) fsnotify_create(dir->d_inode, dentry); @@ -3183,6 +3205,7 @@ static const char *open_last_lookups(struct nameidata *nd, else inode_unlock_shared(dir->d_inode); +drop_write: if (got_write) mnt_drop_write(nd->path.mnt); @@ -3242,6 +3265,7 @@ static int do_open(struct nameidata *nd, open_flag &= ~O_TRUNC; acc_mode = 0; } else if (d_is_reg(nd->path.dentry) && open_flag & O_TRUNC) { + WARN_ON_ONCE(nd->flags & LOOKUP_NONBLOCK); error = mnt_want_write(nd->path.mnt); if (error) return error; @@ -3311,7 +3335,10 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags, int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path); if (unlikely(error)) return error; - error = mnt_want_write(path.mnt); + if (flags & LOOKUP_NONBLOCK) + error = mnt_want_write_trylock(path.mnt); + else + error = mnt_want_write(path.mnt); if (unlikely(error)) goto out; child = vfs_tmpfile(path.dentry, op->mode, op->open_flag); -- 2.29.2