diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index d33af95321fbd88384421a8570f9b59c6f4b2696..42c5b9f23b411e9c77d8dcbd0da9629a6cb3639f 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -264,12 +264,6 @@ void kernfs_put(struct kernfs_node *kn) } EXPORT_SYMBOL_GPL(kernfs_put); -static int kernfs_dop_delete(const struct dentry *dentry) -{ - struct kernfs_node *kn = dentry->d_fsdata; - return !(kn && !(kn->flags & KERNFS_REMOVED)); -} - static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) { struct kernfs_node *kn; @@ -277,6 +271,10 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) if (flags & LOOKUP_RCU) return -ECHILD; + /* Always perform fresh lookup for negatives */ + if (!dentry->d_inode) + goto out_bad_unlocked; + kn = dentry->d_fsdata; mutex_lock(&kernfs_mutex); @@ -301,22 +299,14 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) out_valid: return 1; out_bad: - /* - * Remove the dentry from the dcache hashes. - * If this is a deleted dentry we use d_drop instead of d_delete - * so kernfs doesn't need to cope with negative dentries. - * - * If this is a dentry that has simply been renamed we - * use d_drop to remove it from the dcache lookup on its - * old parent. If this dentry persists later when a lookup - * is performed at its new name the dentry will be readded - * to the dcache hashes. - */ mutex_unlock(&kernfs_mutex); - - /* If we have submounts we must allow the vfs caches - * to lie about the state of the filesystem to prevent - * leaks and other nasty things. +out_bad_unlocked: + /* + * @dentry doesn't match the underlying kernfs node, drop the + * dentry and force lookup. If we have submounts we must allow the + * vfs caches to lie about the state of the filesystem to prevent + * leaks and other nasty things, so use check_submounts_and_drop() + * instead of d_drop(). */ if (check_submounts_and_drop(dentry) != 0) goto out_valid; @@ -331,7 +321,6 @@ static void kernfs_dop_release(struct dentry *dentry) const struct dentry_operations kernfs_dops = { .d_revalidate = kernfs_dop_revalidate, - .d_delete = kernfs_dop_delete, .d_release = kernfs_dop_release, }; @@ -682,7 +671,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { - struct dentry *ret = NULL; + struct dentry *ret; struct kernfs_node *parent = dentry->d_parent->d_fsdata; struct kernfs_node *kn; struct inode *inode; @@ -697,7 +686,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, /* no such entry */ if (!kn) { - ret = ERR_PTR(-ENOENT); + ret = NULL; goto out_unlock; } kernfs_get(kn);