lookup_and_lock() and done_lookup_and_lock() are now told, via LOOKUP_ intent flags what operation is being performed, including a new LOOKUP_REMOVE. They use this to determine whether shared or exclusive locking is needed. If all filesystems eventually support all async interface, this locking can be discarded. Signed-off-by: NeilBrown <neilb@xxxxxxx> --- fs/namei.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index e8a85c9f431c..c7b7445c770e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1898,13 +1898,26 @@ static struct dentry *lookup_and_lock_nested(const struct qstr *last, unsigned int subclass) { struct dentry *dentry; + unsigned int shared = 0; - if (!(lookup_flags & LOOKUP_PARENT_LOCKED)) - inode_lock_nested(base->d_inode, subclass); + if (!(lookup_flags & LOOKUP_PARENT_LOCKED)) { + if (lookup_flags & LOOKUP_CREATE) + shared = S_ASYNC_CREATE; + if (lookup_flags & LOOKUP_REMOVE) + shared = S_ASYNC_REMOVE; + + if (base->d_inode->i_flags & shared) + inode_lock_shared_nested(base->d_inode, subclass); + else + inode_lock_nested(base->d_inode, subclass); + } do { dentry = lookup_one_qstr(last, base, lookup_flags); } while (!IS_ERR(dentry) && !d_update_lock(dentry, base, last, subclass)); if (IS_ERR(dentry) && !(lookup_flags & LOOKUP_PARENT_LOCKED)) { + if (base->d_inode->i_flags & shared) + inode_unlock_shared(base->d_inode); + else inode_unlock(base->d_inode); } return dentry; @@ -1921,11 +1934,22 @@ static struct dentry *lookup_and_lock(const struct qstr *last, void done_lookup_and_lock(struct dentry *base, struct dentry *dentry, unsigned int lookup_flags) { + unsigned int shared = 0; + + if (lookup_flags & LOOKUP_CREATE) + shared = S_ASYNC_CREATE; + if (lookup_flags & LOOKUP_REMOVE) + shared = S_ASYNC_REMOVE; + d_lookup_done(dentry); d_update_unlock(dentry); dput(dentry); - if (!(lookup_flags & LOOKUP_PARENT_LOCKED)) - inode_unlock(base->d_inode); + if (!(lookup_flags & LOOKUP_PARENT_LOCKED)) { + if (base->d_inode->i_flags & shared) + inode_unlock_shared(base->d_inode); + else + inode_unlock(base->d_inode); + } } EXPORT_SYMBOL(done_lookup_and_lock); @@ -4004,7 +4028,7 @@ static const char *open_last_lookups(struct nameidata *nd, * dropping this one anyway. */ } - if (open_flag & O_CREAT) + if ((open_flag & O_CREAT) && !(dir->d_inode->i_flags & S_ASYNC_OPEN)) inode_lock(dir->d_inode); else inode_lock_shared(dir->d_inode); @@ -4015,7 +4039,7 @@ static const char *open_last_lookups(struct nameidata *nd, if (file->f_mode & FMODE_OPENED) fsnotify_open(file); } - if (open_flag & O_CREAT) + if ((open_flag & O_CREAT) && !(dir->d_inode->i_flags & S_ASYNC_OPEN)) inode_unlock(dir->d_inode); else inode_unlock_shared(dir->d_inode); @@ -4775,7 +4799,7 @@ int do_rmdir(int dfd, struct filename *name) struct path path; struct qstr last; int type; - unsigned int lookup_flags = 0; + unsigned int lookup_flags = LOOKUP_REMOVE; retry: error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type); if (error) @@ -4914,7 +4938,7 @@ int do_unlinkat(int dfd, struct filename *name) int type; struct inode *inode = NULL; struct inode *delegated_inode = NULL; - unsigned int lookup_flags = 0; + unsigned int lookup_flags = LOOKUP_REMOVE; retry: error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type); if (error) -- 2.47.1