diff options
author | Eric Biggers <ebiggers@google.com> | 2019-05-20 12:29:43 -0400 |
---|---|---|
committer | Eric Biggers <ebiggers@google.com> | 2019-05-28 13:27:52 -0400 |
commit | 03569f2fb8e734f281379767de674e23c38b0b14 (patch) | |
tree | 13c222b83eaf83f30c2ae175c9f539033bec44a7 | |
parent | eeacfdc68a104967162dfcba60f53f6f5b62a334 (diff) |
fscrypt: introduce fscrypt_encrypt_block_inplace()
fscrypt_encrypt_page() behaves very differently depending on whether the
filesystem set FS_CFLG_OWN_PAGES in its fscrypt_operations. This makes
the function difficult to understand and document. 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_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>
-rw-r--r-- | fs/crypto/crypto.c | 50 | ||||
-rw-r--r-- | fs/ubifs/crypto.c | 12 | ||||
-rw-r--r-- | include/linux/fscrypt.h | 13 |
3 files changed, 50 insertions, 25 deletions
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 59337287e580..2969a1dff10b 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c | |||
@@ -200,8 +200,7 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, | |||
200 | /** | 200 | /** |
201 | * fscypt_encrypt_page() - Encrypts a page | 201 | * fscypt_encrypt_page() - Encrypts a page |
202 | * @inode: The inode for which the encryption should take place | 202 | * @inode: The inode for which the encryption should take place |
203 | * @page: The page to encrypt. Must be locked for bounce-page | 203 | * @page: The page to encrypt. Must be locked. |
204 | * encryption. | ||
205 | * @len: Length of data to encrypt in @page and encrypted | 204 | * @len: Length of data to encrypt in @page and encrypted |
206 | * data in returned page. | 205 | * data in returned page. |
207 | * @offs: Offset of data within @page and returned | 206 | * @offs: Offset of data within @page and returned |
@@ -211,10 +210,9 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, | |||
211 | * previously written data. | 210 | * previously written data. |
212 | * @gfp_flags: The gfp flag for memory allocation | 211 | * @gfp_flags: The gfp flag for memory allocation |
213 | * | 212 | * |
214 | * Encrypts @page. If the filesystem set FS_CFLG_OWN_PAGES, then the data is | 213 | * Encrypts @page. A bounce page is allocated, the data is encrypted into the |
215 | * encrypted in-place and @page is returned. Else, a bounce page is allocated, | 214 | * bounce page, and the bounce page is returned. The caller is responsible for |
216 | * the data is encrypted into the bounce page, and the bounce page is returned. | 215 | * calling fscrypt_free_bounce_page(). |
217 | * The caller is responsible for calling fscrypt_free_bounce_page(). | ||
218 | * | 216 | * |
219 | * Return: A page containing the encrypted data on success, else an ERR_PTR() | 217 | * Return: A page containing the encrypted data on success, else an ERR_PTR() |
220 | */ | 218 | */ |
@@ -225,24 +223,12 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, | |||
225 | u64 lblk_num, gfp_t gfp_flags) | 223 | u64 lblk_num, gfp_t gfp_flags) |
226 | 224 | ||
227 | { | 225 | { |
228 | struct page *ciphertext_page = page; | 226 | struct page *ciphertext_page; |
229 | int err; | 227 | int err; |
230 | 228 | ||
231 | if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) { | ||
232 | /* with inplace-encryption we just encrypt the page */ | ||
233 | err = fscrypt_crypt_block(inode, FS_ENCRYPT, lblk_num, page, | ||
234 | ciphertext_page, len, offs, | ||
235 | gfp_flags); | ||
236 | if (err) | ||
237 | return ERR_PTR(err); | ||
238 | |||
239 | return ciphertext_page; | ||
240 | } | ||
241 | |||
242 | if (WARN_ON_ONCE(!PageLocked(page))) | 229 | if (WARN_ON_ONCE(!PageLocked(page))) |
243 | return ERR_PTR(-EINVAL); | 230 | return ERR_PTR(-EINVAL); |
244 | 231 | ||
245 | /* The encryption operation will require a bounce page. */ | ||
246 | ciphertext_page = fscrypt_alloc_bounce_page(gfp_flags); | 232 | ciphertext_page = fscrypt_alloc_bounce_page(gfp_flags); |
247 | if (!ciphertext_page) | 233 | if (!ciphertext_page) |
248 | return ERR_PTR(-ENOMEM); | 234 | return ERR_PTR(-ENOMEM); |
@@ -260,6 +246,32 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, | |||
260 | EXPORT_SYMBOL(fscrypt_encrypt_page); | 246 | EXPORT_SYMBOL(fscrypt_encrypt_page); |
261 | 247 | ||
262 | /** | 248 | /** |
249 | * fscrypt_encrypt_block_inplace() - Encrypt a filesystem block in-place | ||
250 | * @inode: The inode to which this block belongs | ||
251 | * @page: The page containing the block to encrypt | ||
252 | * @len: Size of block to encrypt. Doesn't need to be a multiple of the | ||
253 | * fs block size, but must be a multiple of FS_CRYPTO_BLOCK_SIZE. | ||
254 | * @offs: Byte offset within @page at which the block to encrypt begins | ||
255 | * @lblk_num: Filesystem logical block number of the block, i.e. the 0-based | ||
256 | * number of the block within the file | ||
257 | * @gfp_flags: Memory allocation flags | ||
258 | * | ||
259 | * Encrypt a possibly-compressed filesystem block that is located in an | ||
260 | * arbitrary page, not necessarily in the original pagecache page. The @inode | ||
261 | * and @lblk_num must be specified, as they can't be determined from @page. | ||
262 | * | ||
263 | * Return: 0 on success; -errno on failure | ||
264 | */ | ||
265 | int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page, | ||
266 | unsigned int len, unsigned int offs, | ||
267 | u64 lblk_num, gfp_t gfp_flags) | ||
268 | { | ||
269 | return fscrypt_crypt_block(inode, FS_ENCRYPT, lblk_num, page, page, | ||
270 | len, offs, gfp_flags); | ||
271 | } | ||
272 | EXPORT_SYMBOL(fscrypt_encrypt_block_inplace); | ||
273 | |||
274 | /** | ||
263 | * fscrypt_decrypt_page() - Decrypts a page in-place | 275 | * fscrypt_decrypt_page() - Decrypts a page in-place |
264 | * @inode: The corresponding inode for the page to decrypt. | 276 | * @inode: The corresponding inode for the page to decrypt. |
265 | * @page: The page to decrypt. Must be locked in case | 277 | * @page: The page to decrypt. Must be locked in case |
diff --git a/fs/ubifs/crypto.c b/fs/ubifs/crypto.c index 4aaedf2d7f44..032efdad2e66 100644 --- a/fs/ubifs/crypto.c +++ b/fs/ubifs/crypto.c | |||
@@ -29,8 +29,8 @@ int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn, | |||
29 | { | 29 | { |
30 | struct ubifs_info *c = inode->i_sb->s_fs_info; | 30 | struct ubifs_info *c = inode->i_sb->s_fs_info; |
31 | void *p = &dn->data; | 31 | void *p = &dn->data; |
32 | struct page *ret; | ||
33 | unsigned int pad_len = round_up(in_len, UBIFS_CIPHER_BLOCK_SIZE); | 32 | unsigned int pad_len = round_up(in_len, UBIFS_CIPHER_BLOCK_SIZE); |
33 | int err; | ||
34 | 34 | ||
35 | ubifs_assert(c, pad_len <= *out_len); | 35 | ubifs_assert(c, pad_len <= *out_len); |
36 | dn->compr_size = cpu_to_le16(in_len); | 36 | dn->compr_size = cpu_to_le16(in_len); |
@@ -39,11 +39,11 @@ int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn, | |||
39 | if (pad_len != in_len) | 39 | if (pad_len != in_len) |
40 | memset(p + in_len, 0, pad_len - in_len); | 40 | memset(p + in_len, 0, pad_len - in_len); |
41 | 41 | ||
42 | ret = fscrypt_encrypt_page(inode, virt_to_page(&dn->data), pad_len, | 42 | err = fscrypt_encrypt_block_inplace(inode, virt_to_page(p), pad_len, |
43 | offset_in_page(&dn->data), block, GFP_NOFS); | 43 | offset_in_page(p), block, GFP_NOFS); |
44 | if (IS_ERR(ret)) { | 44 | if (err) { |
45 | ubifs_err(c, "fscrypt_encrypt_page failed: %ld", PTR_ERR(ret)); | 45 | ubifs_err(c, "fscrypt_encrypt_block_inplace() failed: %d", err); |
46 | return PTR_ERR(ret); | 46 | return err; |
47 | } | 47 | } |
48 | *out_len = pad_len; | 48 | *out_len = pad_len; |
49 | 49 | ||
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 1c7287f146a9..a9b2d26e615d 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h | |||
@@ -106,6 +106,10 @@ extern void fscrypt_release_ctx(struct fscrypt_ctx *); | |||
106 | extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, | 106 | extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, |
107 | unsigned int, unsigned int, | 107 | unsigned int, unsigned int, |
108 | u64, gfp_t); | 108 | u64, gfp_t); |
109 | extern int fscrypt_encrypt_block_inplace(const struct inode *inode, | ||
110 | struct page *page, unsigned int len, | ||
111 | unsigned int offs, u64 lblk_num, | ||
112 | gfp_t gfp_flags); | ||
109 | extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, | 113 | extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, |
110 | unsigned int, u64); | 114 | unsigned int, u64); |
111 | 115 | ||
@@ -293,6 +297,15 @@ static inline struct page *fscrypt_encrypt_page(const struct inode *inode, | |||
293 | return ERR_PTR(-EOPNOTSUPP); | 297 | return ERR_PTR(-EOPNOTSUPP); |
294 | } | 298 | } |
295 | 299 | ||
300 | static inline int fscrypt_encrypt_block_inplace(const struct inode *inode, | ||
301 | struct page *page, | ||
302 | unsigned int len, | ||
303 | unsigned int offs, u64 lblk_num, | ||
304 | gfp_t gfp_flags) | ||
305 | { | ||
306 | return -EOPNOTSUPP; | ||
307 | } | ||
308 | |||
296 | static inline int fscrypt_decrypt_page(const struct inode *inode, | 309 | static inline int fscrypt_decrypt_page(const struct inode *inode, |
297 | struct page *page, | 310 | struct page *page, |
298 | unsigned int len, unsigned int offs, | 311 | unsigned int len, unsigned int offs, |