diff options
author | Michael Halcrow <mhalcrow@us.ibm.com> | 2007-10-16 04:28:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-16 12:43:12 -0400 |
commit | 2ed92554abc5c40d4450f9869c9565a1919a9242 (patch) | |
tree | 3b9be8b86474ad61d357990185476fc56ac2f490 /fs | |
parent | d7cdc5febf9f2664755002c3a2f84bd348389fe9 (diff) |
eCryptfs: make open, truncate, and setattr use persistent file
Rather than open a new lower file for every eCryptfs file that is opened,
truncated, or setattr'd, instead use the existing lower persistent file for
the eCryptfs inode. Change truncate to use read_write.c functions. Change
ecryptfs_getxattr() to use the common ecryptfs_getxattr_lower() function.
Signed-off-by: Michael Halcrow <mhalcrow@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ecryptfs/crypto.c | 2 | ||||
-rw-r--r-- | fs/ecryptfs/file.c | 50 | ||||
-rw-r--r-- | fs/ecryptfs/inode.c | 113 |
3 files changed, 44 insertions, 121 deletions
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 55110ffe9ebd..26070d69e59a 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c | |||
@@ -1673,7 +1673,7 @@ out: | |||
1673 | /** | 1673 | /** |
1674 | * ecryptfs_read_xattr_region | 1674 | * ecryptfs_read_xattr_region |
1675 | * @page_virt: The vitual address into which to read the xattr data | 1675 | * @page_virt: The vitual address into which to read the xattr data |
1676 | * @ecryptfs_dentry: The eCryptfs dentry | 1676 | * @ecryptfs_inode: The eCryptfs inode |
1677 | * | 1677 | * |
1678 | * Attempts to read the crypto metadata from the extended attribute | 1678 | * Attempts to read the crypto metadata from the extended attribute |
1679 | * region of the lower file. | 1679 | * region of the lower file. |
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index df70bfa176d9..95be9a90c504 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c | |||
@@ -187,11 +187,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
187 | /* Private value of ecryptfs_dentry allocated in | 187 | /* Private value of ecryptfs_dentry allocated in |
188 | * ecryptfs_lookup() */ | 188 | * ecryptfs_lookup() */ |
189 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); | 189 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); |
190 | struct inode *lower_inode = NULL; | ||
191 | struct file *lower_file = NULL; | ||
192 | struct vfsmount *lower_mnt; | ||
193 | struct ecryptfs_file_info *file_info; | 190 | struct ecryptfs_file_info *file_info; |
194 | int lower_flags; | ||
195 | 191 | ||
196 | mount_crypt_stat = &ecryptfs_superblock_to_private( | 192 | mount_crypt_stat = &ecryptfs_superblock_to_private( |
197 | ecryptfs_dentry->d_sb)->mount_crypt_stat; | 193 | ecryptfs_dentry->d_sb)->mount_crypt_stat; |
@@ -219,26 +215,12 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
219 | if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { | 215 | if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { |
220 | ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); | 216 | ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); |
221 | /* Policy code enabled in future release */ | 217 | /* Policy code enabled in future release */ |
222 | crypt_stat->flags |= ECRYPTFS_POLICY_APPLIED; | 218 | crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED |
223 | crypt_stat->flags |= ECRYPTFS_ENCRYPTED; | 219 | | ECRYPTFS_ENCRYPTED); |
224 | } | 220 | } |
225 | mutex_unlock(&crypt_stat->cs_mutex); | 221 | mutex_unlock(&crypt_stat->cs_mutex); |
226 | lower_flags = file->f_flags; | 222 | ecryptfs_set_file_lower( |
227 | if ((lower_flags & O_ACCMODE) == O_WRONLY) | 223 | file, ecryptfs_inode_to_private(inode)->lower_file); |
228 | lower_flags = (lower_flags & O_ACCMODE) | O_RDWR; | ||
229 | if (file->f_flags & O_APPEND) | ||
230 | lower_flags &= ~O_APPEND; | ||
231 | lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); | ||
232 | /* Corresponding fput() in ecryptfs_release() */ | ||
233 | rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt, | ||
234 | lower_flags); | ||
235 | if (rc) { | ||
236 | ecryptfs_printk(KERN_ERR, "Error opening lower file\n"); | ||
237 | goto out_puts; | ||
238 | } | ||
239 | ecryptfs_set_file_lower(file, lower_file); | ||
240 | /* Isn't this check the same as the one in lookup? */ | ||
241 | lower_inode = lower_dentry->d_inode; | ||
242 | if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { | 224 | if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { |
243 | ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); | 225 | ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); |
244 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); | 226 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); |
@@ -260,7 +242,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
260 | "and plaintext passthrough mode is not " | 242 | "and plaintext passthrough mode is not " |
261 | "enabled; returning -EIO\n"); | 243 | "enabled; returning -EIO\n"); |
262 | mutex_unlock(&crypt_stat->cs_mutex); | 244 | mutex_unlock(&crypt_stat->cs_mutex); |
263 | goto out_puts; | 245 | goto out_free; |
264 | } | 246 | } |
265 | rc = 0; | 247 | rc = 0; |
266 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); | 248 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); |
@@ -272,11 +254,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
272 | ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " | 254 | ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " |
273 | "size: [0x%.16x]\n", inode, inode->i_ino, | 255 | "size: [0x%.16x]\n", inode, inode->i_ino, |
274 | i_size_read(inode)); | 256 | i_size_read(inode)); |
275 | ecryptfs_set_file_lower(file, lower_file); | ||
276 | goto out; | 257 | goto out; |
277 | out_puts: | 258 | out_free: |
278 | mntput(lower_mnt); | ||
279 | dput(lower_dentry); | ||
280 | kmem_cache_free(ecryptfs_file_info_cache, | 259 | kmem_cache_free(ecryptfs_file_info_cache, |
281 | ecryptfs_file_to_private(file)); | 260 | ecryptfs_file_to_private(file)); |
282 | out: | 261 | out: |
@@ -296,20 +275,9 @@ static int ecryptfs_flush(struct file *file, fl_owner_t td) | |||
296 | 275 | ||
297 | static int ecryptfs_release(struct inode *inode, struct file *file) | 276 | static int ecryptfs_release(struct inode *inode, struct file *file) |
298 | { | 277 | { |
299 | struct file *lower_file = ecryptfs_file_to_lower(file); | 278 | kmem_cache_free(ecryptfs_file_info_cache, |
300 | struct ecryptfs_file_info *file_info = ecryptfs_file_to_private(file); | 279 | ecryptfs_file_to_private(file)); |
301 | struct inode *lower_inode = ecryptfs_inode_to_lower(inode); | 280 | return 0; |
302 | int rc; | ||
303 | |||
304 | rc = ecryptfs_close_lower_file(lower_file); | ||
305 | if (rc) { | ||
306 | printk(KERN_ERR "Error closing lower_file\n"); | ||
307 | goto out; | ||
308 | } | ||
309 | inode->i_blocks = lower_inode->i_blocks; | ||
310 | kmem_cache_free(ecryptfs_file_info_cache, file_info); | ||
311 | out: | ||
312 | return rc; | ||
313 | } | 281 | } |
314 | 282 | ||
315 | static int | 283 | static int |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index a29dc31965fa..5701f816faf4 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
@@ -739,8 +739,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
739 | int rc = 0; | 739 | int rc = 0; |
740 | struct inode *inode = dentry->d_inode; | 740 | struct inode *inode = dentry->d_inode; |
741 | struct dentry *lower_dentry; | 741 | struct dentry *lower_dentry; |
742 | struct vfsmount *lower_mnt; | 742 | struct file fake_ecryptfs_file; |
743 | struct file fake_ecryptfs_file, *lower_file = NULL; | ||
744 | struct ecryptfs_crypt_stat *crypt_stat; | 743 | struct ecryptfs_crypt_stat *crypt_stat; |
745 | loff_t i_size = i_size_read(inode); | 744 | loff_t i_size = i_size_read(inode); |
746 | loff_t lower_size_before_truncate; | 745 | loff_t lower_size_before_truncate; |
@@ -763,51 +762,43 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
763 | goto out; | 762 | goto out; |
764 | } | 763 | } |
765 | lower_dentry = ecryptfs_dentry_to_lower(dentry); | 764 | lower_dentry = ecryptfs_dentry_to_lower(dentry); |
766 | /* This dget & mntget is released through fput at out_fput: */ | 765 | ecryptfs_set_file_lower( |
767 | lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); | 766 | &fake_ecryptfs_file, |
768 | rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt, | 767 | ecryptfs_inode_to_private(dentry->d_inode)->lower_file); |
769 | O_RDWR); | ||
770 | if (rc) { | ||
771 | ecryptfs_printk(KERN_ERR, | ||
772 | "Error opening dentry; rc = [%i]\n", rc); | ||
773 | goto out_free; | ||
774 | } | ||
775 | ecryptfs_set_file_lower(&fake_ecryptfs_file, lower_file); | ||
776 | /* Switch on growing or shrinking file */ | 768 | /* Switch on growing or shrinking file */ |
777 | if (new_length > i_size) { | 769 | if (new_length > i_size) { |
778 | rc = ecryptfs_fill_zeros(&fake_ecryptfs_file, new_length); | 770 | char zero[] = { 0x00 }; |
779 | if (rc) { | 771 | |
780 | ecryptfs_printk(KERN_ERR, | 772 | /* Write a single 0 at the last position of the file; |
781 | "Problem with fill_zeros\n"); | 773 | * this triggers code that will fill in 0's throughout |
782 | goto out_fput; | 774 | * the intermediate portion of the previous end of the |
783 | } | 775 | * file and the new and of the file */ |
784 | i_size_write(inode, new_length); | 776 | rc = ecryptfs_write(&fake_ecryptfs_file, zero, |
785 | rc = ecryptfs_write_inode_size_to_metadata(inode); | 777 | (new_length - 1), 1); |
786 | if (rc) { | ||
787 | printk(KERN_ERR "Problem with " | ||
788 | "ecryptfs_write_inode_size_to_metadata; " | ||
789 | "rc = [%d]\n", rc); | ||
790 | goto out_fput; | ||
791 | } | ||
792 | } else { /* new_length < i_size_read(inode) */ | 778 | } else { /* new_length < i_size_read(inode) */ |
793 | pgoff_t index = 0; | 779 | /* We're chopping off all the pages down do the page |
794 | int end_pos_in_page = -1; | 780 | * in which new_length is located. Fill in the end of |
795 | 781 | * that page from (new_length & ~PAGE_CACHE_MASK) to | |
796 | if (new_length != 0) { | 782 | * PAGE_CACHE_SIZE with zeros. */ |
797 | index = ((new_length - 1) >> PAGE_CACHE_SHIFT); | 783 | size_t num_zeros = (PAGE_CACHE_SIZE |
798 | end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK); | 784 | - (new_length & ~PAGE_CACHE_MASK)); |
799 | } | 785 | |
800 | if (end_pos_in_page != (PAGE_CACHE_SIZE - 1)) { | 786 | if (num_zeros) { |
801 | rc = ecryptfs_write_zeros(&fake_ecryptfs_file, | 787 | char *zeros_virt; |
802 | index, | 788 | |
803 | (end_pos_in_page + 1), | 789 | zeros_virt = kzalloc(num_zeros, GFP_KERNEL); |
804 | ((PAGE_CACHE_SIZE - 1) | 790 | if (!zeros_virt) { |
805 | - end_pos_in_page)); | 791 | rc = -ENOMEM; |
792 | goto out_free; | ||
793 | } | ||
794 | rc = ecryptfs_write(&fake_ecryptfs_file, zeros_virt, | ||
795 | new_length, num_zeros); | ||
796 | kfree(zeros_virt); | ||
806 | if (rc) { | 797 | if (rc) { |
807 | printk(KERN_ERR "Error attempting to zero out " | 798 | printk(KERN_ERR "Error attempting to zero out " |
808 | "the remainder of the end page on " | 799 | "the remainder of the end page on " |
809 | "reducing truncate; rc = [%d]\n", rc); | 800 | "reducing truncate; rc = [%d]\n", rc); |
810 | goto out_fput; | 801 | goto out_free; |
811 | } | 802 | } |
812 | } | 803 | } |
813 | vmtruncate(inode, new_length); | 804 | vmtruncate(inode, new_length); |
@@ -816,7 +807,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
816 | printk(KERN_ERR "Problem with " | 807 | printk(KERN_ERR "Problem with " |
817 | "ecryptfs_write_inode_size_to_metadata; " | 808 | "ecryptfs_write_inode_size_to_metadata; " |
818 | "rc = [%d]\n", rc); | 809 | "rc = [%d]\n", rc); |
819 | goto out_fput; | 810 | goto out_free; |
820 | } | 811 | } |
821 | /* We are reducing the size of the ecryptfs file, and need to | 812 | /* We are reducing the size of the ecryptfs file, and need to |
822 | * know if we need to reduce the size of the lower file. */ | 813 | * know if we need to reduce the size of the lower file. */ |
@@ -828,14 +819,6 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
828 | vmtruncate(lower_dentry->d_inode, | 819 | vmtruncate(lower_dentry->d_inode, |
829 | lower_size_after_truncate); | 820 | lower_size_after_truncate); |
830 | } | 821 | } |
831 | /* Update the access times */ | ||
832 | lower_dentry->d_inode->i_mtime = lower_dentry->d_inode->i_ctime | ||
833 | = CURRENT_TIME; | ||
834 | mark_inode_dirty_sync(inode); | ||
835 | out_fput: | ||
836 | rc = ecryptfs_close_lower_file(lower_file); | ||
837 | if (rc) | ||
838 | printk(KERN_ERR "Error closing lower_file\n"); | ||
839 | out_free: | 822 | out_free: |
840 | if (ecryptfs_file_to_private(&fake_ecryptfs_file)) | 823 | if (ecryptfs_file_to_private(&fake_ecryptfs_file)) |
841 | kmem_cache_free(ecryptfs_file_info_cache, | 824 | kmem_cache_free(ecryptfs_file_info_cache, |
@@ -895,21 +878,8 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) | |||
895 | else if (S_ISREG(dentry->d_inode->i_mode) | 878 | else if (S_ISREG(dentry->d_inode->i_mode) |
896 | && (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) | 879 | && (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) |
897 | || !(crypt_stat->flags & ECRYPTFS_KEY_VALID))) { | 880 | || !(crypt_stat->flags & ECRYPTFS_KEY_VALID))) { |
898 | struct vfsmount *lower_mnt; | ||
899 | struct file *lower_file = NULL; | ||
900 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat; | 881 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat; |
901 | int lower_flags; | ||
902 | 882 | ||
903 | lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); | ||
904 | lower_flags = O_RDONLY; | ||
905 | rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, | ||
906 | lower_mnt, lower_flags); | ||
907 | if (rc) { | ||
908 | printk(KERN_ERR | ||
909 | "Error opening lower file; rc = [%d]\n", rc); | ||
910 | mutex_unlock(&crypt_stat->cs_mutex); | ||
911 | goto out; | ||
912 | } | ||
913 | mount_crypt_stat = &ecryptfs_superblock_to_private( | 883 | mount_crypt_stat = &ecryptfs_superblock_to_private( |
914 | dentry->d_sb)->mount_crypt_stat; | 884 | dentry->d_sb)->mount_crypt_stat; |
915 | rc = ecryptfs_read_metadata(dentry); | 885 | rc = ecryptfs_read_metadata(dentry); |
@@ -923,16 +893,13 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) | |||
923 | "enabled; returning -EIO\n"); | 893 | "enabled; returning -EIO\n"); |
924 | 894 | ||
925 | mutex_unlock(&crypt_stat->cs_mutex); | 895 | mutex_unlock(&crypt_stat->cs_mutex); |
926 | fput(lower_file); | ||
927 | goto out; | 896 | goto out; |
928 | } | 897 | } |
929 | rc = 0; | 898 | rc = 0; |
930 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); | 899 | crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); |
931 | mutex_unlock(&crypt_stat->cs_mutex); | 900 | mutex_unlock(&crypt_stat->cs_mutex); |
932 | fput(lower_file); | ||
933 | goto out; | 901 | goto out; |
934 | } | 902 | } |
935 | fput(lower_file); | ||
936 | } | 903 | } |
937 | mutex_unlock(&crypt_stat->cs_mutex); | 904 | mutex_unlock(&crypt_stat->cs_mutex); |
938 | if (ia->ia_valid & ATTR_SIZE) { | 905 | if (ia->ia_valid & ATTR_SIZE) { |
@@ -995,20 +962,8 @@ ssize_t | |||
995 | ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, | 962 | ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, |
996 | size_t size) | 963 | size_t size) |
997 | { | 964 | { |
998 | int rc = 0; | 965 | return ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry), name, |
999 | struct dentry *lower_dentry; | 966 | value, size); |
1000 | |||
1001 | lower_dentry = ecryptfs_dentry_to_lower(dentry); | ||
1002 | if (!lower_dentry->d_inode->i_op->getxattr) { | ||
1003 | rc = -ENOSYS; | ||
1004 | goto out; | ||
1005 | } | ||
1006 | mutex_lock(&lower_dentry->d_inode->i_mutex); | ||
1007 | rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value, | ||
1008 | size); | ||
1009 | mutex_unlock(&lower_dentry->d_inode->i_mutex); | ||
1010 | out: | ||
1011 | return rc; | ||
1012 | } | 967 | } |
1013 | 968 | ||
1014 | static ssize_t | 969 | static ssize_t |