diff options
| author | Michael Halcrow <mhalcrow@us.ibm.com> | 2006-10-31 01:07:20 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-31 11:07:01 -0500 |
| commit | 45ec4ababe999cb95f9c0cad03b2689cb0b77a2b (patch) | |
| tree | 8d2ff3c5c356539bc87777948822741ca488ea6b /fs | |
| parent | 316bb95e8ed0ddcd767e8aa54264b6c6190f150c (diff) | |
[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>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/ecryptfs/dentry.c | 8 | ||||
| -rw-r--r-- | fs/ecryptfs/inode.c | 62 |
2 files changed, 27 insertions, 43 deletions
diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c index f0d2a433242b..0b9992ab990f 100644 --- a/fs/ecryptfs/dentry.c +++ b/fs/ecryptfs/dentry.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | 24 | ||
| 25 | #include <linux/dcache.h> | 25 | #include <linux/dcache.h> |
| 26 | #include <linux/namei.h> | 26 | #include <linux/namei.h> |
| 27 | #include <linux/mount.h> | ||
| 27 | #include "ecryptfs_kernel.h" | 28 | #include "ecryptfs_kernel.h" |
| 28 | 29 | ||
| 29 | /** | 30 | /** |
| @@ -76,8 +77,13 @@ static void ecryptfs_d_release(struct dentry *dentry) | |||
| 76 | if (ecryptfs_dentry_to_private(dentry)) | 77 | if (ecryptfs_dentry_to_private(dentry)) |
| 77 | kmem_cache_free(ecryptfs_dentry_info_cache, | 78 | kmem_cache_free(ecryptfs_dentry_info_cache, |
| 78 | ecryptfs_dentry_to_private(dentry)); | 79 | ecryptfs_dentry_to_private(dentry)); |
| 79 | if (lower_dentry) | 80 | if (lower_dentry) { |
| 81 | struct vfsmount *lower_mnt = | ||
| 82 | ecryptfs_dentry_to_lower_mnt(dentry); | ||
| 83 | |||
| 84 | mntput(lower_mnt); | ||
| 80 | dput(lower_dentry); | 85 | dput(lower_dentry); |
| 86 | } | ||
| 81 | return; | 87 | return; |
| 82 | } | 88 | } |
| 83 | 89 | ||
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 2f2c6cf972f7..ff4865d24f0f 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
| @@ -325,7 +325,6 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 325 | struct dentry *lower_dir_dentry; | 325 | struct dentry *lower_dir_dentry; |
| 326 | struct dentry *lower_dentry; | 326 | struct dentry *lower_dentry; |
| 327 | struct vfsmount *lower_mnt; | 327 | struct vfsmount *lower_mnt; |
| 328 | struct dentry *tlower_dentry = NULL; | ||
| 329 | char *encoded_name; | 328 | char *encoded_name; |
| 330 | unsigned int encoded_namelen; | 329 | unsigned int encoded_namelen; |
| 331 | struct ecryptfs_crypt_stat *crypt_stat = NULL; | 330 | struct ecryptfs_crypt_stat *crypt_stat = NULL; |
| @@ -336,27 +335,32 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 336 | lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent); | 335 | lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent); |
| 337 | dentry->d_op = &ecryptfs_dops; | 336 | dentry->d_op = &ecryptfs_dops; |
| 338 | if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, ".")) | 337 | if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, ".")) |
| 339 | || (dentry->d_name.len == 2 && !strcmp(dentry->d_name.name, ".."))) | 338 | || (dentry->d_name.len == 2 |
| 340 | goto out_drop; | 339 | && !strcmp(dentry->d_name.name, ".."))) { |
| 340 | d_drop(dentry); | ||
| 341 | goto out; | ||
| 342 | } | ||
| 341 | encoded_namelen = ecryptfs_encode_filename(crypt_stat, | 343 | encoded_namelen = ecryptfs_encode_filename(crypt_stat, |
| 342 | dentry->d_name.name, | 344 | dentry->d_name.name, |
| 343 | dentry->d_name.len, | 345 | dentry->d_name.len, |
| 344 | &encoded_name); | 346 | &encoded_name); |
| 345 | if (encoded_namelen < 0) { | 347 | if (encoded_namelen < 0) { |
| 346 | rc = encoded_namelen; | 348 | rc = encoded_namelen; |
| 347 | goto out_drop; | 349 | d_drop(dentry); |
| 350 | goto out; | ||
| 348 | } | 351 | } |
| 349 | ecryptfs_printk(KERN_DEBUG, "encoded_name = [%s]; encoded_namelen " | 352 | ecryptfs_printk(KERN_DEBUG, "encoded_name = [%s]; encoded_namelen " |
| 350 | "= [%d]\n", encoded_name, encoded_namelen); | 353 | "= [%d]\n", encoded_name, encoded_namelen); |
| 351 | lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry, | 354 | lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry, |
| 352 | encoded_namelen - 1); | 355 | encoded_namelen - 1); |
| 353 | kfree(encoded_name); | 356 | kfree(encoded_name); |
| 354 | lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); | ||
| 355 | if (IS_ERR(lower_dentry)) { | 357 | if (IS_ERR(lower_dentry)) { |
| 356 | ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n"); | 358 | ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n"); |
| 357 | rc = PTR_ERR(lower_dentry); | 359 | rc = PTR_ERR(lower_dentry); |
| 358 | goto out_drop; | 360 | d_drop(dentry); |
| 361 | goto out; | ||
| 359 | } | 362 | } |
| 363 | lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); | ||
| 360 | ecryptfs_printk(KERN_DEBUG, "lower_dentry = [%p]; lower_dentry->" | 364 | ecryptfs_printk(KERN_DEBUG, "lower_dentry = [%p]; lower_dentry->" |
| 361 | "d_name.name = [%s]\n", lower_dentry, | 365 | "d_name.name = [%s]\n", lower_dentry, |
| 362 | lower_dentry->d_name.name); | 366 | lower_dentry->d_name.name); |
| @@ -397,12 +401,6 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 397 | "as we *think* we are about to unlink\n"); | 401 | "as we *think* we are about to unlink\n"); |
| 398 | goto out; | 402 | goto out; |
| 399 | } | 403 | } |
| 400 | tlower_dentry = dget(lower_dentry); | ||
| 401 | if (!tlower_dentry || IS_ERR(tlower_dentry)) { | ||
| 402 | rc = -ENOMEM; | ||
| 403 | ecryptfs_printk(KERN_ERR, "Cannot dget lower_dentry\n"); | ||
| 404 | goto out_dput; | ||
| 405 | } | ||
| 406 | /* Released in this function */ | 404 | /* Released in this function */ |
| 407 | page_virt = | 405 | page_virt = |
| 408 | (char *)kmem_cache_alloc(ecryptfs_header_cache_2, | 406 | (char *)kmem_cache_alloc(ecryptfs_header_cache_2, |
| @@ -414,7 +412,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 414 | goto out_dput; | 412 | goto out_dput; |
| 415 | } | 413 | } |
| 416 | memset(page_virt, 0, PAGE_CACHE_SIZE); | 414 | memset(page_virt, 0, PAGE_CACHE_SIZE); |
| 417 | rc = ecryptfs_read_header_region(page_virt, tlower_dentry, nd->mnt); | 415 | rc = ecryptfs_read_header_region(page_virt, lower_dentry, nd->mnt); |
| 418 | crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; | 416 | crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; |
| 419 | if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) | 417 | if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) |
| 420 | ecryptfs_set_default_sizes(crypt_stat); | 418 | ecryptfs_set_default_sizes(crypt_stat); |
| @@ -437,9 +435,6 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 437 | 435 | ||
| 438 | out_dput: | 436 | out_dput: |
| 439 | dput(lower_dentry); | 437 | dput(lower_dentry); |
| 440 | if (tlower_dentry) | ||
| 441 | dput(tlower_dentry); | ||
| 442 | out_drop: | ||
| 443 | d_drop(dentry); | 438 | d_drop(dentry); |
| 444 | out: | 439 | out: |
| 445 | return ERR_PTR(rc); | 440 | return ERR_PTR(rc); |
| @@ -475,8 +470,8 @@ out_lock: | |||
| 475 | unlock_dir(lower_dir_dentry); | 470 | unlock_dir(lower_dir_dentry); |
| 476 | dput(lower_new_dentry); | 471 | dput(lower_new_dentry); |
| 477 | dput(lower_old_dentry); | 472 | dput(lower_old_dentry); |
| 478 | if (!new_dentry->d_inode) | 473 | d_drop(new_dentry); |
| 479 | d_drop(new_dentry); | 474 | d_drop(old_dentry); |
| 480 | return rc; | 475 | return rc; |
| 481 | } | 476 | } |
| 482 | 477 | ||
| @@ -565,41 +560,24 @@ out: | |||
| 565 | 560 | ||
| 566 | static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) | 561 | static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) |
| 567 | { | 562 | { |
| 568 | int rc = 0; | ||
| 569 | struct dentry *tdentry = NULL; | ||
| 570 | struct dentry *lower_dentry; | 563 | struct dentry *lower_dentry; |
| 571 | struct dentry *tlower_dentry = NULL; | ||
| 572 | struct dentry *lower_dir_dentry; | 564 | struct dentry *lower_dir_dentry; |
| 565 | int rc; | ||
| 573 | 566 | ||
| 574 | lower_dentry = ecryptfs_dentry_to_lower(dentry); | 567 | lower_dentry = ecryptfs_dentry_to_lower(dentry); |
| 575 | if (!(tdentry = dget(dentry))) { | 568 | dget(dentry); |
| 576 | rc = -EINVAL; | ||
| 577 | ecryptfs_printk(KERN_ERR, "Error dget'ing dentry [%p]\n", | ||
| 578 | dentry); | ||
| 579 | goto out; | ||
| 580 | } | ||
| 581 | lower_dir_dentry = lock_parent(lower_dentry); | 569 | lower_dir_dentry = lock_parent(lower_dentry); |
| 582 | if (!(tlower_dentry = dget(lower_dentry))) { | 570 | dget(lower_dentry); |
| 583 | rc = -EINVAL; | ||
| 584 | ecryptfs_printk(KERN_ERR, "Error dget'ing lower_dentry " | ||
| 585 | "[%p]\n", lower_dentry); | ||
| 586 | goto out; | ||
| 587 | } | ||
| 588 | rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); | 571 | rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); |
| 589 | if (!rc) { | 572 | dput(lower_dentry); |
| 590 | d_delete(tlower_dentry); | 573 | if (!rc) |
| 591 | tlower_dentry = NULL; | 574 | d_delete(lower_dentry); |
| 592 | } | ||
| 593 | ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode); | 575 | ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode); |
| 594 | dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; | 576 | dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; |
| 595 | unlock_dir(lower_dir_dentry); | 577 | unlock_dir(lower_dir_dentry); |
| 596 | if (!rc) | 578 | if (!rc) |
| 597 | d_drop(dentry); | 579 | d_drop(dentry); |
| 598 | out: | 580 | dput(dentry); |
| 599 | if (tdentry) | ||
| 600 | dput(tdentry); | ||
| 601 | if (tlower_dentry) | ||
| 602 | dput(tlower_dentry); | ||
| 603 | return rc; | 581 | return rc; |
| 604 | } | 582 | } |
| 605 | 583 | ||
