Commit 2edbfbf1 authored by Al Viro's avatar Al Viro

ecryptfs: don't leave RCU pathwalk immediately

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 3a93e17c
...@@ -44,15 +44,15 @@ ...@@ -44,15 +44,15 @@
*/ */
static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags) static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags)
{ {
struct dentry *lower_dentry; struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
int rc = 1; int rc;
if (!(lower_dentry->d_flags & DCACHE_OP_REVALIDATE))
return 1;
if (flags & LOOKUP_RCU) if (flags & LOOKUP_RCU)
return -ECHILD; 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); rc = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
if (dentry->d_inode) { if (dentry->d_inode) {
struct inode *lower_inode = struct inode *lower_inode =
...@@ -60,12 +60,17 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags) ...@@ -60,12 +60,17 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags)
fsstack_copy_attr_all(dentry->d_inode, lower_inode); fsstack_copy_attr_all(dentry->d_inode, lower_inode);
} }
out:
return rc; return rc;
} }
struct kmem_cache *ecryptfs_dentry_info_cache; 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 * ecryptfs_d_release
* @dentry: The ecryptfs dentry * @dentry: The ecryptfs dentry
...@@ -74,15 +79,12 @@ struct kmem_cache *ecryptfs_dentry_info_cache; ...@@ -74,15 +79,12 @@ struct kmem_cache *ecryptfs_dentry_info_cache;
*/ */
static void ecryptfs_d_release(struct dentry *dentry) static void ecryptfs_d_release(struct dentry *dentry)
{ {
if (ecryptfs_dentry_to_private(dentry)) { struct ecryptfs_dentry_info *p = dentry->d_fsdata;
if (ecryptfs_dentry_to_lower(dentry)) { if (p) {
dput(ecryptfs_dentry_to_lower(dentry)); if (p->lower_path.dentry)
mntput(ecryptfs_dentry_to_lower_mnt(dentry)); path_put(&p->lower_path);
} call_rcu(&p->rcu, ecryptfs_dentry_free_rcu);
kmem_cache_free(ecryptfs_dentry_info_cache,
ecryptfs_dentry_to_private(dentry));
} }
return;
} }
const struct dentry_operations ecryptfs_dops = { const struct dentry_operations ecryptfs_dops = {
......
...@@ -261,7 +261,10 @@ struct ecryptfs_inode_info { ...@@ -261,7 +261,10 @@ struct ecryptfs_inode_info {
* vfsmount too. */ * vfsmount too. */
struct ecryptfs_dentry_info { struct ecryptfs_dentry_info {
struct path lower_path; struct path lower_path;
struct ecryptfs_crypt_stat *crypt_stat; union {
struct ecryptfs_crypt_stat *crypt_stat;
struct rcu_head rcu;
};
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment