EXPORT_SYMBOL(fscrypt_decrypt_page);
 
 /*
- * Validate dentries for encrypted directories to make sure we aren't
- * potentially caching stale data after a key has been added or
- * removed.
+ * Validate dentries in encrypted directories to make sure we aren't potentially
+ * caching stale dentries after a key has been added.
  */
 static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
        struct dentry *dir;
-       int dir_has_key, cached_with_key;
+       int err;
+       int valid;
+
+       /*
+        * Plaintext names are always valid, since fscrypt doesn't support
+        * reverting to ciphertext names without evicting the directory's inode
+        * -- which implies eviction of the dentries in the directory.
+        */
+       if (!(dentry->d_flags & DCACHE_ENCRYPTED_NAME))
+               return 1;
+
+       /*
+        * Ciphertext name; valid if the directory's key is still unavailable.
+        *
+        * Although fscrypt forbids rename() on ciphertext names, we still must
+        * use dget_parent() here rather than use ->d_parent directly.  That's
+        * because a corrupted fs image may contain directory hard links, which
+        * the VFS handles by moving the directory's dentry tree in the dcache
+        * each time ->lookup() finds the directory and it already has a dentry
+        * elsewhere.  Thus ->d_parent can be changing, and we must safely grab
+        * a reference to some ->d_parent to prevent it from being freed.
+        */
 
        if (flags & LOOKUP_RCU)
                return -ECHILD;
 
        dir = dget_parent(dentry);
-       if (!IS_ENCRYPTED(d_inode(dir))) {
-               dput(dir);
-               return 0;
-       }
-
-       spin_lock(&dentry->d_lock);
-       cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;
-       spin_unlock(&dentry->d_lock);
-       dir_has_key = fscrypt_has_encryption_key(d_inode(dir));
+       err = fscrypt_get_encryption_info(d_inode(dir));
+       valid = !fscrypt_has_encryption_key(d_inode(dir));
        dput(dir);
 
-       /*
-        * If the dentry was cached without the key, and it is a
-        * negative dentry, it might be a valid name.  We can't check
-        * if the key has since been made available due to locking
-        * reasons, so we fail the validation so ext4_lookup() can do
-        * this check.
-        *
-        * We also fail the validation if the dentry was created with
-        * the key present, but we no longer have the key, or vice versa.
-        */
-       if ((!cached_with_key && d_is_negative(dentry)) ||
-                       (!cached_with_key && dir_has_key) ||
-                       (cached_with_key && !dir_has_key))
-               return 0;
-       return 1;
+       if (err < 0)
+               return err;
+
+       return valid;
 }
 
 const struct dentry_operations fscrypt_d_ops = {
 
  * filenames are presented in encrypted form.  Therefore, we'll try to set up
  * the directory's encryption key, but even without it the lookup can continue.
  *
- * To allow invalidating stale dentries if the directory's encryption key is
- * added later, we also install a custom ->d_revalidate() method and use the
- * DCACHE_ENCRYPTED_WITH_KEY flag to indicate whether a given dentry is a
- * plaintext name (flag set) or a ciphertext name (flag cleared).
+ * This also installs a custom ->d_revalidate() method which will invalidate the
+ * dentry if it was created without the key and the key is later added.
  *
  * Return: 0 on success, -errno if a problem occurred while setting up the
  * encryption key