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: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2013-09-15 20:45:11 -04:00
parent 3a93e17cf6
commit 2edbfbf1c1
2 changed files with 20 additions and 15 deletions

View File

@ -44,15 +44,15 @@
*/
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 = {

View 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;
};
};
/**