fscrypt: introduce fscrypt_decrypt_block_inplace()

Currently fscrypt_decrypt_page() does one of two logically distinct
things depending on whether FS_CFLG_OWN_PAGES is set in the filesystem's
fscrypt_operations: decrypt a pagecache page in-place, or decrypt a
filesystem block in-place in any page.  Currently these happen to share
the same implementation, but this conflates the notion of blocks and
pages.  It also makes it so that all callers have to provide inode and
lblk_num, when fscrypt could determine these itself for pagecache pages.

Therefore, move the FS_CFLG_OWN_PAGES behavior into a new function
fscrypt_decrypt_block_inplace().  This mirrors
fscrypt_encrypt_block_inplace().

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

Reviewed-by: Chandan Rajendra <chandan@linux.ibm.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
Eric Biggers 2019-05-20 09:29:46 -07:00
parent 930d453995
commit 41adbcb726
3 changed files with 42 additions and 7 deletions

View File

@ -285,8 +285,7 @@ EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
/** /**
* fscrypt_decrypt_page() - Decrypts a page in-place * fscrypt_decrypt_page() - Decrypts a page in-place
* @inode: The corresponding inode for the page to decrypt. * @inode: The corresponding inode for the page to decrypt.
* @page: The page to decrypt. Must be locked in case * @page: The page to decrypt. Must be locked.
* it is a writeback page (FS_CFLG_OWN_PAGES unset).
* @len: Number of bytes in @page to be decrypted. * @len: Number of bytes in @page to be decrypted.
* @offs: Start of data in @page. * @offs: Start of data in @page.
* @lblk_num: Logical block number. * @lblk_num: Logical block number.
@ -300,8 +299,7 @@ EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
int fscrypt_decrypt_page(const struct inode *inode, struct page *page, int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs, u64 lblk_num) unsigned int len, unsigned int offs, u64 lblk_num)
{ {
if (WARN_ON_ONCE(!PageLocked(page) && if (WARN_ON_ONCE(!PageLocked(page)))
!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES)))
return -EINVAL; return -EINVAL;
return fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page, page, return fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page, page,
@ -309,6 +307,31 @@ int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
} }
EXPORT_SYMBOL(fscrypt_decrypt_page); EXPORT_SYMBOL(fscrypt_decrypt_page);
/**
* fscrypt_decrypt_block_inplace() - Decrypt a filesystem block in-place
* @inode: The inode to which this block belongs
* @page: The page containing the block to decrypt
* @len: Size of block to decrypt. Doesn't need to be a multiple of the
* fs block size, but must be a multiple of FS_CRYPTO_BLOCK_SIZE.
* @offs: Byte offset within @page at which the block to decrypt begins
* @lblk_num: Filesystem logical block number of the block, i.e. the 0-based
* number of the block within the file
*
* Decrypt a possibly-compressed filesystem block that is located in an
* arbitrary page, not necessarily in the original pagecache page. The @inode
* and @lblk_num must be specified, as they can't be determined from @page.
*
* Return: 0 on success; -errno on failure
*/
int fscrypt_decrypt_block_inplace(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs,
u64 lblk_num)
{
return fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page, page,
len, offs, GFP_NOFS);
}
EXPORT_SYMBOL(fscrypt_decrypt_block_inplace);
/* /*
* Validate dentries in encrypted directories to make sure we aren't potentially * Validate dentries in encrypted directories to make sure we aren't potentially
* caching stale dentries after a key has been added. * caching stale dentries after a key has been added.

View File

@ -64,10 +64,11 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
} }
ubifs_assert(c, dlen <= UBIFS_BLOCK_SIZE); ubifs_assert(c, dlen <= UBIFS_BLOCK_SIZE);
err = fscrypt_decrypt_page(inode, virt_to_page(&dn->data), dlen, err = fscrypt_decrypt_block_inplace(inode, virt_to_page(&dn->data),
offset_in_page(&dn->data), block); dlen, offset_in_page(&dn->data),
block);
if (err) { if (err) {
ubifs_err(c, "fscrypt_decrypt_page failed: %i", err); ubifs_err(c, "fscrypt_decrypt_block_inplace() failed: %d", err);
return err; return err;
} }
*out_len = clen; *out_len = clen;

View File

@ -114,6 +114,9 @@ extern int fscrypt_encrypt_block_inplace(const struct inode *inode,
gfp_t gfp_flags); gfp_t gfp_flags);
extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
unsigned int, u64); unsigned int, u64);
extern int fscrypt_decrypt_block_inplace(const struct inode *inode,
struct page *page, unsigned int len,
unsigned int offs, u64 lblk_num);
static inline bool fscrypt_is_bounce_page(struct page *page) static inline bool fscrypt_is_bounce_page(struct page *page)
{ {
@ -315,6 +318,14 @@ static inline int fscrypt_decrypt_page(const struct inode *inode,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline int fscrypt_decrypt_block_inplace(const struct inode *inode,
struct page *page,
unsigned int len,
unsigned int offs, u64 lblk_num)
{
return -EOPNOTSUPP;
}
static inline bool fscrypt_is_bounce_page(struct page *page) static inline bool fscrypt_is_bounce_page(struct page *page)
{ {
return false; return false;