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 /** 270*bf12be1cSMichael Halcrow * ecryptfs_copy_up_encrypted_with_header 271*bf12be1cSMichael Halcrow * @page: Sort of a ``virtual'' representation of the encrypted lower 272*bf12be1cSMichael Halcrow * file. The actual lower file does not have the metadata in 273*bf12be1cSMichael Halcrow * the header. This is locked. 274*bf12be1cSMichael Halcrow * @crypt_stat: The eCryptfs inode's cryptographic context 275237fead6SMichael Halcrow * 276*bf12be1cSMichael Halcrow * The ``view'' is the version of the file that userspace winds up 277*bf12be1cSMichael Halcrow * seeing, with the header information inserted. 278237fead6SMichael Halcrow */ 279*bf12be1cSMichael Halcrow static int 280*bf12be1cSMichael Halcrow ecryptfs_copy_up_encrypted_with_header(struct page *page, 281*bf12be1cSMichael Halcrow struct ecryptfs_crypt_stat *crypt_stat) 282237fead6SMichael Halcrow { 283*bf12be1cSMichael Halcrow loff_t extent_num_in_page = 0; 284*bf12be1cSMichael Halcrow loff_t num_extents_per_page = (PAGE_CACHE_SIZE 285*bf12be1cSMichael Halcrow / crypt_stat->extent_size); 286237fead6SMichael Halcrow int rc = 0; 287237fead6SMichael Halcrow 288*bf12be1cSMichael Halcrow while (extent_num_in_page < num_extents_per_page) { 289*bf12be1cSMichael Halcrow loff_t view_extent_num = ((page->index * num_extents_per_page) 290*bf12be1cSMichael Halcrow + extent_num_in_page); 291e77a56ddSMichael Halcrow 292*bf12be1cSMichael Halcrow if (view_extent_num < crypt_stat->num_header_extents_at_front) { 293*bf12be1cSMichael Halcrow /* This is a header extent */ 294e77a56ddSMichael Halcrow char *page_virt; 295e77a56ddSMichael Halcrow 2969d8b8ce5SMichael Halcrow page_virt = kmap_atomic(page, KM_USER0); 297e77a56ddSMichael Halcrow memset(page_virt, 0, PAGE_CACHE_SIZE); 298*bf12be1cSMichael Halcrow /* TODO: Support more than one header extent */ 299*bf12be1cSMichael Halcrow if (view_extent_num == 0) { 300e77a56ddSMichael Halcrow rc = ecryptfs_read_xattr_region( 301d7cdc5feSMichael Halcrow page_virt, page->mapping->host); 302e77a56ddSMichael Halcrow set_header_info(page_virt, crypt_stat); 303e77a56ddSMichael Halcrow } 3049d8b8ce5SMichael Halcrow kunmap_atomic(page_virt, KM_USER0); 3050a9ac382SMichael Halcrow flush_dcache_page(page); 306e77a56ddSMichael Halcrow if (rc) { 307*bf12be1cSMichael Halcrow ClearPageUptodate(page); 308*bf12be1cSMichael Halcrow printk(KERN_ERR "%s: Error reading xattr " 309*bf12be1cSMichael Halcrow "region; rc = [%d]\n", __FUNCTION__, rc); 310e77a56ddSMichael Halcrow goto out; 311e77a56ddSMichael Halcrow } 312*bf12be1cSMichael Halcrow SetPageUptodate(page); 313e77a56ddSMichael Halcrow } else { 314*bf12be1cSMichael Halcrow /* This is an encrypted data extent */ 315*bf12be1cSMichael Halcrow loff_t lower_offset = 316*bf12be1cSMichael Halcrow ((view_extent_num - 317*bf12be1cSMichael Halcrow crypt_stat->num_header_extents_at_front) 318*bf12be1cSMichael Halcrow * crypt_stat->extent_size); 319*bf12be1cSMichael Halcrow 320*bf12be1cSMichael Halcrow rc = ecryptfs_read_lower_page_segment( 321*bf12be1cSMichael Halcrow page, (lower_offset >> PAGE_CACHE_SHIFT), 322*bf12be1cSMichael Halcrow (lower_offset & ~PAGE_CACHE_MASK), 323*bf12be1cSMichael Halcrow crypt_stat->extent_size, page->mapping->host); 324e77a56ddSMichael Halcrow if (rc) { 325*bf12be1cSMichael Halcrow printk(KERN_ERR "%s: Error attempting to read " 326*bf12be1cSMichael Halcrow "extent at offset [%lld] in the lower " 327*bf12be1cSMichael Halcrow "file; rc = [%d]\n", __FUNCTION__, 328*bf12be1cSMichael Halcrow lower_offset, rc); 329e77a56ddSMichael Halcrow goto out; 330e77a56ddSMichael Halcrow } 331e77a56ddSMichael Halcrow } 332*bf12be1cSMichael Halcrow extent_num_in_page++; 333*bf12be1cSMichael Halcrow } 334*bf12be1cSMichael Halcrow out: 335*bf12be1cSMichael Halcrow return rc; 336*bf12be1cSMichael Halcrow } 337*bf12be1cSMichael Halcrow 338*bf12be1cSMichael Halcrow /** 339*bf12be1cSMichael Halcrow * ecryptfs_readpage 340*bf12be1cSMichael Halcrow * @file: An eCryptfs file 341*bf12be1cSMichael Halcrow * @page: Page from eCryptfs inode mapping into which to stick the read data 342*bf12be1cSMichael Halcrow * 343*bf12be1cSMichael Halcrow * Read in a page, decrypting if necessary. 344*bf12be1cSMichael Halcrow * 345*bf12be1cSMichael Halcrow * Returns zero on success; non-zero on error. 346*bf12be1cSMichael Halcrow */ 347*bf12be1cSMichael Halcrow static int ecryptfs_readpage(struct file *file, struct page *page) 348*bf12be1cSMichael Halcrow { 349*bf12be1cSMichael Halcrow struct ecryptfs_crypt_stat *crypt_stat = 350*bf12be1cSMichael Halcrow &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat; 351*bf12be1cSMichael Halcrow int rc = 0; 352*bf12be1cSMichael Halcrow 353*bf12be1cSMichael Halcrow if (!crypt_stat 354*bf12be1cSMichael Halcrow || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED) 355*bf12be1cSMichael Halcrow || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) { 356*bf12be1cSMichael Halcrow ecryptfs_printk(KERN_DEBUG, 357*bf12be1cSMichael Halcrow "Passing through unencrypted page\n"); 358*bf12be1cSMichael Halcrow rc = ecryptfs_read_lower_page_segment(page, page->index, 0, 359*bf12be1cSMichael Halcrow PAGE_CACHE_SIZE, 360*bf12be1cSMichael Halcrow page->mapping->host); 361*bf12be1cSMichael Halcrow } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { 362*bf12be1cSMichael Halcrow if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { 363*bf12be1cSMichael Halcrow rc = ecryptfs_copy_up_encrypted_with_header(page, 364*bf12be1cSMichael Halcrow crypt_stat); 365*bf12be1cSMichael Halcrow if (rc) { 366*bf12be1cSMichael Halcrow printk(KERN_ERR "%s: Error attempting to copy " 367*bf12be1cSMichael Halcrow "the encrypted content from the lower " 368*bf12be1cSMichael Halcrow "file whilst inserting the metadata " 369*bf12be1cSMichael Halcrow "from the xattr into the header; rc = " 370*bf12be1cSMichael Halcrow "[%d]\n", __FUNCTION__, rc); 371*bf12be1cSMichael Halcrow goto out; 372*bf12be1cSMichael Halcrow } 373*bf12be1cSMichael Halcrow 374e77a56ddSMichael Halcrow } else { 375*bf12be1cSMichael Halcrow rc = ecryptfs_read_lower_page_segment( 376*bf12be1cSMichael Halcrow page, page->index, 0, PAGE_CACHE_SIZE, 377*bf12be1cSMichael Halcrow page->mapping->host); 378e77a56ddSMichael Halcrow if (rc) { 379e77a56ddSMichael Halcrow printk(KERN_ERR "Error reading page; rc = " 380e77a56ddSMichael Halcrow "[%d]\n", rc); 381e77a56ddSMichael Halcrow goto out; 382e77a56ddSMichael Halcrow } 383e77a56ddSMichael Halcrow } 384237fead6SMichael Halcrow } else { 3850216f7f7SMichael Halcrow rc = ecryptfs_decrypt_page(page); 386237fead6SMichael Halcrow if (rc) { 387237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error decrypting page; " 388237fead6SMichael Halcrow "rc = [%d]\n", rc); 389237fead6SMichael Halcrow goto out; 390237fead6SMichael Halcrow } 391237fead6SMichael Halcrow } 392237fead6SMichael Halcrow out: 393237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n", 394237fead6SMichael Halcrow page->index); 395237fead6SMichael Halcrow unlock_page(page); 396237fead6SMichael Halcrow return rc; 397237fead6SMichael Halcrow } 398237fead6SMichael Halcrow 399dd2a3b7aSMichael Halcrow /** 400dd2a3b7aSMichael Halcrow * Called with lower inode mutex held. 401dd2a3b7aSMichael Halcrow */ 402237fead6SMichael Halcrow static int fill_zeros_to_end_of_page(struct page *page, unsigned int to) 403237fead6SMichael Halcrow { 404237fead6SMichael Halcrow struct inode *inode = page->mapping->host; 405237fead6SMichael Halcrow int end_byte_in_page; 406237fead6SMichael Halcrow 4079d8b8ce5SMichael Halcrow if ((i_size_read(inode) / PAGE_CACHE_SIZE) != page->index) 4089d8b8ce5SMichael Halcrow goto out; 409237fead6SMichael Halcrow end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE; 410237fead6SMichael Halcrow if (to > end_byte_in_page) 411237fead6SMichael Halcrow end_byte_in_page = to; 412c9f2875bSNate Diller zero_user_page(page, end_byte_in_page, 413c9f2875bSNate Diller PAGE_CACHE_SIZE - end_byte_in_page, KM_USER0); 414237fead6SMichael Halcrow out: 4159d8b8ce5SMichael Halcrow return 0; 416237fead6SMichael Halcrow } 417237fead6SMichael Halcrow 41853a2731fSMichael Halcrow /** 41953a2731fSMichael Halcrow * eCryptfs does not currently support holes. When writing after a 42053a2731fSMichael Halcrow * seek past the end of the file, eCryptfs fills in 0's through to the 42153a2731fSMichael Halcrow * current location. The code to fill in the 0's to all the 42253a2731fSMichael Halcrow * intermediate pages calls ecryptfs_prepare_write_no_truncate(). 42353a2731fSMichael Halcrow */ 42453a2731fSMichael Halcrow static int 42553a2731fSMichael Halcrow ecryptfs_prepare_write_no_truncate(struct file *file, struct page *page, 426237fead6SMichael Halcrow unsigned from, unsigned to) 427237fead6SMichael Halcrow { 428237fead6SMichael Halcrow int rc = 0; 429237fead6SMichael Halcrow 430237fead6SMichael Halcrow if (from == 0 && to == PAGE_CACHE_SIZE) 431237fead6SMichael Halcrow goto out; /* If we are writing a full page, it will be 432237fead6SMichael Halcrow up to date. */ 433237fead6SMichael Halcrow if (!PageUptodate(page)) 434237fead6SMichael Halcrow rc = ecryptfs_do_readpage(file, page, page->index); 435237fead6SMichael Halcrow out: 436237fead6SMichael Halcrow return rc; 437237fead6SMichael Halcrow } 438237fead6SMichael Halcrow 43953a2731fSMichael Halcrow static int ecryptfs_prepare_write(struct file *file, struct page *page, 44053a2731fSMichael Halcrow unsigned from, unsigned to) 44153a2731fSMichael Halcrow { 44253a2731fSMichael Halcrow int rc = 0; 44353a2731fSMichael Halcrow 44453a2731fSMichael Halcrow if (from == 0 && to == PAGE_CACHE_SIZE) 44553a2731fSMichael Halcrow goto out; /* If we are writing a full page, it will be 44653a2731fSMichael Halcrow up to date. */ 44753a2731fSMichael Halcrow if (!PageUptodate(page)) 448*bf12be1cSMichael Halcrow rc = ecryptfs_read_lower_page_segment(page, page->index, 0, 449*bf12be1cSMichael Halcrow PAGE_CACHE_SIZE, 450*bf12be1cSMichael Halcrow page->mapping->host); 451240e2df5SMichael Halcrow if (page->index != 0) { 452*bf12be1cSMichael Halcrow loff_t end_of_prev_pg_pos = 453*bf12be1cSMichael Halcrow (((loff_t)page->index << PAGE_CACHE_SHIFT) - 1); 454240e2df5SMichael Halcrow 455240e2df5SMichael Halcrow if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) { 456240e2df5SMichael Halcrow rc = ecryptfs_truncate(file->f_path.dentry, 457240e2df5SMichael Halcrow end_of_prev_pg_pos); 45853a2731fSMichael Halcrow if (rc) { 45953a2731fSMichael Halcrow printk(KERN_ERR "Error on attempt to " 46053a2731fSMichael Halcrow "truncate to (higher) offset [%lld];" 461240e2df5SMichael Halcrow " rc = [%d]\n", end_of_prev_pg_pos, rc); 46253a2731fSMichael Halcrow goto out; 46353a2731fSMichael Halcrow } 46453a2731fSMichael Halcrow } 465d4c5cdb3SMichael Halcrow if (end_of_prev_pg_pos + 1 > i_size_read(page->mapping->host)) 466d4c5cdb3SMichael Halcrow zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0); 467240e2df5SMichael Halcrow } 46853a2731fSMichael Halcrow out: 46953a2731fSMichael Halcrow return rc; 47053a2731fSMichael Halcrow } 47153a2731fSMichael Halcrow 472237fead6SMichael Halcrow int ecryptfs_writepage_and_release_lower_page(struct page *lower_page, 473237fead6SMichael Halcrow struct inode *lower_inode, 474237fead6SMichael Halcrow struct writeback_control *wbc) 475237fead6SMichael Halcrow { 476237fead6SMichael Halcrow int rc = 0; 477237fead6SMichael Halcrow 478237fead6SMichael Halcrow rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc); 479237fead6SMichael Halcrow if (rc) { 480237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); " 481237fead6SMichael Halcrow "rc = [%d]\n", rc); 482237fead6SMichael Halcrow goto out; 483237fead6SMichael Halcrow } 484237fead6SMichael Halcrow lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; 485237fead6SMichael Halcrow page_cache_release(lower_page); 486237fead6SMichael Halcrow out: 487237fead6SMichael Halcrow return rc; 488237fead6SMichael Halcrow } 489237fead6SMichael Halcrow 49055144768SNick Piggin static void ecryptfs_release_lower_page(struct page *lower_page) 491237fead6SMichael Halcrow { 492237fead6SMichael Halcrow unlock_page(lower_page); 493237fead6SMichael Halcrow page_cache_release(lower_page); 494237fead6SMichael Halcrow } 495237fead6SMichael Halcrow 496237fead6SMichael Halcrow /** 497237fead6SMichael Halcrow * ecryptfs_write_inode_size_to_header 498237fead6SMichael Halcrow * 499237fead6SMichael Halcrow * Writes the lower file size to the first 8 bytes of the header. 500237fead6SMichael Halcrow * 501237fead6SMichael Halcrow * Returns zero on success; non-zero on error. 502237fead6SMichael Halcrow */ 5030216f7f7SMichael Halcrow static int ecryptfs_write_inode_size_to_header(struct inode *ecryptfs_inode) 504237fead6SMichael Halcrow { 505237fead6SMichael Halcrow u64 file_size; 5060216f7f7SMichael Halcrow char *file_size_virt; 5070216f7f7SMichael Halcrow int rc; 508237fead6SMichael Halcrow 5090216f7f7SMichael Halcrow file_size_virt = kmalloc(sizeof(u64), GFP_KERNEL); 5100216f7f7SMichael Halcrow if (!file_size_virt) { 5110216f7f7SMichael Halcrow rc = -ENOMEM; 512237fead6SMichael Halcrow goto out; 513237fead6SMichael Halcrow } 5140216f7f7SMichael Halcrow file_size = (u64)i_size_read(ecryptfs_inode); 515237fead6SMichael Halcrow file_size = cpu_to_be64(file_size); 5160216f7f7SMichael Halcrow memcpy(file_size_virt, &file_size, sizeof(u64)); 5170216f7f7SMichael Halcrow rc = ecryptfs_write_lower(ecryptfs_inode, file_size_virt, 0, 5180216f7f7SMichael Halcrow sizeof(u64)); 5190216f7f7SMichael Halcrow kfree(file_size_virt); 5200216f7f7SMichael Halcrow if (rc) 5210216f7f7SMichael Halcrow printk(KERN_ERR "%s: Error writing file size to header; " 5220216f7f7SMichael Halcrow "rc = [%d]\n", __FUNCTION__, rc); 523237fead6SMichael Halcrow out: 524237fead6SMichael Halcrow return rc; 525237fead6SMichael Halcrow } 526237fead6SMichael Halcrow 5270216f7f7SMichael Halcrow struct kmem_cache *ecryptfs_xattr_cache; 5280216f7f7SMichael Halcrow 5290216f7f7SMichael Halcrow static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode) 530dd2a3b7aSMichael Halcrow { 531dd2a3b7aSMichael Halcrow ssize_t size; 532dd2a3b7aSMichael Halcrow void *xattr_virt; 5330216f7f7SMichael Halcrow struct dentry *lower_dentry = 5340216f7f7SMichael Halcrow ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry; 5350216f7f7SMichael Halcrow struct inode *lower_inode = lower_dentry->d_inode; 536dd2a3b7aSMichael Halcrow u64 file_size; 537dd2a3b7aSMichael Halcrow int rc; 538dd2a3b7aSMichael Halcrow 5390216f7f7SMichael Halcrow if (!lower_inode->i_op->getxattr || !lower_inode->i_op->setxattr) { 5400216f7f7SMichael Halcrow printk(KERN_WARNING 5410216f7f7SMichael Halcrow "No support for setting xattr in lower filesystem\n"); 5420216f7f7SMichael Halcrow rc = -ENOSYS; 5430216f7f7SMichael Halcrow goto out; 5440216f7f7SMichael Halcrow } 545dd2a3b7aSMichael Halcrow xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL); 546dd2a3b7aSMichael Halcrow if (!xattr_virt) { 547dd2a3b7aSMichael Halcrow printk(KERN_ERR "Out of memory whilst attempting to write " 548dd2a3b7aSMichael Halcrow "inode size to xattr\n"); 549dd2a3b7aSMichael Halcrow rc = -ENOMEM; 550dd2a3b7aSMichael Halcrow goto out; 551dd2a3b7aSMichael Halcrow } 5520216f7f7SMichael Halcrow mutex_lock(&lower_inode->i_mutex); 5530216f7f7SMichael Halcrow size = lower_inode->i_op->getxattr(lower_dentry, ECRYPTFS_XATTR_NAME, 5540216f7f7SMichael Halcrow xattr_virt, PAGE_CACHE_SIZE); 555dd2a3b7aSMichael Halcrow if (size < 0) 556dd2a3b7aSMichael Halcrow size = 8; 5570216f7f7SMichael Halcrow file_size = (u64)i_size_read(ecryptfs_inode); 558dd2a3b7aSMichael Halcrow file_size = cpu_to_be64(file_size); 559dd2a3b7aSMichael Halcrow memcpy(xattr_virt, &file_size, sizeof(u64)); 5600216f7f7SMichael Halcrow rc = lower_inode->i_op->setxattr(lower_dentry, ECRYPTFS_XATTR_NAME, 561dd2a3b7aSMichael Halcrow xattr_virt, size, 0); 5620216f7f7SMichael Halcrow mutex_unlock(&lower_inode->i_mutex); 563dd2a3b7aSMichael Halcrow if (rc) 564dd2a3b7aSMichael Halcrow printk(KERN_ERR "Error whilst attempting to write inode size " 565dd2a3b7aSMichael Halcrow "to lower file xattr; rc = [%d]\n", rc); 566dd2a3b7aSMichael Halcrow kmem_cache_free(ecryptfs_xattr_cache, xattr_virt); 567dd2a3b7aSMichael Halcrow out: 568dd2a3b7aSMichael Halcrow return rc; 569dd2a3b7aSMichael Halcrow } 570dd2a3b7aSMichael Halcrow 5710216f7f7SMichael Halcrow int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode) 572dd2a3b7aSMichael Halcrow { 573dd2a3b7aSMichael Halcrow struct ecryptfs_crypt_stat *crypt_stat; 574dd2a3b7aSMichael Halcrow 5750216f7f7SMichael Halcrow crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; 576dd2a3b7aSMichael Halcrow if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) 5770216f7f7SMichael Halcrow return ecryptfs_write_inode_size_to_xattr(ecryptfs_inode); 578dd2a3b7aSMichael Halcrow else 5790216f7f7SMichael Halcrow return ecryptfs_write_inode_size_to_header(ecryptfs_inode); 580dd2a3b7aSMichael Halcrow } 581dd2a3b7aSMichael Halcrow 582237fead6SMichael Halcrow int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, 583237fead6SMichael Halcrow struct file *lower_file, 584237fead6SMichael Halcrow unsigned long lower_page_index, int byte_offset, 585237fead6SMichael Halcrow int region_bytes) 586237fead6SMichael Halcrow { 587237fead6SMichael Halcrow int rc = 0; 588237fead6SMichael Halcrow 5899d8b8ce5SMichael Halcrow *lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index); 5909d8b8ce5SMichael Halcrow if (!(*lower_page)) { 5919d8b8ce5SMichael Halcrow rc = -EINVAL; 5929d8b8ce5SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error attempting to grab " 593237fead6SMichael Halcrow "lower page with index [0x%.16x]\n", 594237fead6SMichael Halcrow lower_page_index); 595237fead6SMichael Halcrow goto out; 596237fead6SMichael Halcrow } 597237fead6SMichael Halcrow rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file, 598237fead6SMichael Halcrow (*lower_page), 599237fead6SMichael Halcrow byte_offset, 600237fead6SMichael Halcrow region_bytes); 601237fead6SMichael Halcrow if (rc) { 602237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "prepare_write for " 603237fead6SMichael Halcrow "lower_page_index = [0x%.16x] failed; rc = " 604237fead6SMichael Halcrow "[%d]\n", lower_page_index, rc); 60555144768SNick Piggin ecryptfs_release_lower_page(*lower_page); 606237fead6SMichael Halcrow (*lower_page) = NULL; 607237fead6SMichael Halcrow } 608a8fa74abSDmitriy Monakhov out: 609237fead6SMichael Halcrow return rc; 610237fead6SMichael Halcrow } 611237fead6SMichael Halcrow 612237fead6SMichael Halcrow /** 613237fead6SMichael Halcrow * ecryptfs_commit_lower_page 614237fead6SMichael Halcrow * 615237fead6SMichael Halcrow * Returns zero on success; non-zero on error 616237fead6SMichael Halcrow */ 617237fead6SMichael Halcrow int 618237fead6SMichael Halcrow ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, 619237fead6SMichael Halcrow struct file *lower_file, int byte_offset, 620237fead6SMichael Halcrow int region_size) 621237fead6SMichael Halcrow { 622237fead6SMichael Halcrow int rc = 0; 623237fead6SMichael Halcrow 624237fead6SMichael Halcrow rc = lower_inode->i_mapping->a_ops->commit_write( 625237fead6SMichael Halcrow lower_file, lower_page, byte_offset, region_size); 626237fead6SMichael Halcrow if (rc < 0) { 627237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, 628237fead6SMichael Halcrow "Error committing write; rc = [%d]\n", rc); 629237fead6SMichael Halcrow } else 630237fead6SMichael Halcrow rc = 0; 63155144768SNick Piggin ecryptfs_release_lower_page(lower_page); 632237fead6SMichael Halcrow return rc; 633237fead6SMichael Halcrow } 634237fead6SMichael Halcrow 635237fead6SMichael Halcrow /** 636237fead6SMichael Halcrow * ecryptfs_copy_page_to_lower 637237fead6SMichael Halcrow * 638237fead6SMichael Halcrow * Used for plaintext pass-through; no page index interpolation 639237fead6SMichael Halcrow * required. 640237fead6SMichael Halcrow */ 641237fead6SMichael Halcrow int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode, 642237fead6SMichael Halcrow struct file *lower_file) 643237fead6SMichael Halcrow { 644237fead6SMichael Halcrow int rc = 0; 645237fead6SMichael Halcrow struct page *lower_page; 646237fead6SMichael Halcrow 647237fead6SMichael Halcrow rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file, 648237fead6SMichael Halcrow page->index, 0, PAGE_CACHE_SIZE); 649237fead6SMichael Halcrow if (rc) { 650237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error attempting to get page " 651237fead6SMichael Halcrow "at index [0x%.16x]\n", page->index); 652237fead6SMichael Halcrow goto out; 653237fead6SMichael Halcrow } 654237fead6SMichael Halcrow /* TODO: aops */ 655237fead6SMichael Halcrow memcpy((char *)page_address(lower_page), page_address(page), 656237fead6SMichael Halcrow PAGE_CACHE_SIZE); 657237fead6SMichael Halcrow rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file, 658237fead6SMichael Halcrow 0, PAGE_CACHE_SIZE); 659237fead6SMichael Halcrow if (rc) 660237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error attempting to commit page " 661237fead6SMichael Halcrow "at index [0x%.16x]\n", page->index); 662237fead6SMichael Halcrow out: 663237fead6SMichael Halcrow return rc; 664237fead6SMichael Halcrow } 665237fead6SMichael Halcrow 666237fead6SMichael Halcrow /** 667237fead6SMichael Halcrow * ecryptfs_commit_write 668237fead6SMichael Halcrow * @file: The eCryptfs file object 669237fead6SMichael Halcrow * @page: The eCryptfs page 670237fead6SMichael Halcrow * @from: Ignored (we rotate the page IV on each write) 671237fead6SMichael Halcrow * @to: Ignored 672237fead6SMichael Halcrow * 673237fead6SMichael Halcrow * This is where we encrypt the data and pass the encrypted data to 674237fead6SMichael Halcrow * the lower filesystem. In OpenPGP-compatible mode, we operate on 675237fead6SMichael Halcrow * entire underlying packets. 676237fead6SMichael Halcrow */ 677237fead6SMichael Halcrow static int ecryptfs_commit_write(struct file *file, struct page *page, 678237fead6SMichael Halcrow unsigned from, unsigned to) 679237fead6SMichael Halcrow { 680237fead6SMichael Halcrow loff_t pos; 681*bf12be1cSMichael Halcrow struct inode *ecryptfs_inode = page->mapping->host; 682*bf12be1cSMichael Halcrow struct ecryptfs_crypt_stat *crypt_stat = 683*bf12be1cSMichael Halcrow &ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat; 684237fead6SMichael Halcrow int rc; 685237fead6SMichael Halcrow 686e2bd99ecSMichael Halcrow if (crypt_stat->flags & ECRYPTFS_NEW_FILE) { 687237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in " 688237fead6SMichael Halcrow "crypt_stat at memory location [%p]\n", crypt_stat); 689e2bd99ecSMichael Halcrow crypt_stat->flags &= ~(ECRYPTFS_NEW_FILE); 690237fead6SMichael Halcrow } else 691237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "Not a new file\n"); 692237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" 693237fead6SMichael Halcrow "(page w/ index = [0x%.16x], to = [%d])\n", page->index, 694237fead6SMichael Halcrow to); 695*bf12be1cSMichael Halcrow /* Fills in zeros if 'to' goes beyond inode size */ 696237fead6SMichael Halcrow rc = fill_zeros_to_end_of_page(page, to); 697237fead6SMichael Halcrow if (rc) { 698237fead6SMichael Halcrow ecryptfs_printk(KERN_WARNING, "Error attempting to fill " 699237fead6SMichael Halcrow "zeros in page with index = [0x%.16x]\n", 700237fead6SMichael Halcrow page->index); 701237fead6SMichael Halcrow goto out; 702237fead6SMichael Halcrow } 7030216f7f7SMichael Halcrow rc = ecryptfs_encrypt_page(page); 704237fead6SMichael Halcrow if (rc) { 705237fead6SMichael Halcrow ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " 706237fead6SMichael Halcrow "index [0x%.16x])\n", page->index); 707237fead6SMichael Halcrow goto out; 708237fead6SMichael Halcrow } 709*bf12be1cSMichael Halcrow pos = (page->index << PAGE_CACHE_SHIFT) + to; 710*bf12be1cSMichael Halcrow if (pos > i_size_read(ecryptfs_inode)) { 711*bf12be1cSMichael Halcrow i_size_write(ecryptfs_inode, pos); 712237fead6SMichael Halcrow ecryptfs_printk(KERN_DEBUG, "Expanded file size to " 713*bf12be1cSMichael Halcrow "[0x%.16x]\n", i_size_read(ecryptfs_inode)); 714237fead6SMichael Halcrow } 715*bf12be1cSMichael Halcrow rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); 716dd2a3b7aSMichael Halcrow if (rc) 717dd2a3b7aSMichael Halcrow printk(KERN_ERR "Error writing inode size to metadata; " 718dd2a3b7aSMichael Halcrow "rc = [%d]\n", rc); 719237fead6SMichael Halcrow out: 720237fead6SMichael Halcrow return rc; 721237fead6SMichael Halcrow } 722237fead6SMichael Halcrow 723237fead6SMichael Halcrow /** 724240e2df5SMichael Halcrow * ecryptfs_write_zeros 725237fead6SMichael Halcrow * @file: The ecryptfs file 726237fead6SMichael Halcrow * @index: The index in which we are writing 727237fead6SMichael Halcrow * @start: The position after the last block of data 728237fead6SMichael Halcrow * @num_zeros: The number of zeros to write 729237fead6SMichael Halcrow * 730237fead6SMichael Halcrow * Write a specified number of zero's to a page. 731237fead6SMichael Halcrow * 732237fead6SMichael Halcrow * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE 733237fead6SMichael Halcrow */ 734240e2df5SMichael Halcrow int 735240e2df5SMichael Halcrow ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int num_zeros) 736237fead6SMichael Halcrow { 737237fead6SMichael Halcrow int rc = 0; 738237fead6SMichael Halcrow struct page *tmp_page; 739237fead6SMichael Halcrow 740237fead6SMichael Halcrow tmp_page = ecryptfs_get1page(file, index); 741237fead6SMichael Halcrow if (IS_ERR(tmp_page)) { 742237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error getting page at index " 743237fead6SMichael Halcrow "[0x%.16x]\n", index); 744237fead6SMichael Halcrow rc = PTR_ERR(tmp_page); 745237fead6SMichael Halcrow goto out; 746237fead6SMichael Halcrow } 7475dda6992SMichael Halcrow rc = ecryptfs_prepare_write_no_truncate(file, tmp_page, start, 7485dda6992SMichael Halcrow (start + num_zeros)); 7495dda6992SMichael Halcrow if (rc) { 750237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error preparing to write zero's " 75153a2731fSMichael Halcrow "to page at index [0x%.16x]\n", 752237fead6SMichael Halcrow index); 753237fead6SMichael Halcrow page_cache_release(tmp_page); 754237fead6SMichael Halcrow goto out; 755237fead6SMichael Halcrow } 756c9f2875bSNate Diller zero_user_page(tmp_page, start, num_zeros, KM_USER0); 757237fead6SMichael Halcrow rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros); 758237fead6SMichael Halcrow if (rc < 0) { 759237fead6SMichael Halcrow ecryptfs_printk(KERN_ERR, "Error attempting to write zero's " 760237fead6SMichael Halcrow "to remainder of page at index [0x%.16x]\n", 761237fead6SMichael Halcrow index); 762237fead6SMichael Halcrow page_cache_release(tmp_page); 763237fead6SMichael Halcrow goto out; 764237fead6SMichael Halcrow } 765237fead6SMichael Halcrow rc = 0; 766237fead6SMichael Halcrow page_cache_release(tmp_page); 767237fead6SMichael Halcrow out: 768237fead6SMichael Halcrow return rc; 769237fead6SMichael Halcrow } 770237fead6SMichael Halcrow 771237fead6SMichael Halcrow static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block) 772237fead6SMichael Halcrow { 773237fead6SMichael Halcrow int rc = 0; 774237fead6SMichael Halcrow struct inode *inode; 775237fead6SMichael Halcrow struct inode *lower_inode; 776237fead6SMichael Halcrow 777237fead6SMichael Halcrow inode = (struct inode *)mapping->host; 778237fead6SMichael Halcrow lower_inode = ecryptfs_inode_to_lower(inode); 779237fead6SMichael Halcrow if (lower_inode->i_mapping->a_ops->bmap) 780237fead6SMichael Halcrow rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping, 781237fead6SMichael Halcrow block); 782237fead6SMichael Halcrow return rc; 783237fead6SMichael Halcrow } 784237fead6SMichael Halcrow 785237fead6SMichael Halcrow struct address_space_operations ecryptfs_aops = { 786237fead6SMichael Halcrow .writepage = ecryptfs_writepage, 787237fead6SMichael Halcrow .readpage = ecryptfs_readpage, 788237fead6SMichael Halcrow .prepare_write = ecryptfs_prepare_write, 789237fead6SMichael Halcrow .commit_write = ecryptfs_commit_write, 790237fead6SMichael Halcrow .bmap = ecryptfs_bmap, 791237fead6SMichael Halcrow }; 792