/* Slow case: now with the dentry lock held */
        rcu_read_unlock();
 
+       WARN_ON(d_in_lookup(dentry));
+
        /* Unreachable? Get rid of it */
        if (unlikely(d_unhashed(dentry)))
                goto kill_it;
 static void __d_instantiate(struct dentry *dentry, struct inode *inode)
 {
        unsigned add_flags = d_flags_for_inode(inode);
+       WARN_ON(d_in_lookup(dentry));
 
        spin_lock(&dentry->d_lock);
        hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
 }
 EXPORT_SYMBOL(d_rehash);
 
+void __d_lookup_done(struct dentry *dentry)
+{
+       dentry->d_flags &= ~DCACHE_PAR_LOOKUP;
+       /* more stuff will land here */
+}
+EXPORT_SYMBOL(__d_lookup_done);
 
 /* inode->i_lock held if inode is non-NULL */
 
 static inline void __d_add(struct dentry *dentry, struct inode *inode)
 {
        spin_lock(&dentry->d_lock);
+       if (unlikely(d_in_lookup(dentry)))
+               __d_lookup_done(dentry);
        if (inode) {
                unsigned add_flags = d_flags_for_inode(inode);
                hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
        BUG_ON(d_ancestor(target, dentry));
 
        dentry_lock_for_move(dentry, target);
+       if (unlikely(d_in_lookup(target)))
+               __d_lookup_done(target);
 
        write_seqcount_begin(&dentry->d_seq);
        write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED);
 
                inode_unlock(inode);
                return ERR_PTR(-ENOMEM);
        }
+       spin_lock(&dentry->d_lock);
+       dentry->d_flags |= DCACHE_PAR_LOOKUP;
+       spin_unlock(&dentry->d_lock);
        old = inode->i_op->lookup(inode, dentry, flags);
+       d_lookup_done(dentry);
        if (unlikely(old)) {
                dput(dentry);
                dentry = old;
 
 #define DCACHE_ENCRYPTED_WITH_KEY      0x04000000 /* dir is encrypted with a valid key */
 #define DCACHE_OP_REAL                 0x08000000
 
+#define DCACHE_PAR_LOOKUP              0x10000000 /* being looked up (with parent locked shared) */
+
 extern seqlock_t rename_lock;
 
 /*
        spin_unlock(&dentry->d_lock);
 }
 
+extern void __d_lookup_done(struct dentry *);
+
+static inline int d_in_lookup(struct dentry *dentry)
+{
+       return dentry->d_flags & DCACHE_PAR_LOOKUP;
+}
+
+static inline void d_lookup_done(struct dentry *dentry)
+{
+       if (unlikely(d_in_lookup(dentry))) {
+               spin_lock(&dentry->d_lock);
+               __d_lookup_done(dentry);
+               spin_unlock(&dentry->d_lock);
+       }
+}
+
 extern void dput(struct dentry *);
 
 static inline bool d_managed(const struct dentry *dentry)