summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2019-05-20 12:29:47 -0400
committerEric Biggers <ebiggers@google.com>2019-05-28 13:27:53 -0400
commitaa8bc1ac6ef32a332671ca25e06cfd277a3839a5 (patch)
tree40a7109717078adacb8bed18199f35fb706f36f3
parent41adbcb7267b0060682576d523956160b5c617bd (diff)
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: Chandan Rajendra <chandan@linux.ibm.com> Signed-off-by: Eric Biggers <ebiggers@google.com>
-rw-r--r--fs/crypto/bio.c3
-rw-r--r--fs/crypto/crypto.c46
-rw-r--r--fs/ext4/inode.c7
-rw-r--r--include/linux/fscrypt.h12
4 files changed, 42 insertions, 26 deletions
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index f9111ffa12ff..61da06fda45c 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -33,8 +33,7 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
33 33
34 bio_for_each_segment_all(bv, bio, iter_all) { 34 bio_for_each_segment_all(bv, bio, iter_all) {
35 struct page *page = bv->bv_page; 35 struct page *page = bv->bv_page;
36 int ret = fscrypt_decrypt_page(page->mapping->host, page, 36 int ret = fscrypt_decrypt_pagecache_blocks(page, PAGE_SIZE, 0);
37 PAGE_SIZE, 0, page->index);
38 37
39 if (ret) 38 if (ret)
40 SetPageError(page); 39 SetPageError(page);
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index f82c45ac285a..45c3d0427fb2 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -283,29 +283,47 @@ int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
283EXPORT_SYMBOL(fscrypt_encrypt_block_inplace); 283EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
284 284
285/** 285/**
286 * fscrypt_decrypt_page() - Decrypts a page in-place 286 * fscrypt_decrypt_pagecache_blocks() - Decrypt filesystem blocks in a pagecache page
287 * @inode: The corresponding inode for the page to decrypt. 287 * @page: The locked pagecache page containing the block(s) to decrypt
288 * @page: The page to decrypt. Must be locked. 288 * @len: Total size of the block(s) to decrypt. Must be a nonzero
289 * @len: Number of bytes in @page to be decrypted. 289 * multiple of the filesystem's block size.
290 * @offs: Start of data in @page. 290 * @offs: Byte offset within @page of the first block to decrypt. Must be
291 * @lblk_num: Logical block number. 291 * a multiple of the filesystem's block size.
292 * 292 *
293 * Decrypts page in-place using the ctx encryption context. 293 * The specified block(s) are decrypted in-place within the pagecache page,
294 * which must still be locked and not uptodate. Normally, blocksize ==
295 * PAGE_SIZE and the whole page is decrypted at once.
294 * 296 *
295 * Called from the read completion callback. 297 * This is for use by the filesystem's ->readpages() method.
296 * 298 *
297 * Return: Zero on success, non-zero otherwise. 299 * Return: 0 on success; -errno on failure
298 */ 300 */
299int fscrypt_decrypt_page(const struct inode *inode, struct page *page, 301int fscrypt_decrypt_pagecache_blocks(struct page *page, unsigned int len,
300 unsigned int len, unsigned int offs, u64 lblk_num) 302 unsigned int offs)
301{ 303{
304 const struct inode *inode = page->mapping->host;
305 const unsigned int blockbits = inode->i_blkbits;
306 const unsigned int blocksize = 1 << blockbits;
307 u64 lblk_num = ((u64)page->index << (PAGE_SHIFT - blockbits)) +
308 (offs >> blockbits);
309 unsigned int i;
310 int err;
311
302 if (WARN_ON_ONCE(!PageLocked(page))) 312 if (WARN_ON_ONCE(!PageLocked(page)))
303 return -EINVAL; 313 return -EINVAL;
304 314
305 return fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page, page, 315 if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, blocksize)))
306 len, offs, GFP_NOFS); 316 return -EINVAL;
317
318 for (i = offs; i < offs + len; i += blocksize, lblk_num++) {
319 err = fscrypt_crypt_block(inode, FS_DECRYPT, lblk_num, page,
320 page, blocksize, i, GFP_NOFS);
321 if (err)
322 return err;
323 }
324 return 0;
307} 325}
308EXPORT_SYMBOL(fscrypt_decrypt_page); 326EXPORT_SYMBOL(fscrypt_decrypt_pagecache_blocks);
309 327
310/** 328/**
311 * fscrypt_decrypt_block_inplace() - Decrypt a filesystem block in-place 329 * fscrypt_decrypt_block_inplace() - Decrypt a filesystem block in-place
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c7f77c643008..8bfd8941f5ff 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1232,8 +1232,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len,
1232 if (unlikely(err)) 1232 if (unlikely(err))
1233 page_zero_new_buffers(page, from, to); 1233 page_zero_new_buffers(page, from, to);
1234 else if (decrypt) 1234 else if (decrypt)
1235 err = fscrypt_decrypt_page(page->mapping->host, page, 1235 err = fscrypt_decrypt_pagecache_blocks(page, PAGE_SIZE, 0);
1236 PAGE_SIZE, 0, page->index);
1237 return err; 1236 return err;
1238} 1237}
1239#endif 1238#endif
@@ -4066,8 +4065,8 @@ static int __ext4_block_zero_page_range(handle_t *handle,
4066 /* We expect the key to be set. */ 4065 /* We expect the key to be set. */
4067 BUG_ON(!fscrypt_has_encryption_key(inode)); 4066 BUG_ON(!fscrypt_has_encryption_key(inode));
4068 BUG_ON(blocksize != PAGE_SIZE); 4067 BUG_ON(blocksize != PAGE_SIZE);
4069 WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host, 4068 WARN_ON_ONCE(fscrypt_decrypt_pagecache_blocks(
4070 page, PAGE_SIZE, 0, page->index)); 4069 page, PAGE_SIZE, 0));
4071 } 4070 }
4072 } 4071 }
4073 if (ext4_should_journal_data(inode)) { 4072 if (ext4_should_journal_data(inode)) {
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 315affc99b05..bd8f207a2fb6 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -112,8 +112,9 @@ extern int fscrypt_encrypt_block_inplace(const struct inode *inode,
112 struct page *page, unsigned int len, 112 struct page *page, unsigned int len,
113 unsigned int offs, u64 lblk_num, 113 unsigned int offs, u64 lblk_num,
114 gfp_t gfp_flags); 114 gfp_t gfp_flags);
115extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, 115
116 unsigned int, u64); 116extern int fscrypt_decrypt_pagecache_blocks(struct page *page, unsigned int len,
117 unsigned int offs);
117extern int fscrypt_decrypt_block_inplace(const struct inode *inode, 118extern int fscrypt_decrypt_block_inplace(const struct inode *inode,
118 struct page *page, unsigned int len, 119 struct page *page, unsigned int len,
119 unsigned int offs, u64 lblk_num); 120 unsigned int offs, u64 lblk_num);
@@ -310,10 +311,9 @@ static inline int fscrypt_encrypt_block_inplace(const struct inode *inode,
310 return -EOPNOTSUPP; 311 return -EOPNOTSUPP;
311} 312}
312 313
313static inline int fscrypt_decrypt_page(const struct inode *inode, 314static inline int fscrypt_decrypt_pagecache_blocks(struct page *page,
314 struct page *page, 315 unsigned int len,
315 unsigned int len, unsigned int offs, 316 unsigned int offs)
316 u64 lblk_num)
317{ 317{
318 return -EOPNOTSUPP; 318 return -EOPNOTSUPP;
319} 319}