vfs: check unlinked ancestors before mount
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / dcache.c
index ce5a7e6..761e31b 100644 (file)
@@ -1184,6 +1184,39 @@ int have_submounts(struct dentry *parent)
 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
  * list for prune_dcache(). We descend to the next level