}
 EXPORT_SYMBOL(have_submounts);
 
+/*
+ * Called by mount code to set a mountpoint and check if the mountpoint is
+ * reachable (e.g. NFS can unhash a directory dentry and then the complete
+ * subtree can become unreachable).
+ *
+ * Only one of check_submounts_and_drop() and d_set_mounted() must succeed.  For
+ * this reason take rename_lock and d_lock on dentry and ancestors.
+ */
+int d_set_mounted(struct dentry *dentry)
+{
+       struct dentry *p;
+       int ret = -ENOENT;
+       write_seqlock(&rename_lock);
+       for (p = dentry->d_parent; !IS_ROOT(p); p = p->d_parent) {
+               /* Need exclusion wrt. check_submounts_and_drop() */
+               spin_lock(&p->d_lock);
+               if (unlikely(d_unhashed(p))) {
+                       spin_unlock(&p->d_lock);
+                       goto out;
+               }
+               spin_unlock(&p->d_lock);
+       }
+       spin_lock(&dentry->d_lock);
+       if (!d_unlinked(dentry)) {
+               dentry->d_flags |= DCACHE_MOUNTED;
+               ret = 0;
+       }
+       spin_unlock(&dentry->d_lock);
+out:
+       write_sequnlock(&rename_lock);
+       return ret;
+}
+
 /*
  * Search the dentry child list of the specified parent,
  * and move any unused dentries to the end of the unused
 
 {
        struct list_head *chain = mountpoint_hashtable + hash(NULL, dentry);
        struct mountpoint *mp;
+       int ret;
 
        list_for_each_entry(mp, chain, m_hash) {
                if (mp->m_dentry == dentry) {
        if (!mp)
                return ERR_PTR(-ENOMEM);
 
-       spin_lock(&dentry->d_lock);
-       if (d_unlinked(dentry)) {
-               spin_unlock(&dentry->d_lock);
+       ret = d_set_mounted(dentry);
+       if (ret) {
                kfree(mp);
-               return ERR_PTR(-ENOENT);
+               return ERR_PTR(ret);
        }
-       dentry->d_flags |= DCACHE_MOUNTED;
-       spin_unlock(&dentry->d_lock);
+
        mp->m_dentry = dentry;
        mp->m_count = 1;
        list_add(&mp->m_hash, chain);