1237fead6SMichael Halcrow /** 2237fead6SMichael Halcrow * eCryptfs: Linux filesystem encryption layer 3237fead6SMichael Halcrow * This is where eCryptfs coordinates the symmetric encryption and 4237fead6SMichael Halcrow * decryption of the file data as it passes between the lower 5237fead6SMichael Halcrow * encrypted file and the upper decrypted file. 6237fead6SMichael Halcrow * 7237fead6SMichael Halcrow * Copyright (C) 1997-2003 Erez Zadok 8237fead6SMichael Halcrow * Copyright (C) 2001-2003 Stony Brook University 9dd2a3b7aSMichael Halcrow * Copyright (C) 2004-2007 International Business Machines Corp. 10237fead6SMichael Halcrow * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> 11237fead6SMichael Halcrow * 12237fead6SMichael Halcrow * This program is free software; you can redistribute it and/or 13237fead6SMichael Halcrow * modify it under the terms of the GNU General Public License as 14237fead6SMichael Halcrow * published by the Free Software Foundation; either version 2 of the 15237fead6SMichael Halcrow * License, or (at your option) any later version. 16237fead6SMichael Halcrow * 17237fead6SMichael Halcrow * This program is distributed in the hope that it will be useful, but 18237fead6SMichael Halcrow * WITHOUT ANY WARRANTY; without even the implied warranty of 19237fead6SMichael Halcrow * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20237fead6SMichael Halcrow * General Public License for more details. 21237fead6SMichael Halcrow * 22237fead6SMichael Halcrow * You should have received a copy of the GNU General Public License 23237fead6SMichael Halcrow * along with this program; if not, write to the Free Software 24237fead6SMichael Halcrow * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 25237fead6SMichael Halcrow * 02111-1307, USA. 26237fead6SMichael Halcrow */ 27237fead6SMichael Halcrow 28237fead6SMichael Halcrow #include <linux/pagemap.h> 29237fead6SMichael Halcrow #include <linux/writeback.h> 30237fead6SMichael Halcrow #include <linux/page-flags.h> 31237fead6SMichael Halcrow #include <linux/mount.h> 32237fead6SMichael Halcrow #include <linux/file.h> 33237fead6SMichael Halcrow #include <linux/crypto.h> 34237fead6SMichael Halcrow #include <linux/scatterlist.h> 35237fead6SMichael Halcrow #include "ecryptfs_kernel.h" 36237fead6SMichael Halcrow 37237fead6SMichael Halcrow struct kmem_cache *ecryptfs_lower_page_cache; 38237fead6SMichael Halcrow 39237fead6SMichael Halcrow /** 40237fead6SMichael Halcrow * ecryptfs_get1page 41237fead6SMichael Halcrow * 42237fead6SMichael Halcrow * Get one page from cache or lower f/s, return error otherwise. 43237fead6SMichael Halcrow * 44237fead6SMichael Halcrow * Returns unlocked and up-to-date page (if ok), with increased 45237fead6SMichael Halcrow * refcnt. 46237fead6SMichael Halcrow */ 47da0102a1SMichael Halcrow struct page *ecryptfs_get1page(struct file *file, loff_t index) 48237fead6SMichael Halcrow { 49237fead6SMichael Halcrow struct dentry *dentry; 50237fead6SMichael Halcrow struct inode *inode; 51237fead6SMichael Halcrow struct address_space *mapping; 52237fead6SMichael Halcrow 53bd243a4bSJosef "Jeff" Sipek dentry = file->f_path.dentry; 54237fead6SMichael Halcrow inode = dentry->d_inode; 55237fead6SMichael Halcrow mapping = inode->i_mapping; 566fe6900eSNick Piggin return read_mapping_page(mapping, index, (void *)file); 57237fead6SMichael Halcrow } 58237fead6SMichael Halcrow 59237fead6SMichael Halcrow /** 60237fead6SMichael Halcrow * ecryptfs_fill_zeros 61237fead6SMichael Halcrow * @file: The ecryptfs file 62237fead6SMichael Halcrow * @new_length: The new length of the data in the underlying file; 63237fead6SMichael Halcrow * everything between the prior end of the file and the 64237fead6SMichael Halcrow * new end of the file will be filled with zero's. 65237fead6SMichael Halcrow * new_length must be greater than current length 66237fead6SMichael Halcrow * 67237fead6SMichael Halcrow * Function for handling lseek-ing past the end of the file. 68237fead6SMichael Halcrow * 69237fead6SMichael Halcrow * This function does not support shrinking, only growing a file. 70237fead6SMichael Halcrow * 71237fead6SMichael Halcrow * Returns zero on success; non-zero otherwise. 72237fead6SMichael Halcrow */ 73237fead6SMichael Halcrow int ecryptfs_fill_zeros(struct file *file, loff_t new_length) 74237fead6SMichael Halcrow { 75237fead6SMichael Halcrow int rc = 0; 76bd243a4bSJosef "Jeff" Sipek struct dentry *dentry = file->f_path.dentry; 77237fead6SMichael Halcrow struct inode *inode = dentry->d_inode; 78237fead6SMichael Halcrow pgoff_t old_end_page_index = 0; 79237fead6SMichael Halcrow pgoff_t index = old_end_page_index; 80237fead6SMichael Halcrow int old_end_pos_in_page = -1; 81237fead6SMichael Halcrow pgoff_t new_end_page_index; 82237fead6SMichael Halcrow int new_end_pos_in_page; 83237fead6SMichael Halcrow loff_t cur_length = i_size_read(inode); 84237fead6SMichael Halcrow 85237fead6SMichael Halcrow if (cur_length != 0) { 86237fead6SMichael Halcrow index = old_end_page_index = 87237fead6SMichael Halcrow ((cur_length - 1) >> PAGE_CACHE_SHIFT); 88237fead6SMichael Halcrow old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK); 89237fead6SMichael Halcrow } 90237fead6SMichael Halcrow new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT); 91237fead6SMichael Halcrow new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK); 92237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "old_end_page_index = [0x%.16x]; " 93237fead6SMichael Halcrow "old_end_pos_in_page = [%d]; " 94237fead6SMichael Halcrow "new_end_page_index = [0x%.16x]; " 95237fead6SMichael Halcrow "new_end_pos_in_page = [%d]\n", 96237fead6SMichael Halcrow old_end_page_index, old_end_pos_in_page, 97237fead6SMichael Halcrow new_end_page_index, new_end_pos_in_page); 98237fead6SMichael Halcrow if (old_end_page_index == new_end_page_index) { 99237fead6SMichael Halcrow /* Start and end are in the same page; we just need to 100237fead6SMichael Halcrow * set a portion of the existing page to zero's */ 101240e2df5SMichael Halcrow rc = ecryptfs_write_zeros(file, index, 102240e2df5SMichael Halcrow (old_end_pos_in_page + 1), 103240e2df5SMichael Halcrow (new_end_pos_in_page 104240e2df5SMichael Halcrow - old_end_pos_in_page)); 105237fead6SMichael Halcrow if (rc) 106240e2df5SMichael Halcrow ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(" 107240e2df5SMichael Halcrow "file=[%p], " 108237fead6SMichael Halcrow "index=[0x%.16x], " 109237fead6SMichael Halcrow "old_end_pos_in_page=[d], " 110237fead6SMichael Halcrow "(PAGE_CACHE_SIZE - new_end_pos_in_page" 111237fead6SMichael Halcrow "=[%d]" 112237fead6SMichael Halcrow ")=[d]) returned [%d]\n", file, index, 113237fead6SMichael Halcrow old_end_pos_in_page, 114237fead6SMichael Halcrow new_end_pos_in_page, 115237fead6SMichael Halcrow (PAGE_CACHE_SIZE - new_end_pos_in_page), 116237fead6SMichael Halcrow rc); 117237fead6SMichael Halcrow goto out; 118237fead6SMichael Halcrow } 119237fead6SMichael Halcrow /* Fill the remainder of the previous last page with zeros */ 120240e2df5SMichael Halcrow rc = ecryptfs_write_zeros(file, index, (old_end_pos_in_page + 1), 121237fead6SMichael Halcrow ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page)); 122237fead6SMichael Halcrow if (rc) { 123240e2df5SMichael Halcrow ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(file=[%p], " 124237fead6SMichael Halcrow "index=[0x%.16x], old_end_pos_in_page=[d], " 125237fead6SMichael Halcrow "(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) " 126237fead6SMichael Halcrow "returned [%d]\n", file, index, 127237fead6SMichael Halcrow old_end_pos_in_page, 128237fead6SMichael Halcrow (PAGE_CACHE_SIZE - old_end_pos_in_page), rc); 129237fead6SMichael Halcrow goto out; 130237fead6SMichael Halcrow } 131237fead6SMichael Halcrow index++; 132237fead6SMichael Halcrow while (index < new_end_page_index) { 133237fead6SMichael Halcrow /* Fill all intermediate pages with zeros */ 134240e2df5SMichael Halcrow rc = ecryptfs_write_zeros(file, index, 0, PAGE_CACHE_SIZE); 135237fead6SMichael Halcrow if (rc) { 136240e2df5SMichael Halcrow ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(" 137240e2df5SMichael Halcrow "file=[%p], " 138237fead6SMichael Halcrow "index=[0x%.16x], " 139237fead6SMichael Halcrow "old_end_pos_in_page=[d], " 140237fead6SMichael Halcrow "(PAGE_CACHE_SIZE - new_end_pos_in_page" 141237fead6SMichael Halcrow "=[%d]" 142237fead6SMichael Halcrow ")=[d]) returned [%d]\n", file, index, 143237fead6SMichael Halcrow old_end_pos_in_page, 144237fead6SMichael Halcrow new_end_pos_in_page, 145237fead6SMichael Halcrow (PAGE_CACHE_SIZE - new_end_pos_in_page), 146237fead6SMichael Halcrow rc); 147237fead6SMichael Halcrow goto out; 148237fead6SMichael Halcrow } 149237fead6SMichael Halcrow index++; 150237fead6SMichael Halcrow } 151237fead6SMichael Halcrow /* Fill the portion at the beginning of the last new page with 152237fead6SMichael Halcrow * zero's */ 153240e2df5SMichael Halcrow rc = ecryptfs_write_zeros(file, index, 0, (new_end_pos_in_page + 1)); 154237fead6SMichael Halcrow if (rc) { 155240e2df5SMichael Halcrow ecryptfs_printk(KERN_ERR, "ecryptfs_write_zeros(file=" 156237fead6SMichael Halcrow "[%p], index=[0x%.16x], 0, " 157237fead6SMichael Halcrow "new_end_pos_in_page=[%d]" 158237fead6SMichael Halcrow "returned [%d]\n", file, index, 159237fead6SMichael Halcrow new_end_pos_in_page, rc); 160237fead6SMichael Halcrow goto out; 161237fead6SMichael Halcrow } 162237fead6SMichael Halcrow out: 163237fead6SMichael Halcrow return rc; 164237fead6SMichael Halcrow } 165237fead6SMichael Halcrow 166237fead6SMichael Halcrow /** 167237fead6SMichael Halcrow * ecryptfs_writepage 168237fead6SMichael Halcrow * @page: Page that is locked before this call is made 169237fead6SMichael Halcrow * 170237fead6SMichael Halcrow * Returns zero on success; non-zero otherwise 171237fead6SMichael Halcrow */ 172237fead6SMichael Halcrow static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) 173237fead6SMichael Halcrow { 174237fead6SMichael Halcrow int rc; 175237fead6SMichael Halcrow 1760216f7f7SMichael Halcrow rc = ecryptfs_encrypt_page(page); 177237fead6SMichael Halcrow if (rc) { 178237fead6SMichael Halcrow ecryptfs_printk(KERN_WARNING, "Error encrypting " 179237fead6SMichael Halcrow "page (upper index [0x%.16x])\n", page->index); 180237fead6SMichael Halcrow ClearPageUptodate(page); 181237fead6SMichael Halcrow goto out; 182237fead6SMichael Halcrow } 183237fead6SMichael Halcrow SetPageUptodate(page); 184237fead6SMichael Halcrow unlock_page(page); 185237fead6SMichael Halcrow out: 186237fead6SMichael Halcrow return rc; 187237fead6SMichael Halcrow } 188237fead6SMichael Halcrow 189237fead6SMichael Halcrow /** 190237fead6SMichael Halcrow * Reads the data from the lower file file at index lower_page_index 191237fead6SMichael Halcrow * and copies that data into page. 192237fead6SMichael Halcrow * 193237fead6SMichael Halcrow * @param page Page to fill 194237fead6SMichael Halcrow * @param lower_page_index Index of the page in the lower file to get 195237fead6SMichael Halcrow */ 196237fead6SMichael Halcrow int ecryptfs_do_readpage(struct file *file, struct page *page, 197237fead6SMichael Halcrow pgoff_t lower_page_index) 198237fead6SMichael Halcrow { 199237fead6SMichael Halcrow int rc; 200237fead6SMichael Halcrow struct dentry *dentry; 201237fead6SMichael Halcrow struct file *lower_file; 202237fead6SMichael Halcrow struct dentry *lower_dentry; 203237fead6SMichael Halcrow struct inode *inode; 204237fead6SMichael Halcrow struct inode *lower_inode; 205237fead6SMichael Halcrow char *page_data; 206237fead6SMichael Halcrow struct page *lower_page = NULL; 207237fead6SMichael Halcrow char *lower_page_data; 208237fead6SMichael Halcrow const struct address_space_operations *lower_a_ops; 209237fead6SMichael Halcrow 210bd243a4bSJosef "Jeff" Sipek dentry = file->f_path.dentry; 211237fead6SMichael Halcrow lower_file = ecryptfs_file_to_lower(file); 212237fead6SMichael Halcrow lower_dentry = ecryptfs_dentry_to_lower(dentry); 213237fead6SMichael Halcrow inode = dentry->d_inode; 214237fead6SMichael Halcrow lower_inode = ecryptfs_inode_to_lower(inode); 215237fead6SMichael Halcrow lower_a_ops = lower_inode->i_mapping->a_ops; 216237fead6SMichael Halcrow lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index, 217237fead6SMichael Halcrow (filler_t *)lower_a_ops->readpage, 218237fead6SMichael Halcrow (void *)lower_file); 219237fead6SMichael Halcrow if (IS_ERR(lower_page)) { 220237fead6SMichael Halcrow rc = PTR_ERR(lower_page); 221237fead6SMichael Halcrow lower_page = NULL; 222237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error reading from page cache\n"); 223237fead6SMichael Halcrow goto out; 224237fead6SMichael Halcrow } 2259d8b8ce5SMichael Halcrow page_data = kmap_atomic(page, KM_USER0); 2269d8b8ce5SMichael Halcrow lower_page_data = kmap_atomic(lower_page, KM_USER1); 227237fead6SMichael Halcrow memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE); 2289d8b8ce5SMichael Halcrow kunmap_atomic(lower_page_data, KM_USER1); 2299d8b8ce5SMichael Halcrow kunmap_atomic(page_data, KM_USER0); 2300a9ac382SMichael Halcrow flush_dcache_page(page); 231237fead6SMichael Halcrow rc = 0; 232237fead6SMichael Halcrow out: 233237fead6SMichael Halcrow if (likely(lower_page)) 234237fead6SMichael Halcrow page_cache_release(lower_page); 235237fead6SMichael Halcrow if (rc == 0) 236237fead6SMichael Halcrow SetPageUptodate(page); 237237fead6SMichael Halcrow else 238237fead6SMichael Halcrow ClearPageUptodate(page); 239237fead6SMichael Halcrow return rc; 240237fead6SMichael Halcrow } 241e77a56ddSMichael Halcrow /** 242e77a56ddSMichael Halcrow * Header Extent: 243e77a56ddSMichael Halcrow * Octets 0-7: Unencrypted file size (big-endian) 244e77a56ddSMichael Halcrow * Octets 8-15: eCryptfs special marker 245e77a56ddSMichael Halcrow * Octets 16-19: Flags 246e77a56ddSMichael Halcrow * Octet 16: File format version number (between 0 and 255) 247e77a56ddSMichael Halcrow * Octets 17-18: Reserved 248e77a56ddSMichael Halcrow * Octet 19: Bit 1 (lsb): Reserved 249e77a56ddSMichael Halcrow * Bit 2: Encrypted? 250e77a56ddSMichael Halcrow * Bits 3-8: Reserved 251e77a56ddSMichael Halcrow * Octets 20-23: Header extent size (big-endian) 252e77a56ddSMichael Halcrow * Octets 24-25: Number of header extents at front of file 253e77a56ddSMichael Halcrow * (big-endian) 254e77a56ddSMichael Halcrow * Octet 26: Begin RFC 2440 authentication token packet set 255e77a56ddSMichael Halcrow */ 256e77a56ddSMichael Halcrow static void set_header_info(char *page_virt, 257e77a56ddSMichael Halcrow struct ecryptfs_crypt_stat *crypt_stat) 258e77a56ddSMichael Halcrow { 259e77a56ddSMichael Halcrow size_t written; 260e77a56ddSMichael Halcrow int save_num_header_extents_at_front = 261e77a56ddSMichael Halcrow crypt_stat->num_header_extents_at_front; 262e77a56ddSMichael Halcrow 263e77a56ddSMichael Halcrow crypt_stat->num_header_extents_at_front = 1; 264e77a56ddSMichael Halcrow ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written); 265e77a56ddSMichael Halcrow crypt_stat->num_header_extents_at_front = 266e77a56ddSMichael Halcrow save_num_header_extents_at_front; 267e77a56ddSMichael Halcrow } 268237fead6SMichael Halcrow 269237fead6SMichael Halcrow /** 270bf12be1cSMichael Halcrow * ecryptfs_copy_up_encrypted_with_header 271bf12be1cSMichael Halcrow * @page: Sort of a ``virtual'' representation of the encrypted lower 272bf12be1cSMichael Halcrow * file. The actual lower file does not have the metadata in 273bf12be1cSMichael Halcrow * the header. This is locked. 274bf12be1cSMichael Halcrow * @crypt_stat: The eCryptfs inode's cryptographic context 275237fead6SMichael Halcrow * 276bf12be1cSMichael Halcrow * The ``view'' is the version of the file that userspace winds up 277bf12be1cSMichael Halcrow * seeing, with the header information inserted. 278237fead6SMichael Halcrow */ 279bf12be1cSMichael Halcrow static int 280bf12be1cSMichael Halcrow ecryptfs_copy_up_encrypted_with_header(struct page *page, 281bf12be1cSMichael Halcrow struct ecryptfs_crypt_stat *crypt_stat) 282237fead6SMichael Halcrow { 283bf12be1cSMichael Halcrow loff_t extent_num_in_page = 0; 284bf12be1cSMichael Halcrow loff_t num_extents_per_page = (PAGE_CACHE_SIZE 285bf12be1cSMichael Halcrow / crypt_stat->extent_size); 286237fead6SMichael Halcrow int rc = 0; 287237fead6SMichael Halcrow 288bf12be1cSMichael Halcrow while (extent_num_in_page < num_extents_per_page) { 289*d6a13c17SMichael Halcrow loff_t view_extent_num = ((((loff_t)page->index) 290*d6a13c17SMichael Halcrow * num_extents_per_page) 291bf12be1cSMichael Halcrow + extent_num_in_page); 292e77a56ddSMichael Halcrow 293bf12be1cSMichael Halcrow if (view_extent_num < crypt_stat->num_header_extents_at_front) { 294bf12be1cSMichael Halcrow /* This is a header extent */ 295e77a56ddSMichael Halcrow char *page_virt; 296e77a56ddSMichael Halcrow 2979d8b8ce5SMichael Halcrow page_virt = kmap_atomic(page, KM_USER0); 298e77a56ddSMichael Halcrow memset(page_virt, 0, PAGE_CACHE_SIZE); 299bf12be1cSMichael Halcrow /* TODO: Support more than one header extent */ 300bf12be1cSMichael Halcrow if (view_extent_num == 0) { 301e77a56ddSMichael Halcrow rc = ecryptfs_read_xattr_region( 302d7cdc5feSMichael Halcrow page_virt, page->mapping->host); 303e77a56ddSMichael Halcrow set_header_info(page_virt, crypt_stat); 304e77a56ddSMichael Halcrow } 3059d8b8ce5SMichael Halcrow kunmap_atomic(page_virt, KM_USER0); 3060a9ac382SMichael Halcrow flush_dcache_page(page); 307e77a56ddSMichael Halcrow if (rc) { 308bf12be1cSMichael Halcrow ClearPageUptodate(page); 309bf12be1cSMichael Halcrow printk(KERN_ERR "%s: Error reading xattr " 310bf12be1cSMichael Halcrow "region; rc = [%d]\n", __FUNCTION__, rc); 311e77a56ddSMichael Halcrow goto out; 312e77a56ddSMichael Halcrow } 313bf12be1cSMichael Halcrow SetPageUptodate(page); 314e77a56ddSMichael Halcrow } else { 315bf12be1cSMichael Halcrow /* This is an encrypted data extent */ 316bf12be1cSMichael Halcrow loff_t lower_offset = 317bf12be1cSMichael Halcrow ((view_extent_num - 318bf12be1cSMichael Halcrow crypt_stat->num_header_extents_at_front) 319bf12be1cSMichael Halcrow * crypt_stat->extent_size); 320bf12be1cSMichael Halcrow 321bf12be1cSMichael Halcrow rc = ecryptfs_read_lower_page_segment( 322bf12be1cSMichael Halcrow page, (lower_offset >> PAGE_CACHE_SHIFT), 323bf12be1cSMichael Halcrow (lower_offset & ~PAGE_CACHE_MASK), 324bf12be1cSMichael Halcrow crypt_stat->extent_size, page->mapping->host); 325e77a56ddSMichael Halcrow if (rc) { 326bf12be1cSMichael Halcrow printk(KERN_ERR "%s: Error attempting to read " 327bf12be1cSMichael Halcrow "extent at offset [%lld] in the lower " 328bf12be1cSMichael Halcrow "file; rc = [%d]\n", __FUNCTION__, 329bf12be1cSMichael Halcrow lower_offset, rc); 330e77a56ddSMichael Halcrow goto out; 331e77a56ddSMichael Halcrow } 332e77a56ddSMichael Halcrow } 333bf12be1cSMichael Halcrow extent_num_in_page++; 334bf12be1cSMichael Halcrow } 335bf12be1cSMichael Halcrow out: 336bf12be1cSMichael Halcrow return rc; 337bf12be1cSMichael Halcrow } 338bf12be1cSMichael Halcrow 339bf12be1cSMichael Halcrow /** 340bf12be1cSMichael Halcrow * ecryptfs_readpage 341bf12be1cSMichael Halcrow * @file: An eCryptfs file 342bf12be1cSMichael Halcrow * @page: Page from eCryptfs inode mapping into which to stick the read data 343bf12be1cSMichael Halcrow * 344bf12be1cSMichael Halcrow * Read in a page, decrypting if necessary. 345bf12be1cSMichael Halcrow * 346bf12be1cSMichael Halcrow * Returns zero on success; non-zero on error. 347bf12be1cSMichael Halcrow */ 348bf12be1cSMichael Halcrow static int ecryptfs_readpage(struct file *file, struct page *page) 349bf12be1cSMichael Halcrow { 350bf12be1cSMichael Halcrow struct ecryptfs_crypt_stat *crypt_stat = 351bf12be1cSMichael Halcrow &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat; 352bf12be1cSMichael Halcrow int rc = 0; 353bf12be1cSMichael Halcrow 354bf12be1cSMichael Halcrow if (!crypt_stat 355bf12be1cSMichael Halcrow || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED) 356bf12be1cSMichael Halcrow || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) { 357bf12be1cSMichael Halcrow ecryptfs_printk(KERN_DEBUG, 358bf12be1cSMichael Halcrow "Passing through unencrypted page\n"); 359bf12be1cSMichael Halcrow rc = ecryptfs_read_lower_page_segment(page, page->index, 0, 360bf12be1cSMichael Halcrow PAGE_CACHE_SIZE, 361bf12be1cSMichael Halcrow page->mapping->host); 362bf12be1cSMichael Halcrow } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { 363bf12be1cSMichael Halcrow if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { 364bf12be1cSMichael Halcrow rc = ecryptfs_copy_up_encrypted_with_header(page, 365bf12be1cSMichael Halcrow crypt_stat); 366bf12be1cSMichael Halcrow if (rc) { 367bf12be1cSMichael Halcrow printk(KERN_ERR "%s: Error attempting to copy " 368bf12be1cSMichael Halcrow "the encrypted content from the lower " 369bf12be1cSMichael Halcrow "file whilst inserting the metadata " 370bf12be1cSMichael Halcrow "from the xattr into the header; rc = " 371bf12be1cSMichael Halcrow "[%d]\n", __FUNCTION__, rc); 372bf12be1cSMichael Halcrow goto out; 373bf12be1cSMichael Halcrow } 374bf12be1cSMichael Halcrow 375e77a56ddSMichael Halcrow } else { 376bf12be1cSMichael Halcrow rc = ecryptfs_read_lower_page_segment( 377bf12be1cSMichael Halcrow page, page->index, 0, PAGE_CACHE_SIZE, 378bf12be1cSMichael Halcrow page->mapping->host); 379e77a56ddSMichael Halcrow if (rc) { 380e77a56ddSMichael Halcrow printk(KERN_ERR "Error reading page; rc = " 381e77a56ddSMichael Halcrow "[%d]\n", rc); 382e77a56ddSMichael Halcrow goto out; 383e77a56ddSMichael Halcrow } 384e77a56ddSMichael Halcrow } 385237fead6SMichael Halcrow } else { 3860216f7f7SMichael Halcrow rc = ecryptfs_decrypt_page(page); 387237fead6SMichael Halcrow if (rc) { 388237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error decrypting page; " 389237fead6SMichael Halcrow "rc = [%d]\n", rc); 390237fead6SMichael Halcrow goto out; 391237fead6SMichael Halcrow } 392237fead6SMichael Halcrow } 393237fead6SMichael Halcrow out: 394237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n", 395237fead6SMichael Halcrow page->index); 396237fead6SMichael Halcrow unlock_page(page); 397237fead6SMichael Halcrow return rc; 398237fead6SMichael Halcrow } 399237fead6SMichael Halcrow 400dd2a3b7aSMichael Halcrow /** 401dd2a3b7aSMichael Halcrow * Called with lower inode mutex held. 402dd2a3b7aSMichael Halcrow */ 403237fead6SMichael Halcrow static int fill_zeros_to_end_of_page(struct page *page, unsigned int to) 404237fead6SMichael Halcrow { 405237fead6SMichael Halcrow struct inode *inode = page->mapping->host; 406237fead6SMichael Halcrow int end_byte_in_page; 407237fead6SMichael Halcrow 4089d8b8ce5SMichael Halcrow if ((i_size_read(inode) / PAGE_CACHE_SIZE) != page->index) 4099d8b8ce5SMichael Halcrow goto out; 410237fead6SMichael Halcrow end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE; 411237fead6SMichael Halcrow if (to > end_byte_in_page) 412237fead6SMichael Halcrow end_byte_in_page = to; 413c9f2875bSNate Diller zero_user_page(page, end_byte_in_page, 414c9f2875bSNate Diller PAGE_CACHE_SIZE - end_byte_in_page, KM_USER0); 415237fead6SMichael Halcrow out: 4169d8b8ce5SMichael Halcrow return 0; 417237fead6SMichael Halcrow } 418237fead6SMichael Halcrow 41953a2731fSMichael Halcrow /** 42053a2731fSMichael Halcrow * eCryptfs does not currently support holes. When writing after a 42153a2731fSMichael Halcrow * seek past the end of the file, eCryptfs fills in 0's through to the 42253a2731fSMichael Halcrow * current location. The code to fill in the 0's to all the 42353a2731fSMichael Halcrow * intermediate pages calls ecryptfs_prepare_write_no_truncate(). 42453a2731fSMichael Halcrow */ 42553a2731fSMichael Halcrow static int 42653a2731fSMichael Halcrow ecryptfs_prepare_write_no_truncate(struct file *file, struct page *page, 427237fead6SMichael Halcrow unsigned from, unsigned to) 428237fead6SMichael Halcrow { 429237fead6SMichael Halcrow int rc = 0; 430237fead6SMichael Halcrow 431237fead6SMichael Halcrow if (from == 0 && to == PAGE_CACHE_SIZE) 432237fead6SMichael Halcrow goto out; /* If we are writing a full page, it will be 433237fead6SMichael Halcrow up to date. */ 434237fead6SMichael Halcrow if (!PageUptodate(page)) 435237fead6SMichael Halcrow rc = ecryptfs_do_readpage(file, page, page->index); 436237fead6SMichael Halcrow out: 437237fead6SMichael Halcrow return rc; 438237fead6SMichael Halcrow } 439237fead6SMichael Halcrow 44053a2731fSMichael Halcrow static int ecryptfs_prepare_write(struct file *file, struct page *page, 44153a2731fSMichael Halcrow unsigned from, unsigned to) 44253a2731fSMichael Halcrow { 44353a2731fSMichael Halcrow int rc = 0; 44453a2731fSMichael Halcrow 44553a2731fSMichael Halcrow if (from == 0 && to == PAGE_CACHE_SIZE) 44653a2731fSMichael Halcrow goto out; /* If we are writing a full page, it will be 44753a2731fSMichael Halcrow up to date. */ 44853a2731fSMichael Halcrow if (!PageUptodate(page)) 449bf12be1cSMichael Halcrow rc = ecryptfs_read_lower_page_segment(page, page->index, 0, 450bf12be1cSMichael Halcrow PAGE_CACHE_SIZE, 451bf12be1cSMichael Halcrow page->mapping->host); 452240e2df5SMichael Halcrow if (page->index != 0) { 453bf12be1cSMichael Halcrow loff_t end_of_prev_pg_pos = 454bf12be1cSMichael Halcrow (((loff_t)page->index << PAGE_CACHE_SHIFT) - 1); 455240e2df5SMichael Halcrow 456240e2df5SMichael Halcrow if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) { 457240e2df5SMichael Halcrow rc = ecryptfs_truncate(file->f_path.dentry, 458240e2df5SMichael Halcrow end_of_prev_pg_pos); 45953a2731fSMichael Halcrow if (rc) { 46053a2731fSMichael Halcrow printk(KERN_ERR "Error on attempt to " 46153a2731fSMichael Halcrow "truncate to (higher) offset [%lld];" 462240e2df5SMichael Halcrow " rc = [%d]\n", end_of_prev_pg_pos, rc); 46353a2731fSMichael Halcrow goto out; 46453a2731fSMichael Halcrow } 46553a2731fSMichael Halcrow } 466d4c5cdb3SMichael Halcrow if (end_of_prev_pg_pos + 1 > i_size_read(page->mapping->host)) 467d4c5cdb3SMichael Halcrow zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0); 468240e2df5SMichael Halcrow } 46953a2731fSMichael Halcrow out: 47053a2731fSMichael Halcrow return rc; 47153a2731fSMichael Halcrow } 47253a2731fSMichael Halcrow 473237fead6SMichael Halcrow int ecryptfs_writepage_and_release_lower_page(struct page *lower_page, 474237fead6SMichael Halcrow struct inode *lower_inode, 475237fead6SMichael Halcrow struct writeback_control *wbc) 476237fead6SMichael Halcrow { 477237fead6SMichael Halcrow int rc = 0; 478237fead6SMichael Halcrow 479237fead6SMichael Halcrow rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc); 480237fead6SMichael Halcrow if (rc) { 481237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); " 482237fead6SMichael Halcrow "rc = [%d]\n", rc); 483237fead6SMichael Halcrow goto out; 484237fead6SMichael Halcrow } 485237fead6SMichael Halcrow lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; 486237fead6SMichael Halcrow page_cache_release(lower_page); 487237fead6SMichael Halcrow out: 488237fead6SMichael Halcrow return rc; 489237fead6SMichael Halcrow } 490237fead6SMichael Halcrow 49155144768SNick Piggin static void ecryptfs_release_lower_page(struct page *lower_page) 492237fead6SMichael Halcrow { 493237fead6SMichael Halcrow unlock_page(lower_page); 494237fead6SMichael Halcrow page_cache_release(lower_page); 495237fead6SMichael Halcrow } 496237fead6SMichael Halcrow 497237fead6SMichael Halcrow /** 498237fead6SMichael Halcrow * ecryptfs_write_inode_size_to_header 499237fead6SMichael Halcrow * 500237fead6SMichael Halcrow * Writes the lower file size to the first 8 bytes of the header. 501237fead6SMichael Halcrow * 502237fead6SMichael Halcrow * Returns zero on success; non-zero on error. 503237fead6SMichael Halcrow */ 5040216f7f7SMichael Halcrow static int ecryptfs_write_inode_size_to_header(struct inode *ecryptfs_inode) 505237fead6SMichael Halcrow { 506237fead6SMichael Halcrow u64 file_size; 5070216f7f7SMichael Halcrow char *file_size_virt; 5080216f7f7SMichael Halcrow int rc; 509237fead6SMichael Halcrow 5100216f7f7SMichael Halcrow file_size_virt = kmalloc(sizeof(u64), GFP_KERNEL); 5110216f7f7SMichael Halcrow if (!file_size_virt) { 5120216f7f7SMichael Halcrow rc = -ENOMEM; 513237fead6SMichael Halcrow goto out; 514237fead6SMichael Halcrow } 5150216f7f7SMichael Halcrow file_size = (u64)i_size_read(ecryptfs_inode); 516237fead6SMichael Halcrow file_size = cpu_to_be64(file_size); 5170216f7f7SMichael Halcrow memcpy(file_size_virt, &file_size, sizeof(u64)); 5180216f7f7SMichael Halcrow rc = ecryptfs_write_lower(ecryptfs_inode, file_size_virt, 0, 5190216f7f7SMichael Halcrow sizeof(u64)); 5200216f7f7SMichael Halcrow kfree(file_size_virt); 5210216f7f7SMichael Halcrow if (rc) 5220216f7f7SMichael Halcrow printk(KERN_ERR "%s: Error writing file size to header; " 5230216f7f7SMichael Halcrow "rc = [%d]\n", __FUNCTION__, rc); 524237fead6SMichael Halcrow out: 525237fead6SMichael Halcrow return rc; 526237fead6SMichael Halcrow } 527237fead6SMichael Halcrow 5280216f7f7SMichael Halcrow struct kmem_cache *ecryptfs_xattr_cache; 5290216f7f7SMichael Halcrow 5300216f7f7SMichael Halcrow static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode) 531dd2a3b7aSMichael Halcrow { 532dd2a3b7aSMichael Halcrow ssize_t size; 533dd2a3b7aSMichael Halcrow void *xattr_virt; 5340216f7f7SMichael Halcrow struct dentry *lower_dentry = 5350216f7f7SMichael Halcrow ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry; 5360216f7f7SMichael Halcrow struct inode *lower_inode = lower_dentry->d_inode; 537dd2a3b7aSMichael Halcrow u64 file_size; 538dd2a3b7aSMichael Halcrow int rc; 539dd2a3b7aSMichael Halcrow 5400216f7f7SMichael Halcrow if (!lower_inode->i_op->getxattr || !lower_inode->i_op->setxattr) { 5410216f7f7SMichael Halcrow printk(KERN_WARNING 5420216f7f7SMichael Halcrow "No support for setting xattr in lower filesystem\n"); 5430216f7f7SMichael Halcrow rc = -ENOSYS; 5440216f7f7SMichael Halcrow goto out; 5450216f7f7SMichael Halcrow } 546dd2a3b7aSMichael Halcrow xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL); 547dd2a3b7aSMichael Halcrow if (!xattr_virt) { 548dd2a3b7aSMichael Halcrow printk(KERN_ERR "Out of memory whilst attempting to write " 549dd2a3b7aSMichael Halcrow "inode size to xattr\n"); 550dd2a3b7aSMichael Halcrow rc = -ENOMEM; 551dd2a3b7aSMichael Halcrow goto out; 552dd2a3b7aSMichael Halcrow } 5530216f7f7SMichael Halcrow mutex_lock(&lower_inode->i_mutex); 5540216f7f7SMichael Halcrow size = lower_inode->i_op->getxattr(lower_dentry, ECRYPTFS_XATTR_NAME, 5550216f7f7SMichael Halcrow xattr_virt, PAGE_CACHE_SIZE); 556dd2a3b7aSMichael Halcrow if (size < 0) 557dd2a3b7aSMichael Halcrow size = 8; 5580216f7f7SMichael Halcrow file_size = (u64)i_size_read(ecryptfs_inode); 559dd2a3b7aSMichael Halcrow file_size = cpu_to_be64(file_size); 560dd2a3b7aSMichael Halcrow memcpy(xattr_virt, &file_size, sizeof(u64)); 5610216f7f7SMichael Halcrow rc = lower_inode->i_op->setxattr(lower_dentry, ECRYPTFS_XATTR_NAME, 562dd2a3b7aSMichael Halcrow xattr_virt, size, 0); 5630216f7f7SMichael Halcrow mutex_unlock(&lower_inode->i_mutex); 564dd2a3b7aSMichael Halcrow if (rc) 565dd2a3b7aSMichael Halcrow printk(KERN_ERR "Error whilst attempting to write inode size " 566dd2a3b7aSMichael Halcrow "to lower file xattr; rc = [%d]\n", rc); 567dd2a3b7aSMichael Halcrow kmem_cache_free(ecryptfs_xattr_cache, xattr_virt); 568dd2a3b7aSMichael Halcrow out: 569dd2a3b7aSMichael Halcrow return rc; 570dd2a3b7aSMichael Halcrow } 571dd2a3b7aSMichael Halcrow 5720216f7f7SMichael Halcrow int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode) 573dd2a3b7aSMichael Halcrow { 574dd2a3b7aSMichael Halcrow struct ecryptfs_crypt_stat *crypt_stat; 575dd2a3b7aSMichael Halcrow 5760216f7f7SMichael Halcrow crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; 577dd2a3b7aSMichael Halcrow if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) 5780216f7f7SMichael Halcrow return ecryptfs_write_inode_size_to_xattr(ecryptfs_inode); 579dd2a3b7aSMichael Halcrow else 5800216f7f7SMichael Halcrow return ecryptfs_write_inode_size_to_header(ecryptfs_inode); 581dd2a3b7aSMichael Halcrow } 582dd2a3b7aSMichael Halcrow 583237fead6SMichael Halcrow int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, 584237fead6SMichael Halcrow struct file *lower_file, 585237fead6SMichael Halcrow unsigned long lower_page_index, int byte_offset, 586237fead6SMichael Halcrow int region_bytes) 587237fead6SMichael Halcrow { 588237fead6SMichael Halcrow int rc = 0; 589237fead6SMichael Halcrow 5909d8b8ce5SMichael Halcrow *lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index); 5919d8b8ce5SMichael Halcrow if (!(*lower_page)) { 5929d8b8ce5SMichael Halcrow rc = -EINVAL; 5939d8b8ce5SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error attempting to grab " 594237fead6SMichael Halcrow "lower page with index [0x%.16x]\n", 595237fead6SMichael Halcrow lower_page_index); 596237fead6SMichael Halcrow goto out; 597237fead6SMichael Halcrow } 598237fead6SMichael Halcrow rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file, 599237fead6SMichael Halcrow (*lower_page), 600237fead6SMichael Halcrow byte_offset, 601237fead6SMichael Halcrow region_bytes); 602237fead6SMichael Halcrow if (rc) { 603237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "prepare_write for " 604237fead6SMichael Halcrow "lower_page_index = [0x%.16x] failed; rc = " 605237fead6SMichael Halcrow "[%d]\n", lower_page_index, rc); 60655144768SNick Piggin ecryptfs_release_lower_page(*lower_page); 607237fead6SMichael Halcrow (*lower_page) = NULL; 608237fead6SMichael Halcrow } 609a8fa74abSDmitriy Monakhov out: 610237fead6SMichael Halcrow return rc; 611237fead6SMichael Halcrow } 612237fead6SMichael Halcrow 613237fead6SMichael Halcrow /** 614237fead6SMichael Halcrow * ecryptfs_commit_lower_page 615237fead6SMichael Halcrow * 616237fead6SMichael Halcrow * Returns zero on success; non-zero on error 617237fead6SMichael Halcrow */ 618237fead6SMichael Halcrow int 619237fead6SMichael Halcrow ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, 620237fead6SMichael Halcrow struct file *lower_file, int byte_offset, 621237fead6SMichael Halcrow int region_size) 622237fead6SMichael Halcrow { 623237fead6SMichael Halcrow int rc = 0; 624237fead6SMichael Halcrow 625237fead6SMichael Halcrow rc = lower_inode->i_mapping->a_ops->commit_write( 626237fead6SMichael Halcrow lower_file, lower_page, byte_offset, region_size); 627237fead6SMichael Halcrow if (rc < 0) { 628237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, 629237fead6SMichael Halcrow "Error committing write; rc = [%d]\n", rc); 630237fead6SMichael Halcrow } else 631237fead6SMichael Halcrow rc = 0; 63255144768SNick Piggin ecryptfs_release_lower_page(lower_page); 633237fead6SMichael Halcrow return rc; 634237fead6SMichael Halcrow } 635237fead6SMichael Halcrow 636237fead6SMichael Halcrow /** 637237fead6SMichael Halcrow * ecryptfs_copy_page_to_lower 638237fead6SMichael Halcrow * 639237fead6SMichael Halcrow * Used for plaintext pass-through; no page index interpolation 640237fead6SMichael Halcrow * required. 641237fead6SMichael Halcrow */ 642237fead6SMichael Halcrow int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode, 643237fead6SMichael Halcrow struct file *lower_file) 644237fead6SMichael Halcrow { 645237fead6SMichael Halcrow int rc = 0; 646237fead6SMichael Halcrow struct page *lower_page; 647237fead6SMichael Halcrow 648237fead6SMichael Halcrow rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file, 649237fead6SMichael Halcrow page->index, 0, PAGE_CACHE_SIZE); 650237fead6SMichael Halcrow if (rc) { 651237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error attempting to get page " 652237fead6SMichael Halcrow "at index [0x%.16x]\n", page->index); 653237fead6SMichael Halcrow goto out; 654237fead6SMichael Halcrow } 655237fead6SMichael Halcrow /* TODO: aops */ 656237fead6SMichael Halcrow memcpy((char *)page_address(lower_page), page_address(page), 657237fead6SMichael Halcrow PAGE_CACHE_SIZE); 658237fead6SMichael Halcrow rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file, 659237fead6SMichael Halcrow 0, PAGE_CACHE_SIZE); 660237fead6SMichael Halcrow if (rc) 661237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error attempting to commit page " 662237fead6SMichael Halcrow "at index [0x%.16x]\n", page->index); 663237fead6SMichael Halcrow out: 664237fead6SMichael Halcrow return rc; 665237fead6SMichael Halcrow } 666237fead6SMichael Halcrow 667237fead6SMichael Halcrow /** 668237fead6SMichael Halcrow * ecryptfs_commit_write 669237fead6SMichael Halcrow * @file: The eCryptfs file object 670237fead6SMichael Halcrow * @page: The eCryptfs page 671237fead6SMichael Halcrow * @from: Ignored (we rotate the page IV on each write) 672237fead6SMichael Halcrow * @to: Ignored 673237fead6SMichael Halcrow * 674237fead6SMichael Halcrow * This is where we encrypt the data and pass the encrypted data to 675237fead6SMichael Halcrow * the lower filesystem. In OpenPGP-compatible mode, we operate on 676237fead6SMichael Halcrow * entire underlying packets. 677237fead6SMichael Halcrow */ 678237fead6SMichael Halcrow static int ecryptfs_commit_write(struct file *file, struct page *page, 679237fead6SMichael Halcrow unsigned from, unsigned to) 680237fead6SMichael Halcrow { 681237fead6SMichael Halcrow loff_t pos; 682bf12be1cSMichael Halcrow struct inode *ecryptfs_inode = page->mapping->host; 683bf12be1cSMichael Halcrow struct ecryptfs_crypt_stat *crypt_stat = 684bf12be1cSMichael Halcrow &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat; 685237fead6SMichael Halcrow int rc; 686237fead6SMichael Halcrow 687e2bd99ecSMichael Halcrow if (crypt_stat->flags & ECRYPTFS_NEW_FILE) { 688237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in " 689237fead6SMichael Halcrow "crypt_stat at memory location [%p]\n", crypt_stat); 690e2bd99ecSMichael Halcrow crypt_stat->flags &= ~(ECRYPTFS_NEW_FILE); 691237fead6SMichael Halcrow } else 692237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "Not a new file\n"); 693237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" 694237fead6SMichael Halcrow "(page w/ index = [0x%.16x], to = [%d])\n", page->index, 695237fead6SMichael Halcrow to); 696bf12be1cSMichael Halcrow /* Fills in zeros if 'to' goes beyond inode size */ 697237fead6SMichael Halcrow rc = fill_zeros_to_end_of_page(page, to); 698237fead6SMichael Halcrow if (rc) { 699237fead6SMichael Halcrow ecryptfs_printk(KERN_WARNING, "Error attempting to fill " 700237fead6SMichael Halcrow "zeros in page with index = [0x%.16x]\n", 701237fead6SMichael Halcrow page->index); 702237fead6SMichael Halcrow goto out; 703237fead6SMichael Halcrow } 7040216f7f7SMichael Halcrow rc = ecryptfs_encrypt_page(page); 705237fead6SMichael Halcrow if (rc) { 706237fead6SMichael Halcrow ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " 707237fead6SMichael Halcrow "index [0x%.16x])\n", page->index); 708237fead6SMichael Halcrow goto out; 709237fead6SMichael Halcrow } 710*d6a13c17SMichael Halcrow pos = (((loff_t)page->index) << PAGE_CACHE_SHIFT) + to; 711bf12be1cSMichael Halcrow if (pos > i_size_read(ecryptfs_inode)) { 712bf12be1cSMichael Halcrow i_size_write(ecryptfs_inode, pos); 713237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "Expanded file size to " 714bf12be1cSMichael Halcrow "[0x%.16x]\n", i_size_read(ecryptfs_inode)); 715237fead6SMichael Halcrow } 716bf12be1cSMichael Halcrow rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); 717dd2a3b7aSMichael Halcrow if (rc) 718dd2a3b7aSMichael Halcrow printk(KERN_ERR "Error writing inode size to metadata; " 719dd2a3b7aSMichael Halcrow "rc = [%d]\n", rc); 720237fead6SMichael Halcrow out: 721237fead6SMichael Halcrow return rc; 722237fead6SMichael Halcrow } 723237fead6SMichael Halcrow 724237fead6SMichael Halcrow /** 725240e2df5SMichael Halcrow * ecryptfs_write_zeros 726237fead6SMichael Halcrow * @file: The ecryptfs file 727237fead6SMichael Halcrow * @index: The index in which we are writing 728237fead6SMichael Halcrow * @start: The position after the last block of data 729237fead6SMichael Halcrow * @num_zeros: The number of zeros to write 730237fead6SMichael Halcrow * 731237fead6SMichael Halcrow * Write a specified number of zero's to a page. 732237fead6SMichael Halcrow * 733237fead6SMichael Halcrow * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE 734237fead6SMichael Halcrow */ 735240e2df5SMichael Halcrow int 736240e2df5SMichael Halcrow ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int num_zeros) 737237fead6SMichael Halcrow { 738237fead6SMichael Halcrow int rc = 0; 739237fead6SMichael Halcrow struct page *tmp_page; 740237fead6SMichael Halcrow 741237fead6SMichael Halcrow tmp_page = ecryptfs_get1page(file, index); 742237fead6SMichael Halcrow if (IS_ERR(tmp_page)) { 743237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error getting page at index " 744237fead6SMichael Halcrow "[0x%.16x]\n", index); 745237fead6SMichael Halcrow rc = PTR_ERR(tmp_page); 746237fead6SMichael Halcrow goto out; 747237fead6SMichael Halcrow } 7485dda6992SMichael Halcrow rc = ecryptfs_prepare_write_no_truncate(file, tmp_page, start, 7495dda6992SMichael Halcrow (start + num_zeros)); 7505dda6992SMichael Halcrow if (rc) { 751237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error preparing to write zero's " 75253a2731fSMichael Halcrow "to page at index [0x%.16x]\n", 753237fead6SMichael Halcrow index); 754237fead6SMichael Halcrow page_cache_release(tmp_page); 755237fead6SMichael Halcrow goto out; 756237fead6SMichael Halcrow } 757c9f2875bSNate Diller zero_user_page(tmp_page, start, num_zeros, KM_USER0); 758237fead6SMichael Halcrow rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros); 759237fead6SMichael Halcrow if (rc < 0) { 760237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error attempting to write zero's " 761237fead6SMichael Halcrow "to remainder of page at index [0x%.16x]\n", 762237fead6SMichael Halcrow index); 763237fead6SMichael Halcrow page_cache_release(tmp_page); 764237fead6SMichael Halcrow goto out; 765237fead6SMichael Halcrow } 766237fead6SMichael Halcrow rc = 0; 767237fead6SMichael Halcrow page_cache_release(tmp_page); 768237fead6SMichael Halcrow out: 769237fead6SMichael Halcrow return rc; 770237fead6SMichael Halcrow } 771237fead6SMichael Halcrow 772237fead6SMichael Halcrow static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block) 773237fead6SMichael Halcrow { 774237fead6SMichael Halcrow int rc = 0; 775237fead6SMichael Halcrow struct inode *inode; 776237fead6SMichael Halcrow struct inode *lower_inode; 777237fead6SMichael Halcrow 778237fead6SMichael Halcrow inode = (struct inode *)mapping->host; 779237fead6SMichael Halcrow lower_inode = ecryptfs_inode_to_lower(inode); 780237fead6SMichael Halcrow if (lower_inode->i_mapping->a_ops->bmap) 781237fead6SMichael Halcrow rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping, 782237fead6SMichael Halcrow block); 783237fead6SMichael Halcrow return rc; 784237fead6SMichael Halcrow } 785237fead6SMichael Halcrow 786237fead6SMichael Halcrow struct address_space_operations ecryptfs_aops = { 787237fead6SMichael Halcrow .writepage = ecryptfs_writepage, 788237fead6SMichael Halcrow .readpage = ecryptfs_readpage, 789237fead6SMichael Halcrow .prepare_write = ecryptfs_prepare_write, 790237fead6SMichael Halcrow .commit_write = ecryptfs_commit_write, 791237fead6SMichael Halcrow .bmap = ecryptfs_bmap, 792237fead6SMichael Halcrow }; 793