Cc: Linux Filesystems <linux-fsdevel@vger.kernel.org> Cc: [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Signed-off-by: Nick Piggin <[EMAIL PROTECTED]>
fs/ecryptfs/crypto.c | 32 +++--- fs/ecryptfs/ecryptfs_kernel.h | 4 fs/ecryptfs/mmap.c | 213 +++++++++++++++++++----------------------- 3 files changed, 119 insertions(+), 130 deletions(-) Index: linux-2.6/fs/ecryptfs/mmap.c =================================================================== --- linux-2.6.orig/fs/ecryptfs/mmap.c +++ linux-2.6/fs/ecryptfs/mmap.c @@ -36,26 +36,6 @@ struct kmem_cache *ecryptfs_lower_page_cache; -/** - * ecryptfs_get1page - * - * Get one page from cache or lower f/s, return error otherwise. - * - * Returns unlocked and up-to-date page (if ok), with increased - * refcnt. - */ -static struct page *ecryptfs_get1page(struct file *file, int index) -{ - struct dentry *dentry; - struct inode *inode; - struct address_space *mapping; - - dentry = file->f_path.dentry; - inode = dentry->d_inode; - mapping = inode->i_mapping; - return read_mapping_page(mapping, index, (void *)file); -} - static int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros); @@ -360,17 +340,14 @@ out: /** * Called with lower inode mutex held. */ -static int fill_zeros_to_end_of_page(struct page *page, unsigned int to) +static int fill_zeros_to_end_of_page(struct page *page, loff_t new_isize) { - struct inode *inode = page->mapping->host; int end_byte_in_page; char *page_virt; - if ((i_size_read(inode) / PAGE_CACHE_SIZE) != page->index) + if ((new_isize >> PAGE_CACHE_SHIFT) != 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; + end_byte_in_page = new_isize % PAGE_CACHE_SIZE; page_virt = kmap_atomic(page, KM_USER0); memset((page_virt + end_byte_in_page), 0, (PAGE_CACHE_SIZE - end_byte_in_page)); @@ -380,16 +357,35 @@ out: return 0; } -static int ecryptfs_prepare_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int ecryptfs_write_begin(struct file *file,struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) { + struct page *page; + pgoff_t index; int rc = 0; - if (from == 0 && to == PAGE_CACHE_SIZE) - goto out; /* If we are writing a full page, it will be - up to date. */ - if (!PageUptodate(page)) - rc = ecryptfs_do_readpage(file, page, page->index); + index = pos >> PAGE_CACHE_SHIFT; + page = __grab_cache_page(mapping, index); + if (!page) { + rc = -ENOMEM; + goto out; + } + + /* + * If we are writing a full page (with no possibility of a short + * write), it will be guaranteed to end up being uptodate at + * write_end-time + */ + if (flags & AOP_FLAG_UNINTERRUPTIBLE && len == PAGE_CACHE_SIZE) + goto out; + if (!PageUptodate(page)) { + rc = ecryptfs_do_readpage(file, page, index); + if (rc) { + unlock_page(page); + page_cache_release(page); + } + } out: return rc; } @@ -412,12 +408,6 @@ out: return rc; } -static void ecryptfs_release_lower_page(struct page *lower_page) -{ - unlock_page(lower_page); - page_cache_release(lower_page); -} - /** * ecryptfs_write_inode_size_to_header * @@ -431,23 +421,17 @@ static int ecryptfs_write_inode_size_to_ { int rc = 0; struct page *header_page; + void *fsdata; char *header_virt; - const struct address_space_operations *lower_a_ops; + struct address_space *lower_mapping = lower_inode->i_mapping; u64 file_size; - header_page = grab_cache_page(lower_inode->i_mapping, 0); - if (!header_page) { - ecryptfs_printk(KERN_ERR, "grab_cache_page for " - "lower_page_index 0 failed\n"); - rc = -EINVAL; - goto out; - } - lower_a_ops = lower_inode->i_mapping->a_ops; - rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8); - if (rc) { - ecryptfs_release_lower_page(header_page); + rc = pagecache_write_begin(lower_file, lower_mapping, 0, sizeof(u64), + AOP_FLAG_UNINTERRUPTIBLE, + &header_page, &fsdata); + if (rc) goto out; - } + file_size = (u64)i_size_read(inode); ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size); file_size = cpu_to_be64(file_size); @@ -455,13 +439,17 @@ static int ecryptfs_write_inode_size_to_ memcpy(header_virt, &file_size, sizeof(u64)); kunmap_atomic(header_virt, KM_USER0); flush_dcache_page(header_page); - rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8); - if (rc < 0) + + rc = pagecache_write_end(lower_file, lower_mapping, 0, sizeof(u64), + sizeof(u64), header_page, fsdata); + if (rc != sizeof(u64)) { ecryptfs_printk(KERN_ERR, "Error commiting header page " "write\n"); - ecryptfs_release_lower_page(header_page); + if (rc > 0) + rc = -EINVAL; /* XXX: can we do better? */ + } lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; - mark_inode_dirty_sync(inode); + mark_inode_dirty_sync(inode); /* XXX: lower_inode? */ out: return rc; } @@ -544,31 +532,21 @@ ecryptfs_write_inode_size_to_metadata(st int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, struct file *lower_file, unsigned long lower_page_index, int byte_offset, - int region_bytes) + int region_bytes, void **fsdata) { - int rc = 0; + int rc; + struct address_space *lower_mapping = lower_inode->i_mapping; + loff_t pos = (lower_page_index << PAGE_CACHE_SHIFT) + byte_offset; -retry: - *lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index); - if (!(*lower_page)) { - rc = -EINVAL; - ecryptfs_printk(KERN_ERR, "Error attempting to grab " - "lower page with index [0x%.16x]\n", - lower_page_index); - goto out; - } - rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file, - (*lower_page), - byte_offset, - region_bytes); + rc = pagecache_write_begin(lower_file, lower_mapping, pos, region_bytes, + AOP_FLAG_UNINTERRUPTIBLE, /* XXX: ok? */ + lower_page, fsdata); if (rc) { - ecryptfs_printk(KERN_ERR, "prepare_write for " + ecryptfs_printk(KERN_ERR, "pagecache_write_begin for " "lower_page_index = [0x%.16x] failed; rc = " "[%d]\n", lower_page_index, rc); - ecryptfs_release_lower_page(*lower_page); (*lower_page) = NULL; } -out: return rc; } @@ -580,18 +558,21 @@ out: int ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, struct file *lower_file, int byte_offset, - int region_size) + int region_size, void *fsdata) { - int rc = 0; + int rc; + struct address_space *lower_mapping = lower_inode->i_mapping; + loff_t pos = (lower_page->index << PAGE_CACHE_SHIFT) + byte_offset; - rc = lower_inode->i_mapping->a_ops->commit_write( - lower_file, lower_page, byte_offset, region_size); - if (rc < 0) { + rc = pagecache_write_end(lower_file, lower_mapping, pos, region_size, + region_size, lower_page, fsdata); + if (rc != region_size) { ecryptfs_printk(KERN_ERR, "Error committing write; rc = [%d]\n", rc); + if (rc > 0) + rc = -EINVAL; } else rc = 0; - ecryptfs_release_lower_page(lower_page); return rc; } @@ -606,9 +587,10 @@ int ecryptfs_copy_page_to_lower(struct p { int rc = 0; struct page *lower_page; + void *fsdata; rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file, - page->index, 0, PAGE_CACHE_SIZE); + page->index, 0, PAGE_CACHE_SIZE, &fsdata); if (rc) { ecryptfs_printk(KERN_ERR, "Error attempting to get page " "at index [0x%.16x]\n", page->index); @@ -618,7 +600,7 @@ int ecryptfs_copy_page_to_lower(struct p memcpy((char *)page_address(lower_page), page_address(page), PAGE_CACHE_SIZE); rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file, - 0, PAGE_CACHE_SIZE); + 0, PAGE_CACHE_SIZE, fsdata); if (rc) ecryptfs_printk(KERN_ERR, "Error attempting to commit page " "at index [0x%.16x]\n", page->index); @@ -629,31 +611,37 @@ out: struct kmem_cache *ecryptfs_xattr_cache; /** - * ecryptfs_commit_write + * ecryptfs_write_end * @file: The eCryptfs file object - * @page: The eCryptfs page - * @from: Ignored (we rotate the page IV on each write) - * @to: Ignored + * @mapping: The eCryptfs address_space + * @pos: The start of the write + * @len: The length passed to write_begin (unused) + * @copied: The actual amount copied + * @page: The eCryptfs page returned by write_begin + * @fsdata: Filesystem private data (unused) * * 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. */ -static int ecryptfs_commit_write(struct file *file, struct page *page, - unsigned from, unsigned to) +static int ecryptfs_write_end(struct file *file, + struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) { struct ecryptfs_page_crypt_context ctx; - loff_t pos; + loff_t isize; struct inode *inode; struct inode *lower_inode; struct file *lower_file; struct ecryptfs_crypt_stat *crypt_stat; int rc; - inode = page->mapping->host; + inode = mapping->host; + isize = inode->i_size; /* i_mutex is held */ lower_inode = ecryptfs_inode_to_lower(inode); lower_file = ecryptfs_file_to_lower(file); - mutex_lock(&lower_inode->i_mutex); + mutex_lock(&lower_inode->i_mutex); /* XXX: put this in write_begin? */ crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode) ->crypt_stat; if (crypt_stat->flags & ECRYPTFS_NEW_FILE) { @@ -664,8 +652,8 @@ static int ecryptfs_commit_write(struct ecryptfs_printk(KERN_DEBUG, "Not a new file\n"); ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" "(page w/ index = [0x%.16x], to = [%d])\n", page->index, - to); - rc = fill_zeros_to_end_of_page(page, to); + max(isize, pos+copied)); + rc = fill_zeros_to_end_of_page(page, max(isize, pos+copied)); if (rc) { ecryptfs_printk(KERN_WARNING, "Error attempting to fill " "zeros in page with index = [0x%.16x]\n", @@ -682,11 +670,10 @@ static int ecryptfs_commit_write(struct goto out; } inode->i_blocks = lower_inode->i_blocks; - pos = (page->index << PAGE_CACHE_SHIFT) + to; - if (pos > i_size_read(inode)) { - i_size_write(inode, pos); + if (pos + copied > isize) { + i_size_write(inode, pos + copied); ecryptfs_printk(KERN_DEBUG, "Expanded file size to " - "[0x%.16x]\n", i_size_read(inode)); + "[0x%.16x]\n", pos + copied); } rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode, inode, file->f_dentry, @@ -702,6 +689,9 @@ out: else SetPageUptodate(page); mutex_unlock(&lower_inode->i_mutex); + unlock_page(page); + page_cache_release(page); + return rc; } @@ -722,32 +712,31 @@ int write_zeros(struct file *file, pgoff int rc = 0; struct page *tmp_page; char *tmp_page_virt; - - tmp_page = ecryptfs_get1page(file, index); - if (IS_ERR(tmp_page)) { - ecryptfs_printk(KERN_ERR, "Error getting page at index " - "[0x%.16x]\n", index); - rc = PTR_ERR(tmp_page); - goto out; - } - rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros); + void *fsdata; + struct address_space *mapping = file->f_path.dentry->d_inode->i_mapping; + loff_t pos = (index << PAGE_CACHE_SHIFT) + start; + + rc = pagecache_write_begin(file, mapping, pos, num_zeros, + AOP_FLAG_UNINTERRUPTIBLE, + &tmp_page, &fsdata); if (rc) { ecryptfs_printk(KERN_ERR, "Error preparing to write zero's " "to remainder of page at index [0x%.16x]\n", index); - page_cache_release(tmp_page); goto out; } tmp_page_virt = kmap_atomic(tmp_page, KM_USER0); memset(((char *)tmp_page_virt + start), 0, num_zeros); kunmap_atomic(tmp_page_virt, KM_USER0); flush_dcache_page(tmp_page); - rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros); - if (rc < 0) { + rc = pagecache_write_end(file, mapping, pos, num_zeros, num_zeros, + tmp_page, fsdata); + if (rc != num_zeros) { ecryptfs_printk(KERN_ERR, "Error attempting to write zero's " "to remainder of page at index [0x%.16x]\n", index); - page_cache_release(tmp_page); + if (rc > 0) + rc = -EINVAL; goto out; } rc = 0; @@ -795,8 +784,8 @@ static void ecryptfs_sync_page(struct pa struct address_space_operations ecryptfs_aops = { .writepage = ecryptfs_writepage, .readpage = ecryptfs_readpage, - .prepare_write = ecryptfs_prepare_write, - .commit_write = ecryptfs_commit_write, + .write_begin = ecryptfs_write_begin, + .write_end = ecryptfs_write_end, .bmap = ecryptfs_bmap, .sync_page = ecryptfs_sync_page, }; Index: linux-2.6/fs/ecryptfs/crypto.c =================================================================== --- linux-2.6.orig/fs/ecryptfs/crypto.c +++ linux-2.6/fs/ecryptfs/crypto.c @@ -375,7 +375,8 @@ ecryptfs_extent_to_lwr_pg_idx_and_offset static int ecryptfs_write_out_page(struct ecryptfs_page_crypt_context *ctx, struct page *lower_page, struct inode *lower_inode, - int byte_offset_in_page, int bytes_to_write) + int byte_offset_in_page, int bytes_to_write, + void *fsdata) { int rc = 0; @@ -383,7 +384,7 @@ static int ecryptfs_write_out_page(struc rc = ecryptfs_commit_lower_page(lower_page, lower_inode, ctx->param.lower_file, byte_offset_in_page, - bytes_to_write); + bytes_to_write, fsdata); if (rc) { ecryptfs_printk(KERN_ERR, "Error calling lower " "commit; rc = [%d]\n", rc); @@ -407,7 +408,7 @@ static int ecryptfs_read_in_page(struct struct page **lower_page, struct inode *lower_inode, unsigned long lower_page_idx, - int byte_offset_in_page) + int byte_offset_in_page, void **fsdata) { int rc = 0; @@ -419,13 +420,12 @@ static int ecryptfs_read_in_page(struct lower_page_idx, byte_offset_in_page, (PAGE_CACHE_SIZE - - byte_offset_in_page)); + - byte_offset_in_page), fsdata); if (rc) { ecryptfs_printk( - KERN_ERR, "Error attempting to grab, map, " - "and prepare_write lower page with index " + KERN_ERR, "Error in ecryptfs_get_lower_page " + "lower page with index " "[0x%.16x]; rc = [%d]\n", lower_page_idx, rc); - goto out; } } else { *lower_page = grab_cache_page(lower_inode->i_mapping, @@ -436,10 +436,9 @@ static int ecryptfs_read_in_page(struct KERN_ERR, "Error attempting to grab and map " "lower page with index [0x%.16x]; rc = [%d]\n", lower_page_idx, rc); - goto out; } } -out: + return rc; } @@ -475,6 +474,8 @@ int ecryptfs_encrypt_page(struct ecryptf int lower_byte_offset = 0; int orig_byte_offset = 0; int num_extents_per_page; + void *fsdata; + #define ECRYPTFS_PAGE_STATE_UNREAD 0 #define ECRYPTFS_PAGE_STATE_READ 1 #define ECRYPTFS_PAGE_STATE_MODIFIED 2 @@ -503,10 +504,9 @@ int ecryptfs_encrypt_page(struct ecryptf if (prior_lower_page_idx != lower_page_idx && page_state == ECRYPTFS_PAGE_STATE_MODIFIED) { rc = ecryptfs_write_out_page(ctx, lower_page, - lower_inode, - orig_byte_offset, - (PAGE_CACHE_SIZE - - orig_byte_offset)); + lower_inode, orig_byte_offset, + (PAGE_CACHE_SIZE - orig_byte_offset), + fsdata); if (rc) { ecryptfs_printk(KERN_ERR, "Error attempting " "to write out page; rc = [%d]" @@ -519,7 +519,7 @@ int ecryptfs_encrypt_page(struct ecryptf || page_state == ECRYPTFS_PAGE_STATE_WRITTEN) { rc = ecryptfs_read_in_page(ctx, &lower_page, lower_inode, lower_page_idx, - lower_byte_offset); + lower_byte_offset, &fsdata); if (rc) { ecryptfs_printk(KERN_ERR, "Error attempting " "to read in lower page with " @@ -571,8 +571,8 @@ int ecryptfs_encrypt_page(struct ecryptf } BUG_ON(orig_byte_offset != 0); rc = ecryptfs_write_out_page(ctx, lower_page, lower_inode, 0, - (lower_byte_offset - + crypt_stat->extent_size)); + (lower_byte_offset + crypt_stat->extent_size), + fsdata); if (rc) { ecryptfs_printk(KERN_ERR, "Error attempting to write out " "page; rc = [%d]\n", rc); Index: linux-2.6/fs/ecryptfs/ecryptfs_kernel.h =================================================================== --- linux-2.6.orig/fs/ecryptfs/ecryptfs_kernel.h +++ linux-2.6/fs/ecryptfs/ecryptfs_kernel.h @@ -503,11 +503,11 @@ int ecryptfs_write_inode_size_to_metadat int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, struct file *lower_file, unsigned long lower_page_index, int byte_offset, - int region_bytes); + int region_bytes, void **fsdata); int ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, struct file *lower_file, int byte_offset, - int region_size); + int region_size, void *fsdata); int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode, struct file *lower_file); int ecryptfs_do_readpage(struct file *file, struct page *page, -- - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html