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 | |
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')
-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); |