[PATCH] eCryptfs: Fix handling of lower d_count

Fix the use of dget/dput calls to balance out on the lower filesystem.

Signed-off-by: Michael Halcrow <mhalcrow@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Michael Halcrow 2006-10-30 22:07:20 -08:00 committed by Linus Torvalds
parent 316bb95e8e
commit 45ec4ababe
2 changed files with 27 additions and 43 deletions

View File

@ -24,6 +24,7 @@
#include <linux/dcache.h> #include <linux/dcache.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/mount.h>
#include "ecryptfs_kernel.h" #include "ecryptfs_kernel.h"
/** /**
@ -76,8 +77,13 @@ static void ecryptfs_d_release(struct dentry *dentry)
if (ecryptfs_dentry_to_private(dentry)) if (ecryptfs_dentry_to_private(dentry))
kmem_cache_free(ecryptfs_dentry_info_cache, kmem_cache_free(ecryptfs_dentry_info_cache,
ecryptfs_dentry_to_private(dentry)); ecryptfs_dentry_to_private(dentry));
if (lower_dentry) if (lower_dentry) {
struct vfsmount *lower_mnt =
ecryptfs_dentry_to_lower_mnt(dentry);
mntput(lower_mnt);
dput(lower_dentry); dput(lower_dentry);
}
return; return;
} }

View File

@ -325,7 +325,6 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
struct dentry *lower_dir_dentry; struct dentry *lower_dir_dentry;
struct dentry *lower_dentry; struct dentry *lower_dentry;
struct vfsmount *lower_mnt; struct vfsmount *lower_mnt;
struct dentry *tlower_dentry = NULL;
char *encoded_name; char *encoded_name;
unsigned int encoded_namelen; unsigned int encoded_namelen;
struct ecryptfs_crypt_stat *crypt_stat = NULL; struct ecryptfs_crypt_stat *crypt_stat = NULL;
@ -336,27 +335,32 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent); lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent);
dentry->d_op = &ecryptfs_dops; dentry->d_op = &ecryptfs_dops;
if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, ".")) if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, "."))
|| (dentry->d_name.len == 2 && !strcmp(dentry->d_name.name, ".."))) || (dentry->d_name.len == 2
goto out_drop; && !strcmp(dentry->d_name.name, ".."))) {
d_drop(dentry);
goto out;
}
encoded_namelen = ecryptfs_encode_filename(crypt_stat, encoded_namelen = ecryptfs_encode_filename(crypt_stat,
dentry->d_name.name, dentry->d_name.name,
dentry->d_name.len, dentry->d_name.len,
&encoded_name); &encoded_name);
if (encoded_namelen < 0) { if (encoded_namelen < 0) {
rc = encoded_namelen; rc = encoded_namelen;
goto out_drop; d_drop(dentry);
goto out;
} }
ecryptfs_printk(KERN_DEBUG, "encoded_name = [%s]; encoded_namelen " ecryptfs_printk(KERN_DEBUG, "encoded_name = [%s]; encoded_namelen "
"= [%d]\n", encoded_name, encoded_namelen); "= [%d]\n", encoded_name, encoded_namelen);
lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry, lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry,
encoded_namelen - 1); encoded_namelen - 1);
kfree(encoded_name); kfree(encoded_name);
lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
if (IS_ERR(lower_dentry)) { if (IS_ERR(lower_dentry)) {
ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n"); ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n");
rc = PTR_ERR(lower_dentry); rc = PTR_ERR(lower_dentry);
goto out_drop; d_drop(dentry);
goto out;
} }
lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
ecryptfs_printk(KERN_DEBUG, "lower_dentry = [%p]; lower_dentry->" ecryptfs_printk(KERN_DEBUG, "lower_dentry = [%p]; lower_dentry->"
"d_name.name = [%s]\n", lower_dentry, "d_name.name = [%s]\n", lower_dentry,
lower_dentry->d_name.name); lower_dentry->d_name.name);
@ -397,12 +401,6 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
"as we *think* we are about to unlink\n"); "as we *think* we are about to unlink\n");
goto out; goto out;
} }
tlower_dentry = dget(lower_dentry);
if (!tlower_dentry || IS_ERR(tlower_dentry)) {
rc = -ENOMEM;
ecryptfs_printk(KERN_ERR, "Cannot dget lower_dentry\n");
goto out_dput;
}
/* Released in this function */ /* Released in this function */
page_virt = page_virt =
(char *)kmem_cache_alloc(ecryptfs_header_cache_2, (char *)kmem_cache_alloc(ecryptfs_header_cache_2,
@ -414,7 +412,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
goto out_dput; goto out_dput;
} }
memset(page_virt, 0, PAGE_CACHE_SIZE); memset(page_virt, 0, PAGE_CACHE_SIZE);
rc = ecryptfs_read_header_region(page_virt, tlower_dentry, nd->mnt); rc = ecryptfs_read_header_region(page_virt, lower_dentry, nd->mnt);
crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED))
ecryptfs_set_default_sizes(crypt_stat); ecryptfs_set_default_sizes(crypt_stat);
@ -437,9 +435,6 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
out_dput: out_dput:
dput(lower_dentry); dput(lower_dentry);
if (tlower_dentry)
dput(tlower_dentry);
out_drop:
d_drop(dentry); d_drop(dentry);
out: out:
return ERR_PTR(rc); return ERR_PTR(rc);
@ -475,8 +470,8 @@ out_lock:
unlock_dir(lower_dir_dentry); unlock_dir(lower_dir_dentry);
dput(lower_new_dentry); dput(lower_new_dentry);
dput(lower_old_dentry); dput(lower_old_dentry);
if (!new_dentry->d_inode) d_drop(new_dentry);
d_drop(new_dentry); d_drop(old_dentry);
return rc; return rc;
} }
@ -565,41 +560,24 @@ out:
static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
{ {
int rc = 0;
struct dentry *tdentry = NULL;
struct dentry *lower_dentry; struct dentry *lower_dentry;
struct dentry *tlower_dentry = NULL;
struct dentry *lower_dir_dentry; struct dentry *lower_dir_dentry;
int rc;
lower_dentry = ecryptfs_dentry_to_lower(dentry); lower_dentry = ecryptfs_dentry_to_lower(dentry);
if (!(tdentry = dget(dentry))) { dget(dentry);
rc = -EINVAL;
ecryptfs_printk(KERN_ERR, "Error dget'ing dentry [%p]\n",
dentry);
goto out;
}
lower_dir_dentry = lock_parent(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry);
if (!(tlower_dentry = dget(lower_dentry))) { dget(lower_dentry);
rc = -EINVAL;
ecryptfs_printk(KERN_ERR, "Error dget'ing lower_dentry "
"[%p]\n", lower_dentry);
goto out;
}
rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
if (!rc) { dput(lower_dentry);
d_delete(tlower_dentry); if (!rc)
tlower_dentry = NULL; d_delete(lower_dentry);
}
ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode); ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode);
dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
unlock_dir(lower_dir_dentry); unlock_dir(lower_dir_dentry);
if (!rc) if (!rc)
d_drop(dentry); d_drop(dentry);
out: dput(dentry);
if (tdentry)
dput(tdentry);
if (tlower_dentry)
dput(tlower_dentry);
return rc; return rc;
} }