2006-10-04 13:16:22 +04:00
/**
* eCryptfs : Linux filesystem encryption layer
* This is where eCryptfs coordinates the symmetric encryption and
* decryption of the file data as it passes between the lower
* encrypted file and the upper decrypted file .
*
* Copyright ( C ) 1997 - 2003 Erez Zadok
* Copyright ( C ) 2001 - 2003 Stony Brook University
2007-02-12 11:53:46 +03:00
* Copyright ( C ) 2004 - 2007 International Business Machines Corp .
2006-10-04 13:16:22 +04:00
* Author ( s ) : Michael A . Halcrow < mahalcro @ us . ibm . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA
* 02111 - 1307 , USA .
*/
# include <linux/pagemap.h>
# include <linux/writeback.h>
# include <linux/page-flags.h>
# include <linux/mount.h>
# include <linux/file.h>
# include <linux/crypto.h>
# include <linux/scatterlist.h>
2008-07-24 08:30:07 +04:00
# include <asm/unaligned.h>
2006-10-04 13:16:22 +04:00
# include "ecryptfs_kernel.h"
/**
2007-10-16 12:28:14 +04:00
* ecryptfs_get_locked_page
2006-10-04 13:16:22 +04:00
*
* Get one page from cache or lower f / s , return error otherwise .
*
2007-10-16 12:28:14 +04:00
* Returns locked and up - to - date page ( if ok ) , with increased
2006-10-04 13:16:22 +04:00
* refcnt .
*/
2007-10-16 12:28:14 +04:00
struct page * ecryptfs_get_locked_page ( struct file * file , loff_t index )
2006-10-04 13:16:22 +04:00
{
struct dentry * dentry ;
struct inode * inode ;
struct address_space * mapping ;
2007-10-16 12:28:14 +04:00
struct page * page ;
2006-10-04 13:16:22 +04:00
2006-12-08 13:36:48 +03:00
dentry = file - > f_path . dentry ;
2006-10-04 13:16:22 +04:00
inode = dentry - > d_inode ;
mapping = inode - > i_mapping ;
2007-10-16 12:28:14 +04:00
page = read_mapping_page ( mapping , index , ( void * ) file ) ;
if ( ! IS_ERR ( page ) )
lock_page ( page ) ;
return page ;
2006-10-04 13:16:22 +04:00
}
/**
* ecryptfs_writepage
* @ page : Page that is locked before this call is made
*
* Returns zero on success ; non - zero otherwise
*/
static int ecryptfs_writepage ( struct page * page , struct writeback_control * wbc )
{
int rc ;
2007-10-16 12:28:08 +04:00
rc = ecryptfs_encrypt_page ( page ) ;
2006-10-04 13:16:22 +04:00
if ( rc ) {
ecryptfs_printk ( KERN_WARNING , " Error encrypting "
" page (upper index [0x%.16x]) \n " , page - > index ) ;
ClearPageUptodate ( page ) ;
goto out ;
}
SetPageUptodate ( page ) ;
unlock_page ( page ) ;
out :
return rc ;
}
2007-02-12 11:53:47 +03:00
/**
* Header Extent :
* Octets 0 - 7 : Unencrypted file size ( big - endian )
* Octets 8 - 15 : eCryptfs special marker
* Octets 16 - 19 : Flags
* Octet 16 : File format version number ( between 0 and 255 )
* Octets 17 - 18 : Reserved
* Octet 19 : Bit 1 ( lsb ) : Reserved
* Bit 2 : Encrypted ?
* Bits 3 - 8 : Reserved
* Octets 20 - 23 : Header extent size ( big - endian )
* Octets 24 - 25 : Number of header extents at front of file
* ( big - endian )
* Octet 26 : Begin RFC 2440 authentication token packet set
*/
static void set_header_info ( char * page_virt ,
struct ecryptfs_crypt_stat * crypt_stat )
{
size_t written ;
2008-02-06 12:38:32 +03:00
size_t save_num_header_bytes_at_front =
crypt_stat - > num_header_bytes_at_front ;
2007-02-12 11:53:47 +03:00
2008-02-06 12:38:32 +03:00
crypt_stat - > num_header_bytes_at_front =
ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE ;
2007-02-12 11:53:47 +03:00
ecryptfs_write_header_metadata ( page_virt + 20 , crypt_stat , & written ) ;
2008-02-06 12:38:32 +03:00
crypt_stat - > num_header_bytes_at_front =
save_num_header_bytes_at_front ;
2007-02-12 11:53:47 +03:00
}
2006-10-04 13:16:22 +04:00
2007-10-16 12:28:11 +04:00
/**
* ecryptfs_copy_up_encrypted_with_header
* @ page : Sort of a ` ` virtual ' ' representation of the encrypted lower
* file . The actual lower file does not have the metadata in
* the header . This is locked .
* @ crypt_stat : The eCryptfs inode ' s cryptographic context
*
* The ` ` view ' ' is the version of the file that userspace winds up
* seeing , with the header information inserted .
*/
static int
ecryptfs_copy_up_encrypted_with_header ( struct page * page ,
struct ecryptfs_crypt_stat * crypt_stat )
{
loff_t extent_num_in_page = 0 ;
loff_t num_extents_per_page = ( PAGE_CACHE_SIZE
/ crypt_stat - > extent_size ) ;
int rc = 0 ;
while ( extent_num_in_page < num_extents_per_page ) {
2007-10-16 12:28:12 +04:00
loff_t view_extent_num = ( ( ( ( loff_t ) page - > index )
* num_extents_per_page )
2007-10-16 12:28:11 +04:00
+ extent_num_in_page ) ;
2008-02-06 12:38:32 +03:00
size_t num_header_extents_at_front =
( crypt_stat - > num_header_bytes_at_front
/ crypt_stat - > extent_size ) ;
2007-10-16 12:28:11 +04:00
2008-02-06 12:38:32 +03:00
if ( view_extent_num < num_header_extents_at_front ) {
2007-10-16 12:28:11 +04:00
/* This is a header extent */
char * page_virt ;
page_virt = kmap_atomic ( page , KM_USER0 ) ;
memset ( page_virt , 0 , PAGE_CACHE_SIZE ) ;
/* TODO: Support more than one header extent */
if ( view_extent_num = = 0 ) {
rc = ecryptfs_read_xattr_region (
page_virt , page - > mapping - > host ) ;
set_header_info ( page_virt , crypt_stat ) ;
}
kunmap_atomic ( page_virt , KM_USER0 ) ;
flush_dcache_page ( page ) ;
if ( rc ) {
printk ( KERN_ERR " %s: Error reading xattr "
2008-04-29 11:59:48 +04:00
" region; rc = [%d] \n " , __func__ , rc ) ;
2007-10-16 12:28:11 +04:00
goto out ;
}
} else {
/* This is an encrypted data extent */
loff_t lower_offset =
2008-02-06 12:38:32 +03:00
( ( view_extent_num * crypt_stat - > extent_size )
- crypt_stat - > num_header_bytes_at_front ) ;
2007-10-16 12:28:11 +04:00
rc = ecryptfs_read_lower_page_segment (
page , ( lower_offset > > PAGE_CACHE_SHIFT ) ,
( lower_offset & ~ PAGE_CACHE_MASK ) ,
crypt_stat - > extent_size , page - > mapping - > host ) ;
if ( rc ) {
printk ( KERN_ERR " %s: Error attempting to read "
" extent at offset [%lld] in the lower "
2008-04-29 11:59:48 +04:00
" file; rc = [%d] \n " , __func__ ,
2007-10-16 12:28:11 +04:00
lower_offset , rc ) ;
goto out ;
}
}
extent_num_in_page + + ;
}
out :
return rc ;
}
2006-10-04 13:16:22 +04:00
/**
* ecryptfs_readpage
2007-10-16 12:28:11 +04:00
* @ file : An eCryptfs file
* @ page : Page from eCryptfs inode mapping into which to stick the read data
2006-10-04 13:16:22 +04:00
*
* Read in a page , decrypting if necessary .
*
* Returns zero on success ; non - zero on error .
*/
static int ecryptfs_readpage ( struct file * file , struct page * page )
{
2007-10-16 12:28:11 +04:00
struct ecryptfs_crypt_stat * crypt_stat =
& ecryptfs_inode_to_private ( file - > f_path . dentry - > d_inode ) - > crypt_stat ;
2006-10-04 13:16:22 +04:00
int rc = 0 ;
if ( ! crypt_stat
2007-02-12 11:53:49 +03:00
| | ! ( crypt_stat - > flags & ECRYPTFS_ENCRYPTED )
| | ( crypt_stat - > flags & ECRYPTFS_NEW_FILE ) ) {
2006-10-04 13:16:22 +04:00
ecryptfs_printk ( KERN_DEBUG ,
" Passing through unencrypted page \n " ) ;
2007-10-16 12:28:11 +04:00
rc = ecryptfs_read_lower_page_segment ( page , page - > index , 0 ,
PAGE_CACHE_SIZE ,
page - > mapping - > host ) ;
2007-02-12 11:53:47 +03:00
} else if ( crypt_stat - > flags & ECRYPTFS_VIEW_AS_ENCRYPTED ) {
if ( crypt_stat - > flags & ECRYPTFS_METADATA_IN_XATTR ) {
2007-10-16 12:28:11 +04:00
rc = ecryptfs_copy_up_encrypted_with_header ( page ,
crypt_stat ) ;
if ( rc ) {
printk ( KERN_ERR " %s: Error attempting to copy "
" the encrypted content from the lower "
" file whilst inserting the metadata "
" from the xattr into the header; rc = "
2008-04-29 11:59:48 +04:00
" [%d] \n " , __func__ , rc ) ;
2007-10-16 12:28:11 +04:00
goto out ;
2007-02-12 11:53:47 +03:00
}
2007-10-16 12:28:11 +04:00
2007-02-12 11:53:47 +03:00
} else {
2007-10-16 12:28:11 +04:00
rc = ecryptfs_read_lower_page_segment (
page , page - > index , 0 , PAGE_CACHE_SIZE ,
page - > mapping - > host ) ;
2007-02-12 11:53:47 +03:00
if ( rc ) {
printk ( KERN_ERR " Error reading page; rc = "
" [%d] \n " , rc ) ;
goto out ;
}
}
2006-10-04 13:16:22 +04:00
} else {
2007-10-16 12:28:08 +04:00
rc = ecryptfs_decrypt_page ( page ) ;
2006-10-04 13:16:22 +04:00
if ( rc ) {
ecryptfs_printk ( KERN_ERR , " Error decrypting page; "
" rc = [%d] \n " , rc ) ;
goto out ;
}
}
out :
2007-10-16 12:28:14 +04:00
if ( rc )
ClearPageUptodate ( page ) ;
else
SetPageUptodate ( page ) ;
2006-10-04 13:16:22 +04:00
ecryptfs_printk ( KERN_DEBUG , " Unlocking page with index = [0x%.16x] \n " ,
page - > index ) ;
unlock_page ( page ) ;
return rc ;
}
2007-02-12 11:53:46 +03:00
/**
* Called with lower inode mutex held .
*/
2006-10-04 13:16:22 +04:00
static int fill_zeros_to_end_of_page ( struct page * page , unsigned int to )
{
struct inode * inode = page - > mapping - > host ;
int end_byte_in_page ;
2007-02-12 11:53:48 +03:00
if ( ( i_size_read ( inode ) / PAGE_CACHE_SIZE ) ! = page - > index )
goto out ;
end_byte_in_page = i_size_read ( inode ) % PAGE_CACHE_SIZE ;
if ( to > end_byte_in_page )
end_byte_in_page = to ;
2008-02-05 09:28:29 +03:00
zero_user_segment ( page , end_byte_in_page , PAGE_CACHE_SIZE ) ;
2006-10-04 13:16:22 +04:00
out :
2007-02-12 11:53:48 +03:00
return 0 ;
2006-10-04 13:16:22 +04:00
}
2008-03-05 01:29:24 +03:00
/**
2008-10-16 09:02:50 +04:00
* ecryptfs_write_begin
2008-03-05 01:29:24 +03:00
* @ file : The eCryptfs file
2008-10-16 09:02:50 +04:00
* @ mapping : The eCryptfs object
* @ pos : The file offset at which to start writing
* @ len : Length of the write
* @ flags : Various flags
* @ pagep : Pointer to return the page
* @ fsdata : Pointer to return fs data ( unused )
2008-03-05 01:29:24 +03:00
*
* This function must zero any hole we create
*
* Returns zero on success ; non - zero otherwise
*/
2008-10-16 09:02:50 +04:00
static int ecryptfs_write_begin ( struct file * file ,
struct address_space * mapping ,
loff_t pos , unsigned len , unsigned flags ,
struct page * * pagep , void * * fsdata )
2006-10-04 13:16:22 +04:00
{
2008-10-16 09:02:50 +04:00
pgoff_t index = pos > > PAGE_CACHE_SHIFT ;
struct page * page ;
2007-12-18 03:20:10 +03:00
loff_t prev_page_end_size ;
2008-03-05 01:29:24 +03:00
int rc = 0 ;
2006-10-04 13:16:22 +04:00
fs: symlink write_begin allocation context fix
With the write_begin/write_end aops, page_symlink was broken because it
could no longer pass a GFP_NOFS type mask into the point where the
allocations happened. They are done in write_begin, which would always
assume that the filesystem can be entered from reclaim. This bug could
cause filesystem deadlocks.
The funny thing with having a gfp_t mask there is that it doesn't really
allow the caller to arbitrarily tinker with the context in which it can be
called. It couldn't ever be GFP_ATOMIC, for example, because it needs to
take the page lock. The only thing any callers care about is __GFP_FS
anyway, so turn that into a single flag.
Add a new flag for write_begin, AOP_FLAG_NOFS. Filesystems can now act on
this flag in their write_begin function. Change __grab_cache_page to
accept a nofs argument as well, to honour that flag (while we're there,
change the name to grab_cache_page_write_begin which is more instructive
and does away with random leading underscores).
This is really a more flexible way to go in the end anyway -- if a
filesystem happens to want any extra allocations aside from the pagecache
ones in ints write_begin function, it may now use GFP_KERNEL (rather than
GFP_NOFS) for common case allocations (eg. ocfs2_alloc_write_ctxt, for a
random example).
[kosaki.motohiro@jp.fujitsu.com: fix ubifs]
[kosaki.motohiro@jp.fujitsu.com: fix fuse]
Signed-off-by: Nick Piggin <npiggin@suse.de>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: <stable@kernel.org> [2.6.28.x]
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
[ Cleaned up the calling convention: just pass in the AOP flags
untouched to the grab_cache_page_write_begin() function. That
just simplifies everybody, and may even allow future expansion of the
logic. - Linus ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-01-04 23:00:53 +03:00
page = grab_cache_page_write_begin ( mapping , index , flags ) ;
2008-10-16 09:02:50 +04:00
if ( ! page )
return - ENOMEM ;
* pagep = page ;
2007-10-16 12:28:14 +04:00
if ( ! PageUptodate ( page ) ) {
2008-03-05 01:29:24 +03:00
struct ecryptfs_crypt_stat * crypt_stat =
& ecryptfs_inode_to_private (
file - > f_path . dentry - > d_inode ) - > crypt_stat ;
if ( ! ( crypt_stat - > flags & ECRYPTFS_ENCRYPTED )
| | ( crypt_stat - > flags & ECRYPTFS_NEW_FILE ) ) {
rc = ecryptfs_read_lower_page_segment (
2008-10-16 09:02:50 +04:00
page , index , 0 , PAGE_CACHE_SIZE , mapping - > host ) ;
2008-03-05 01:29:24 +03:00
if ( rc ) {
printk ( KERN_ERR " %s: Error attemping to read "
" lower page segment; rc = [%d] \n " ,
2008-04-29 11:59:48 +04:00
__func__ , rc ) ;
2008-03-05 01:29:24 +03:00
ClearPageUptodate ( page ) ;
goto out ;
} else
SetPageUptodate ( page ) ;
} else if ( crypt_stat - > flags & ECRYPTFS_VIEW_AS_ENCRYPTED ) {
if ( crypt_stat - > flags & ECRYPTFS_METADATA_IN_XATTR ) {
rc = ecryptfs_copy_up_encrypted_with_header (
page , crypt_stat ) ;
if ( rc ) {
printk ( KERN_ERR " %s: Error attempting "
" to copy the encrypted content "
" from the lower file whilst "
" inserting the metadata from "
" the xattr into the header; rc "
2008-04-29 11:59:48 +04:00
" = [%d] \n " , __func__ , rc ) ;
2008-03-05 01:29:24 +03:00
ClearPageUptodate ( page ) ;
goto out ;
}
SetPageUptodate ( page ) ;
} else {
rc = ecryptfs_read_lower_page_segment (
2008-10-16 09:02:50 +04:00
page , index , 0 , PAGE_CACHE_SIZE ,
mapping - > host ) ;
2008-03-05 01:29:24 +03:00
if ( rc ) {
printk ( KERN_ERR " %s: Error reading "
" page; rc = [%d] \n " ,
2008-04-29 11:59:48 +04:00
__func__ , rc ) ;
2008-03-05 01:29:24 +03:00
ClearPageUptodate ( page ) ;
goto out ;
}
SetPageUptodate ( page ) ;
}
} else {
rc = ecryptfs_decrypt_page ( page ) ;
if ( rc ) {
printk ( KERN_ERR " %s: Error decrypting page "
" at index [%ld]; rc = [%d] \n " ,
2008-04-29 11:59:48 +04:00
__func__ , page - > index , rc ) ;
2008-03-05 01:29:24 +03:00
ClearPageUptodate ( page ) ;
goto out ;
}
2007-10-16 12:28:14 +04:00
SetPageUptodate ( page ) ;
2008-03-05 01:29:24 +03:00
}
2007-10-16 12:28:14 +04:00
}
2008-10-16 09:02:50 +04:00
prev_page_end_size = ( ( loff_t ) index < < PAGE_CACHE_SHIFT ) ;
2008-03-05 01:29:24 +03:00
/* If creating a page or more of holes, zero them out via truncate.
* Note , this will increase i_size . */
2008-10-16 09:02:50 +04:00
if ( index ! = 0 ) {
2007-12-18 03:20:10 +03:00
if ( prev_page_end_size > i_size_read ( page - > mapping - > host ) ) {
2007-06-28 01:09:44 +04:00
rc = ecryptfs_truncate ( file - > f_path . dentry ,
2007-12-18 03:20:10 +03:00
prev_page_end_size ) ;
2007-06-28 01:09:44 +04:00
if ( rc ) {
2008-03-05 01:29:24 +03:00
printk ( KERN_ERR " %s: Error on attempt to "
2007-06-28 01:09:44 +04:00
" truncate to (higher) offset [%lld]; "
2008-04-29 11:59:48 +04:00
" rc = [%d] \n " , __func__ ,
2008-03-05 01:29:24 +03:00
prev_page_end_size , rc ) ;
2007-06-28 01:09:44 +04:00
goto out ;
}
2007-05-24 00:58:15 +04:00
}
2007-12-18 03:20:10 +03:00
}
2008-03-05 01:29:24 +03:00
/* Writing to a new page, and creating a small hole from start
* of page ? Zero it out . */
2008-10-16 09:02:50 +04:00
if ( ( i_size_read ( mapping - > host ) = = prev_page_end_size )
& & ( pos ! = 0 ) )
2008-02-05 09:28:29 +03:00
zero_user ( page , 0 , PAGE_CACHE_SIZE ) ;
2006-10-04 13:16:22 +04:00
out :
return rc ;
}
/**
* ecryptfs_write_inode_size_to_header
*
* Writes the lower file size to the first 8 bytes of the header .
*
* Returns zero on success ; non - zero on error .
*/
2007-10-16 12:28:08 +04:00
static int ecryptfs_write_inode_size_to_header ( struct inode * ecryptfs_inode )
2006-10-04 13:16:22 +04:00
{
2007-10-16 12:28:08 +04:00
char * file_size_virt ;
int rc ;
2006-10-04 13:16:22 +04:00
2007-10-16 12:28:08 +04:00
file_size_virt = kmalloc ( sizeof ( u64 ) , GFP_KERNEL ) ;
if ( ! file_size_virt ) {
rc = - ENOMEM ;
2007-03-01 07:12:16 +03:00
goto out ;
}
2008-07-24 08:30:07 +04:00
put_unaligned_be64 ( i_size_read ( ecryptfs_inode ) , file_size_virt ) ;
2007-10-16 12:28:08 +04:00
rc = ecryptfs_write_lower ( ecryptfs_inode , file_size_virt , 0 ,
sizeof ( u64 ) ) ;
kfree ( file_size_virt ) ;
if ( rc )
printk ( KERN_ERR " %s: Error writing file size to header; "
2008-04-29 11:59:48 +04:00
" rc = [%d] \n " , __func__ , rc ) ;
2006-10-04 13:16:22 +04:00
out :
return rc ;
}
2007-10-16 12:28:08 +04:00
struct kmem_cache * ecryptfs_xattr_cache ;
static int ecryptfs_write_inode_size_to_xattr ( struct inode * ecryptfs_inode )
2007-02-12 11:53:46 +03:00
{
ssize_t size ;
void * xattr_virt ;
2007-10-16 12:28:08 +04:00
struct dentry * lower_dentry =
ecryptfs_inode_to_private ( ecryptfs_inode ) - > lower_file - > f_dentry ;
struct inode * lower_inode = lower_dentry - > d_inode ;
2007-02-12 11:53:46 +03:00
int rc ;
2007-10-16 12:28:08 +04:00
if ( ! lower_inode - > i_op - > getxattr | | ! lower_inode - > i_op - > setxattr ) {
printk ( KERN_WARNING
" No support for setting xattr in lower filesystem \n " ) ;
rc = - ENOSYS ;
goto out ;
}
2007-02-12 11:53:46 +03:00
xattr_virt = kmem_cache_alloc ( ecryptfs_xattr_cache , GFP_KERNEL ) ;
if ( ! xattr_virt ) {
printk ( KERN_ERR " Out of memory whilst attempting to write "
" inode size to xattr \n " ) ;
rc = - ENOMEM ;
goto out ;
}
2007-10-16 12:28:08 +04:00
mutex_lock ( & lower_inode - > i_mutex ) ;
size = lower_inode - > i_op - > getxattr ( lower_dentry , ECRYPTFS_XATTR_NAME ,
xattr_virt , PAGE_CACHE_SIZE ) ;
2007-02-12 11:53:46 +03:00
if ( size < 0 )
size = 8 ;
2008-07-24 08:30:07 +04:00
put_unaligned_be64 ( i_size_read ( ecryptfs_inode ) , xattr_virt ) ;
2007-10-16 12:28:08 +04:00
rc = lower_inode - > i_op - > setxattr ( lower_dentry , ECRYPTFS_XATTR_NAME ,
xattr_virt , size , 0 ) ;
mutex_unlock ( & lower_inode - > i_mutex ) ;
2007-02-12 11:53:46 +03:00
if ( rc )
printk ( KERN_ERR " Error whilst attempting to write inode size "
" to lower file xattr; rc = [%d] \n " , rc ) ;
kmem_cache_free ( ecryptfs_xattr_cache , xattr_virt ) ;
out :
return rc ;
}
2007-10-16 12:28:08 +04:00
int ecryptfs_write_inode_size_to_metadata ( struct inode * ecryptfs_inode )
2007-02-12 11:53:46 +03:00
{
struct ecryptfs_crypt_stat * crypt_stat ;
2007-10-16 12:28:08 +04:00
crypt_stat = & ecryptfs_inode_to_private ( ecryptfs_inode ) - > crypt_stat ;
2009-04-14 00:29:27 +04:00
BUG_ON ( ! ( crypt_stat - > flags & ECRYPTFS_ENCRYPTED ) ) ;
2007-02-12 11:53:46 +03:00
if ( crypt_stat - > flags & ECRYPTFS_METADATA_IN_XATTR )
2007-10-16 12:28:08 +04:00
return ecryptfs_write_inode_size_to_xattr ( ecryptfs_inode ) ;
2007-02-12 11:53:46 +03:00
else
2007-10-16 12:28:08 +04:00
return ecryptfs_write_inode_size_to_header ( ecryptfs_inode ) ;
2007-02-12 11:53:46 +03:00
}
2006-10-04 13:16:22 +04:00
/**
2008-10-16 09:02:50 +04:00
* ecryptfs_write_end
2006-10-04 13:16:22 +04:00
* @ file : The eCryptfs file object
2008-10-16 09:02:50 +04:00
* @ mapping : The eCryptfs object
* @ pos : The file position
* @ len : The length of the data ( unused )
* @ copied : The amount of data copied
2006-10-04 13:16:22 +04:00
* @ page : The eCryptfs page
2008-10-16 09:02:50 +04:00
* @ fsdata : The fsdata ( unused )
2006-10-04 13:16:22 +04:00
*
* This is where we encrypt the data and pass the encrypted data to
* the lower filesystem . In OpenPGP - compatible mode , we operate on
* entire underlying packets .
*/
2008-10-16 09:02:50 +04:00
static int ecryptfs_write_end ( struct file * file ,
struct address_space * mapping ,
loff_t pos , unsigned len , unsigned copied ,
struct page * page , void * fsdata )
2006-10-04 13:16:22 +04:00
{
2008-10-16 09:02:50 +04:00
pgoff_t index = pos > > PAGE_CACHE_SHIFT ;
unsigned from = pos & ( PAGE_CACHE_SIZE - 1 ) ;
unsigned to = from + copied ;
struct inode * ecryptfs_inode = mapping - > host ;
2007-10-16 12:28:11 +04:00
struct ecryptfs_crypt_stat * crypt_stat =
& ecryptfs_inode_to_private ( file - > f_path . dentry - > d_inode ) - > crypt_stat ;
2006-10-04 13:16:22 +04:00
int rc ;
2007-02-12 11:53:49 +03:00
if ( crypt_stat - > flags & ECRYPTFS_NEW_FILE ) {
2006-10-04 13:16:22 +04:00
ecryptfs_printk ( KERN_DEBUG , " ECRYPTFS_NEW_FILE flag set in "
" crypt_stat at memory location [%p] \n " , crypt_stat ) ;
2007-02-12 11:53:49 +03:00
crypt_stat - > flags & = ~ ( ECRYPTFS_NEW_FILE ) ;
2006-10-04 13:16:22 +04:00
} else
ecryptfs_printk ( KERN_DEBUG , " Not a new file \n " ) ;
ecryptfs_printk ( KERN_DEBUG , " Calling fill_zeros_to_end_of_page "
2008-10-16 09:02:50 +04:00
" (page w/ index = [0x%.16x], to = [%d]) \n " , index , to ) ;
2009-04-14 00:29:27 +04:00
if ( ! ( crypt_stat - > flags & ECRYPTFS_ENCRYPTED ) ) {
rc = ecryptfs_write_lower_page_segment ( ecryptfs_inode , page , 0 ,
to ) ;
if ( ! rc ) {
rc = copied ;
fsstack_copy_inode_size ( ecryptfs_inode ,
ecryptfs_inode_to_lower ( ecryptfs_inode ) ) ;
}
goto out ;
}
2007-10-16 12:28:11 +04:00
/* Fills in zeros if 'to' goes beyond inode size */
2006-10-04 13:16:22 +04:00
rc = fill_zeros_to_end_of_page ( page , to ) ;
if ( rc ) {
ecryptfs_printk ( KERN_WARNING , " Error attempting to fill "
2008-10-16 09:02:50 +04:00
" zeros in page with index = [0x%.16x] \n " , index ) ;
2006-10-04 13:16:22 +04:00
goto out ;
}
2007-10-16 12:28:08 +04:00
rc = ecryptfs_encrypt_page ( page ) ;
2006-10-04 13:16:22 +04:00
if ( rc ) {
ecryptfs_printk ( KERN_WARNING , " Error encrypting page (upper "
2008-10-16 09:02:50 +04:00
" index [0x%.16x]) \n " , index ) ;
2006-10-04 13:16:22 +04:00
goto out ;
}
2008-10-16 09:02:50 +04:00
if ( pos + copied > i_size_read ( ecryptfs_inode ) ) {
i_size_write ( ecryptfs_inode , pos + copied ) ;
2006-10-04 13:16:22 +04:00
ecryptfs_printk ( KERN_DEBUG , " Expanded file size to "
2007-10-16 12:28:11 +04:00
" [0x%.16x] \n " , i_size_read ( ecryptfs_inode ) ) ;
2006-10-04 13:16:22 +04:00
}
2007-10-16 12:28:11 +04:00
rc = ecryptfs_write_inode_size_to_metadata ( ecryptfs_inode ) ;
2007-02-12 11:53:46 +03:00
if ( rc )
printk ( KERN_ERR " Error writing inode size to metadata; "
" rc = [%d] \n " , rc ) ;
2008-10-16 09:02:50 +04:00
else
rc = copied ;
2006-10-04 13:16:22 +04:00
out :
2008-10-16 09:02:50 +04:00
unlock_page ( page ) ;
page_cache_release ( page ) ;
2006-10-04 13:16:22 +04:00
return rc ;
}
static sector_t ecryptfs_bmap ( struct address_space * mapping , sector_t block )
{
int rc = 0 ;
struct inode * inode ;
struct inode * lower_inode ;
inode = ( struct inode * ) mapping - > host ;
lower_inode = ecryptfs_inode_to_lower ( inode ) ;
if ( lower_inode - > i_mapping - > a_ops - > bmap )
rc = lower_inode - > i_mapping - > a_ops - > bmap ( lower_inode - > i_mapping ,
block ) ;
return rc ;
}
struct address_space_operations ecryptfs_aops = {
. writepage = ecryptfs_writepage ,
. readpage = ecryptfs_readpage ,
2008-10-16 09:02:50 +04:00
. write_begin = ecryptfs_write_begin ,
. write_end = ecryptfs_write_end ,
2006-10-04 13:16:22 +04:00
. bmap = ecryptfs_bmap ,
} ;