diff options
| author | Tyler Hicks <tyhicks@linux.vnet.ibm.com> | 2009-10-14 17:18:27 -0400 |
|---|---|---|
| committer | Tyler Hicks <tyhicks@linux.vnet.ibm.com> | 2010-01-19 23:32:07 -0500 |
| commit | 5f3ef64f4da1c587cdcfaaac72311225b7df094c (patch) | |
| tree | 0bdf086980df60d73bc650cdc520b59029faaa5a /fs/ecryptfs | |
| parent | 24bc7347da73a9ed3383056c3d0f28c0e361621e (diff) | |
eCryptfs: Use notify_change for truncating lower inodes
When truncating inodes in the lower filesystem, eCryptfs directly
invoked vmtruncate(). As Christoph Hellwig pointed out, vmtruncate() is
a filesystem helper function, but filesystems may need to do more than
just a call to vmtruncate().
This patch moves the lower inode truncation out of ecryptfs_truncate()
and renames the function to truncate_upper(). truncate_upper() updates
an iattr for the lower inode to indicate if the lower inode needs to be
truncated upon return. ecryptfs_setattr() then calls notify_change(),
using the updated iattr for the lower inode, to complete the truncation.
For eCryptfs functions needing to truncate, ecryptfs_truncate() is
reintroduced as a simple way to truncate the upper inode to a specified
size and then truncate the lower inode accordingly.
https://bugs.launchpad.net/bugs/451368
Reported-by: Christoph Hellwig <hch@lst.de>
Acked-by: Dustin Kirkland <kirkland@canonical.com>
Cc: ecryptfs-devel@lists.launchpad.net
Cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com>
Diffstat (limited to 'fs/ecryptfs')
| -rw-r--r-- | fs/ecryptfs/inode.c | 99 |
1 files changed, 67 insertions, 32 deletions
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 7f8545032930..2b449d79b7fa 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
| @@ -772,18 +772,23 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, | |||
| 772 | } | 772 | } |
| 773 | 773 | ||
| 774 | /** | 774 | /** |
| 775 | * ecryptfs_truncate | 775 | * truncate_upper |
| 776 | * @dentry: The ecryptfs layer dentry | 776 | * @dentry: The ecryptfs layer dentry |
| 777 | * @new_length: The length to expand the file to | 777 | * @ia: Address of the ecryptfs inode's attributes |
| 778 | * @lower_ia: Address of the lower inode's attributes | ||
| 778 | * | 779 | * |
| 779 | * Function to handle truncations modifying the size of the file. Note | 780 | * Function to handle truncations modifying the size of the file. Note |
| 780 | * that the file sizes are interpolated. When expanding, we are simply | 781 | * that the file sizes are interpolated. When expanding, we are simply |
| 781 | * writing strings of 0's out. When truncating, we need to modify the | 782 | * writing strings of 0's out. When truncating, we truncate the upper |
| 782 | * underlying file size according to the page index interpolations. | 783 | * inode and update the lower_ia according to the page index |
| 784 | * interpolations. If ATTR_SIZE is set in lower_ia->ia_valid upon return, | ||
| 785 | * the caller must use lower_ia in a call to notify_change() to perform | ||
| 786 | * the truncation of the lower inode. | ||
| 783 | * | 787 | * |
| 784 | * Returns zero on success; non-zero otherwise | 788 | * Returns zero on success; non-zero otherwise |
| 785 | */ | 789 | */ |
| 786 | int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | 790 | static int truncate_upper(struct dentry *dentry, struct iattr *ia, |
| 791 | struct iattr *lower_ia) | ||
| 787 | { | 792 | { |
| 788 | int rc = 0; | 793 | int rc = 0; |
| 789 | struct inode *inode = dentry->d_inode; | 794 | struct inode *inode = dentry->d_inode; |
| @@ -794,8 +799,10 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
| 794 | loff_t lower_size_before_truncate; | 799 | loff_t lower_size_before_truncate; |
| 795 | loff_t lower_size_after_truncate; | 800 | loff_t lower_size_after_truncate; |
| 796 | 801 | ||
| 797 | if (unlikely((new_length == i_size))) | 802 | if (unlikely((ia->ia_size == i_size))) { |
| 803 | lower_ia->ia_valid &= ~ATTR_SIZE; | ||
| 798 | goto out; | 804 | goto out; |
| 805 | } | ||
| 799 | crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; | 806 | crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; |
| 800 | /* Set up a fake ecryptfs file, this is used to interface with | 807 | /* Set up a fake ecryptfs file, this is used to interface with |
| 801 | * the file in the underlying filesystem so that the | 808 | * the file in the underlying filesystem so that the |
| @@ -815,28 +822,30 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
| 815 | &fake_ecryptfs_file, | 822 | &fake_ecryptfs_file, |
| 816 | ecryptfs_inode_to_private(dentry->d_inode)->lower_file); | 823 | ecryptfs_inode_to_private(dentry->d_inode)->lower_file); |
| 817 | /* Switch on growing or shrinking file */ | 824 | /* Switch on growing or shrinking file */ |
| 818 | if (new_length > i_size) { | 825 | if (ia->ia_size > i_size) { |
| 819 | char zero[] = { 0x00 }; | 826 | char zero[] = { 0x00 }; |
| 820 | 827 | ||
| 828 | lower_ia->ia_valid &= ~ATTR_SIZE; | ||
| 821 | /* Write a single 0 at the last position of the file; | 829 | /* Write a single 0 at the last position of the file; |
| 822 | * this triggers code that will fill in 0's throughout | 830 | * this triggers code that will fill in 0's throughout |
| 823 | * the intermediate portion of the previous end of the | 831 | * the intermediate portion of the previous end of the |
| 824 | * file and the new and of the file */ | 832 | * file and the new and of the file */ |
| 825 | rc = ecryptfs_write(&fake_ecryptfs_file, zero, | 833 | rc = ecryptfs_write(&fake_ecryptfs_file, zero, |
| 826 | (new_length - 1), 1); | 834 | (ia->ia_size - 1), 1); |
| 827 | } else { /* new_length < i_size_read(inode) */ | 835 | } else { /* ia->ia_size < i_size_read(inode) */ |
| 828 | /* We're chopping off all the pages down do the page | 836 | /* We're chopping off all the pages down to the page |
| 829 | * in which new_length is located. Fill in the end of | 837 | * in which ia->ia_size is located. Fill in the end of |
| 830 | * that page from (new_length & ~PAGE_CACHE_MASK) to | 838 | * that page from (ia->ia_size & ~PAGE_CACHE_MASK) to |
| 831 | * PAGE_CACHE_SIZE with zeros. */ | 839 | * PAGE_CACHE_SIZE with zeros. */ |
| 832 | size_t num_zeros = (PAGE_CACHE_SIZE | 840 | size_t num_zeros = (PAGE_CACHE_SIZE |
| 833 | - (new_length & ~PAGE_CACHE_MASK)); | 841 | - (ia->ia_size & ~PAGE_CACHE_MASK)); |
| 834 | 842 | ||
| 835 | if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { | 843 | if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { |
| 836 | rc = vmtruncate(inode, new_length); | 844 | rc = vmtruncate(inode, ia->ia_size); |
| 837 | if (rc) | 845 | if (rc) |
| 838 | goto out_free; | 846 | goto out_free; |
| 839 | rc = vmtruncate(lower_dentry->d_inode, new_length); | 847 | lower_ia->ia_size = ia->ia_size; |
| 848 | lower_ia->ia_valid |= ATTR_SIZE; | ||
| 840 | goto out_free; | 849 | goto out_free; |
| 841 | } | 850 | } |
| 842 | if (num_zeros) { | 851 | if (num_zeros) { |
| @@ -848,7 +857,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
| 848 | goto out_free; | 857 | goto out_free; |
| 849 | } | 858 | } |
| 850 | rc = ecryptfs_write(&fake_ecryptfs_file, zeros_virt, | 859 | rc = ecryptfs_write(&fake_ecryptfs_file, zeros_virt, |
| 851 | new_length, num_zeros); | 860 | ia->ia_size, num_zeros); |
| 852 | kfree(zeros_virt); | 861 | kfree(zeros_virt); |
| 853 | if (rc) { | 862 | if (rc) { |
| 854 | printk(KERN_ERR "Error attempting to zero out " | 863 | printk(KERN_ERR "Error attempting to zero out " |
| @@ -857,7 +866,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
| 857 | goto out_free; | 866 | goto out_free; |
| 858 | } | 867 | } |
| 859 | } | 868 | } |
| 860 | vmtruncate(inode, new_length); | 869 | vmtruncate(inode, ia->ia_size); |
| 861 | rc = ecryptfs_write_inode_size_to_metadata(inode); | 870 | rc = ecryptfs_write_inode_size_to_metadata(inode); |
| 862 | if (rc) { | 871 | if (rc) { |
| 863 | printk(KERN_ERR "Problem with " | 872 | printk(KERN_ERR "Problem with " |
| @@ -870,10 +879,12 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
| 870 | lower_size_before_truncate = | 879 | lower_size_before_truncate = |
| 871 | upper_size_to_lower_size(crypt_stat, i_size); | 880 | upper_size_to_lower_size(crypt_stat, i_size); |
| 872 | lower_size_after_truncate = | 881 | lower_size_after_truncate = |
| 873 | upper_size_to_lower_size(crypt_stat, new_length); | 882 | upper_size_to_lower_size(crypt_stat, ia->ia_size); |
| 874 | if (lower_size_after_truncate < lower_size_before_truncate) | 883 | if (lower_size_after_truncate < lower_size_before_truncate) { |
| 875 | vmtruncate(lower_dentry->d_inode, | 884 | lower_ia->ia_size = lower_size_after_truncate; |
| 876 | lower_size_after_truncate); | 885 | lower_ia->ia_valid |= ATTR_SIZE; |
| 886 | } else | ||
| 887 | lower_ia->ia_valid &= ~ATTR_SIZE; | ||
| 877 | } | 888 | } |
| 878 | out_free: | 889 | out_free: |
| 879 | if (ecryptfs_file_to_private(&fake_ecryptfs_file)) | 890 | if (ecryptfs_file_to_private(&fake_ecryptfs_file)) |
| @@ -883,6 +894,33 @@ out: | |||
| 883 | return rc; | 894 | return rc; |
| 884 | } | 895 | } |
| 885 | 896 | ||
| 897 | /** | ||
| 898 | * ecryptfs_truncate | ||
| 899 | * @dentry: The ecryptfs layer dentry | ||
| 900 | * @new_length: The length to expand the file to | ||
| 901 | * | ||
| 902 | * Simple function that handles the truncation of an eCryptfs inode and | ||
| 903 | * its corresponding lower inode. | ||
| 904 | * | ||
| 905 | * Returns zero on success; non-zero otherwise | ||
| 906 | */ | ||
| 907 | int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | ||
| 908 | { | ||
| 909 | struct iattr ia = { .ia_valid = ATTR_SIZE, .ia_size = new_length }; | ||
| 910 | struct iattr lower_ia = { .ia_valid = 0 }; | ||
| 911 | int rc; | ||
| 912 | |||
| 913 | rc = truncate_upper(dentry, &ia, &lower_ia); | ||
| 914 | if (!rc && lower_ia.ia_valid & ATTR_SIZE) { | ||
| 915 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); | ||
| 916 | |||
| 917 | mutex_lock(&lower_dentry->d_inode->i_mutex); | ||
| 918 | rc = notify_change(lower_dentry, &lower_ia); | ||
| 919 | mutex_unlock(&lower_dentry->d_inode->i_mutex); | ||
| 920 | } | ||
| 921 | return rc; | ||
| 922 | } | ||
| 923 | |||
| 886 | static int | 924 | static int |
| 887 | ecryptfs_permission(struct inode *inode, int mask) | 925 | ecryptfs_permission(struct inode *inode, int mask) |
| 888 | { | 926 | { |
| @@ -905,6 +943,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) | |||
| 905 | { | 943 | { |
| 906 | int rc = 0; | 944 | int rc = 0; |
| 907 | struct dentry *lower_dentry; | 945 | struct dentry *lower_dentry; |
| 946 | struct iattr lower_ia; | ||
| 908 | struct inode *inode; | 947 | struct inode *inode; |
| 909 | struct inode *lower_inode; | 948 | struct inode *lower_inode; |
| 910 | struct ecryptfs_crypt_stat *crypt_stat; | 949 | struct ecryptfs_crypt_stat *crypt_stat; |
| @@ -943,15 +982,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) | |||
| 943 | } | 982 | } |
| 944 | } | 983 | } |
| 945 | mutex_unlock(&crypt_stat->cs_mutex); | 984 | mutex_unlock(&crypt_stat->cs_mutex); |
| 985 | memcpy(&lower_ia, ia, sizeof(lower_ia)); | ||
| 986 | if (ia->ia_valid & ATTR_FILE) | ||
| 987 | lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file); | ||
| 946 | if (ia->ia_valid & ATTR_SIZE) { | 988 | if (ia->ia_valid & ATTR_SIZE) { |
| 947 | ecryptfs_printk(KERN_DEBUG, | 989 | rc = truncate_upper(dentry, ia, &lower_ia); |
| 948 | "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n", | ||
| 949 | ia->ia_valid, ATTR_SIZE); | ||
| 950 | rc = ecryptfs_truncate(dentry, ia->ia_size); | ||
| 951 | /* ecryptfs_truncate handles resizing of the lower file */ | ||
| 952 | ia->ia_valid &= ~ATTR_SIZE; | ||
| 953 | ecryptfs_printk(KERN_DEBUG, "ia->ia_valid = [%x]\n", | ||
| 954 | ia->ia_valid); | ||
| 955 | if (rc < 0) | 990 | if (rc < 0) |
| 956 | goto out; | 991 | goto out; |
| 957 | } | 992 | } |
| @@ -960,11 +995,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) | |||
| 960 | * mode change is for clearing setuid/setgid bits. Allow lower fs | 995 | * mode change is for clearing setuid/setgid bits. Allow lower fs |
| 961 | * to interpret this in its own way. | 996 | * to interpret this in its own way. |
| 962 | */ | 997 | */ |
| 963 | if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) | 998 | if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) |
| 964 | ia->ia_valid &= ~ATTR_MODE; | 999 | lower_ia.ia_valid &= ~ATTR_MODE; |
| 965 | 1000 | ||
| 966 | mutex_lock(&lower_dentry->d_inode->i_mutex); | 1001 | mutex_lock(&lower_dentry->d_inode->i_mutex); |
| 967 | rc = notify_change(lower_dentry, ia); | 1002 | rc = notify_change(lower_dentry, &lower_ia); |
| 968 | mutex_unlock(&lower_dentry->d_inode->i_mutex); | 1003 | mutex_unlock(&lower_dentry->d_inode->i_mutex); |
| 969 | out: | 1004 | out: |
| 970 | fsstack_copy_attr_all(inode, lower_inode); | 1005 | fsstack_copy_attr_all(inode, lower_inode); |
