[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:
parent
316bb95e8e
commit
45ec4ababe
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue