Commit aa8bc1ac authored by Eric Biggers's avatar Eric Biggers

fscrypt: support decrypting multiple filesystem blocks per page

Rename fscrypt_decrypt_page() to fscrypt_decrypt_pagecache_blocks() and
redefine its behavior to decrypt all filesystem blocks in the given
region of the given page, rather than assuming that the region consists
of just one filesystem block.  Also remove the 'inode' and 'lblk_num'
parameters, since they can be retrieved from the page as it's already
assumed to be a pagecache page.

This is in preparation for allowing encryption on ext4 filesystems with
blocksize != PAGE_SIZE.

This is based on work by Chandan Rajendra.
Reviewed-by: default avatarChandan Rajendra <chandan@linux.ibm.com>
Signed-off-by: default avatarEric Biggers <ebiggers@google.com>
parent 41adbcb7
...@@ -33,8 +33,7 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) ...@@ -33,8 +33,7 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
bio_for_each_segment_all(bv, bio, iter_all) { bio_for_each_segment_all(bv, bio, iter_all) {
struct page *page = bv->bv_page; struct page *page = bv->bv_page;
int ret = fscrypt_decrypt_page(page->mapping->host, page, int ret = fscrypt_decrypt_pagecache_blocks(page, PAGE_SIZE, 0);
PAGE_SIZE, 0, page->index);
if (ret) if (ret)
SetPageError(page); SetPageError(page);
......
...@@ -283,29 +283,47 @@ int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page, ...@@ -283,29 +283,47 @@ int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
EXPORT_SYMBOL(fscrypt_encrypt_block_inplace); EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
/** /**
* fscrypt_decrypt_page() - Decrypts a page in-place * fscrypt_decrypt_pagecache_blocks() - Decrypt filesystem blocks in a pagecache page
* @inode: The corresponding inode for the page to decrypt. * @page: The locked pagecache page containing the block(s) to decrypt
* @page: The page to decrypt. Must be locked. * @len: Total size of the block(s) to decrypt. Must be a nonzero
* @len: Number of bytes in @page to be decrypted. * multiple of the filesystem's block size.
* @offs: Start of data in @page. * @offs: Byte offset within @page of the first block to decrypt. Must be
* @lblk_num: Logical block number. * a multiple of the filesystem's block size.
* *
* Decrypts page in-place using the ctx encryption context. * The specified block(s) are decrypted in-place within the pagecache page,
* which must still be locked and not uptodate. Normally, blocksize ==
* PAGE_SIZE and the whole page is decrypted at once.
* *
* Called from the read completion callback. * This is for use by the filesystem's ->readpages() method.
* *
* Return: Zero on success, non-zero otherwise. * Return: 0 on success; -errno on failure
*/ */
int fscrypt_decrypt_page(const struct inode *inode, struct page *page, int fscrypt_decrypt_pagecache_blocks(struct page *page, unsigned int len,
unsigned int len, unsigned int offs, u64 lblk_num) unsigned int offs)
{ {
const struct inode *inode = page->mapping->host;
const unsigned int blockbits = inode->i_blkbits;
const unsigned int blocksize = 1 << blockbits;
u64 lblk_num = ((u64)page->index << (PAGE_SHIFT - blockbits)) +
(offs >> blockbits);
unsigned int i;
int err;
if (WARN_ON_ONCE(!PageLocked(page))) if (WARN_ON_ONCE(!PageLocked(page)))
return -EINVAL; return -EINVAL;
return fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page, page, if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, blocksize)))
len, offs, GFP_NOFS); return -EINVAL;
for (i = offs; i < offs + len; i += blocksize, lblk_num++) {
err = fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page,
page, blocksize, i, GFP_NOFS);
if (err)
return err;
}
return 0;
} }
EXPORT_SYMBOL(fscrypt_decrypt_page); EXPORT_SYMBOL(fscrypt_decrypt_pagecache_blocks);
/** /**
* fscrypt_decrypt_block_inplace() - Decrypt a filesystem block in-place * fscrypt_decrypt_block_inplace() - Decrypt a filesystem block in-place
......
...@@ -1232,8 +1232,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, ...@@ -1232,8 +1232,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len,
if (unlikely(err)) if (unlikely(err))
page_zero_new_buffers(page, from, to); page_zero_new_buffers(page, from, to);
else if (decrypt) else if (decrypt)
err = fscrypt_decrypt_page(page->mapping->host, page, err = fscrypt_decrypt_pagecache_blocks(page, PAGE_SIZE, 0);
PAGE_SIZE, 0, page->index);
return err; return err;
} }
#endif #endif
...@@ -4066,8 +4065,8 @@ static int __ext4_block_zero_page_range(handle_t *handle, ...@@ -4066,8 +4065,8 @@ static int __ext4_block_zero_page_range(handle_t *handle,
/* We expect the key to be set. */ /* We expect the key to be set. */
BUG_ON(!fscrypt_has_encryption_key(inode)); BUG_ON(!fscrypt_has_encryption_key(inode));
BUG_ON(blocksize != PAGE_SIZE); BUG_ON(blocksize != PAGE_SIZE);
WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host, WARN_ON_ONCE(fscrypt_decrypt_pagecache_blocks(
page, PAGE_SIZE, 0, page->index)); page, PAGE_SIZE, 0));
} }
} }
if (ext4_should_journal_data(inode)) { if (ext4_should_journal_data(inode)) {
......
...@@ -112,8 +112,9 @@ extern int fscrypt_encrypt_block_inplace(const struct inode *inode, ...@@ -112,8 +112,9 @@ extern int fscrypt_encrypt_block_inplace(const struct inode *inode,
struct page *page, unsigned int len, struct page *page, unsigned int len,
unsigned int offs, u64 lblk_num, unsigned int offs, u64 lblk_num,
gfp_t gfp_flags); gfp_t gfp_flags);
extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
unsigned int, u64); extern int fscrypt_decrypt_pagecache_blocks(struct page *page, unsigned int len,
unsigned int offs);
extern int fscrypt_decrypt_block_inplace(const struct inode *inode, extern int fscrypt_decrypt_block_inplace(const struct inode *inode,
struct page *page, unsigned int len, struct page *page, unsigned int len,
unsigned int offs, u64 lblk_num); unsigned int offs, u64 lblk_num);
...@@ -310,10 +311,9 @@ static inline int fscrypt_encrypt_block_inplace(const struct inode *inode, ...@@ -310,10 +311,9 @@ static inline int fscrypt_encrypt_block_inplace(const struct inode *inode,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline int fscrypt_decrypt_page(const struct inode *inode, static inline int fscrypt_decrypt_pagecache_blocks(struct page *page,
struct page *page, unsigned int len,
unsigned int len, unsigned int offs, unsigned int offs)
u64 lblk_num)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment