diff options
Diffstat (limited to 'fs/fuse/dir.c')
| -rw-r--r-- | fs/fuse/dir.c | 36 |
1 files changed, 15 insertions, 21 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index b658b6baf72f..97751bacb79c 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1587,40 +1587,34 @@ int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid, { int err = -ENOTDIR; struct inode *parent; - struct dentry *dir = NULL; - struct dentry *entry = NULL; + struct dentry *dir; + struct dentry *entry; parent = fuse_ilookup(fc, parent_nodeid, NULL); if (!parent) return -ENOENT; + inode_lock_nested(parent, I_MUTEX_PARENT); if (!S_ISDIR(parent->i_mode)) - goto put_parent; + goto unlock; err = -ENOENT; dir = d_find_alias(parent); if (!dir) - goto put_parent; - while (!entry) { - struct dentry *child = try_lookup_noperm(name, dir); - if (!child || IS_ERR(child)) - goto put_parent; - entry = start_removing_dentry(dir, child); - dput(child); - if (IS_ERR(entry)) - goto put_parent; - if (!d_same_name(entry, dir, name)) { - end_removing(entry); - entry = NULL; - } - } + goto unlock; + + name->hash = full_name_hash(dir, name->name, name->len); + entry = d_lookup(dir, name); + dput(dir); + if (!entry) + goto unlock; fuse_dir_changed(parent); if (!(flags & FUSE_EXPIRE_ONLY)) d_invalidate(entry); fuse_invalidate_entry_cache(entry); - if (child_nodeid != 0) { + if (child_nodeid != 0 && d_really_is_positive(entry)) { inode_lock(d_inode(entry)); if (get_node_id(d_inode(entry)) != child_nodeid) { err = -ENOENT; @@ -1648,10 +1642,10 @@ int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid, } else { err = 0; } + dput(entry); - end_removing(entry); - put_parent: - dput(dir); + unlock: + inode_unlock(parent); iput(parent); return err; } |
