ecryptfs: don't leave RCU pathwalk immediately
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 16 Sep 2013 00:45:11 +0000 (20:45 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 25 Oct 2013 03:34:48 +0000 (23:34 -0400)
If the underlying dentry doesn't have ->d_revalidate(), there's no need to
force dropping out of RCU mode.  All we need for that is to make freeing
ecryptfs_dentry_info RCU-delayed.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/ecryptfs/dentry.c
fs/ecryptfs/ecryptfs_kernel.h

index 46e31c92e574dbd0ae38a0badbc6222943f3ebc3..8cefa8e13bccdc4c8eefe26c54a88c14378cf8f9 100644 (file)
  */
 static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags)
 {
-       struct dentry *lower_dentry;
-       int rc = 1;
+       struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+       int rc;
+
+       if (!(lower_dentry->d_flags & DCACHE_OP_REVALIDATE))
+               return 1;
 
        if (flags & LOOKUP_RCU)
                return -ECHILD;
 
-       lower_dentry = ecryptfs_dentry_to_lower(dentry);
-       if (!(lower_dentry->d_flags & DCACHE_OP_REVALIDATE))
-               goto out;
        rc = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
        if (dentry->d_inode) {
                struct inode *lower_inode =
@@ -60,12 +60,17 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags)
 
                fsstack_copy_attr_all(dentry->d_inode, lower_inode);
        }
-out:
        return rc;
 }
 
 struct kmem_cache *ecryptfs_dentry_info_cache;
 
+static void ecryptfs_dentry_free_rcu(struct rcu_head *head)
+{
+       kmem_cache_free(ecryptfs_dentry_info_cache,
+               container_of(head, struct ecryptfs_dentry_info, rcu));
+}
+
 /**
  * ecryptfs_d_release
  * @dentry: The ecryptfs dentry
@@ -74,15 +79,12 @@ struct kmem_cache *ecryptfs_dentry_info_cache;
  */
 static void ecryptfs_d_release(struct dentry *dentry)
 {
-       if (ecryptfs_dentry_to_private(dentry)) {
-               if (ecryptfs_dentry_to_lower(dentry)) {
-                       dput(ecryptfs_dentry_to_lower(dentry));
-                       mntput(ecryptfs_dentry_to_lower_mnt(dentry));
-               }
-               kmem_cache_free(ecryptfs_dentry_info_cache,
-                               ecryptfs_dentry_to_private(dentry));
+       struct ecryptfs_dentry_info *p = dentry->d_fsdata;
+       if (p) {
+               if (p->lower_path.dentry)
+                       path_put(&p->lower_path);
+               call_rcu(&p->rcu, ecryptfs_dentry_free_rcu);
        }
-       return;
 }
 
 const struct dentry_operations ecryptfs_dops = {
index df19d34a033b9521de8623bb33ff2de6c0d9361a..e7ad2b3f24a7f3c44b8226aa34b0bbde3682e917 100644 (file)
@@ -261,7 +261,10 @@ struct ecryptfs_inode_info {
  * vfsmount too. */
 struct ecryptfs_dentry_info {
        struct path lower_path;
-       struct ecryptfs_crypt_stat *crypt_stat;
+       union {
+               struct ecryptfs_crypt_stat *crypt_stat;
+               struct rcu_head rcu;
+       };
 };
 
 /**