From 0b578f358a6a7afee2ddc48dd39c2972726187de Mon Sep 17 00:00:00 2001 From: Chandan Rajendra Date: Mon, 20 May 2019 09:29:50 -0700 Subject: [PATCH] ext4: decrypt only the needed blocks in ext4_block_write_begin() In ext4_block_write_begin(), only decrypt the blocks that actually need to be decrypted (up to two blocks which intersect the boundaries of the region that will be written to), rather than assuming blocksize == PAGE_SIZE and decrypting the whole page. This is in preparation for allowing encryption on ext4 filesystems with blocksize != PAGE_SIZE. Signed-off-by: Chandan Rajendra (EB: rebase onto previous changes, improve the commit message, and move the check for encrypted inode) Signed-off-by: Eric Biggers --- fs/ext4/inode.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 92776d0ff9b9..8e48feddad83 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1164,8 +1164,9 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, int err = 0; unsigned blocksize = inode->i_sb->s_blocksize; unsigned bbits; - struct buffer_head *bh, *head, *wait[2], **wait_bh = wait; - bool decrypt = false; + struct buffer_head *bh, *head, *wait[2]; + int nr_wait = 0; + int i; BUG_ON(!PageLocked(page)); BUG_ON(from > PAGE_SIZE); @@ -1217,24 +1218,30 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, !buffer_unwritten(bh) && (block_start < from || block_end > to)) { ll_rw_block(REQ_OP_READ, 0, 1, &bh); - *wait_bh++ = bh; - decrypt = IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode); + wait[nr_wait++] = bh; } } /* * If we issued read requests, let them complete. */ - while (wait_bh > wait) { - wait_on_buffer(*--wait_bh); - if (!buffer_uptodate(*wait_bh)) + for (i = 0; i < nr_wait; i++) { + wait_on_buffer(wait[i]); + if (!buffer_uptodate(wait[i])) err = -EIO; } if (unlikely(err)) { page_zero_new_buffers(page, from, to); - } else if (decrypt) { - err = fscrypt_decrypt_pagecache_blocks(page, PAGE_SIZE, 0); - if (err) - clear_buffer_uptodate(*wait_bh); + } else if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) { + for (i = 0; i < nr_wait; i++) { + int err2; + + err2 = fscrypt_decrypt_pagecache_blocks(page, blocksize, + bh_offset(wait[i])); + if (err2) { + clear_buffer_uptodate(wait[i]); + err = err2; + } + } } return err; -- 2.45.2