diff options
author | Michael Halcrow <mhalcrow@google.com> | 2015-04-12 00:55:10 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2015-04-12 00:55:10 -0400 |
commit | 2058f83a728adffbe00bded4f804b37a5ee58cbe (patch) | |
tree | e0bc1cf2aa8e3a36e9543567c5c248f785f88e2c /fs/ext4 | |
parent | dde680cefc842e58524772099a3b8219e5abf551 (diff) |
ext4 crypto: implement the ext4 encryption write path
Pulls block_write_begin() into fs/ext4/inode.c because it might need
to do a low-level read of the existing data, in which case we need to
decrypt it.
Signed-off-by: Michael Halcrow <mhalcrow@google.com>
Signed-off-by: Ildar Muslukhov <ildarm@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/extents.c | 17 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 5 | ||||
-rw-r--r-- | fs/ext4/inode.c | 112 | ||||
-rw-r--r-- | fs/ext4/page-io.c | 45 |
4 files changed, 173 insertions, 6 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 74580ea3ab55..973816bfe4a9 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -3122,6 +3122,9 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex) | |||
3122 | ee_len = ext4_ext_get_actual_len(ex); | 3122 | ee_len = ext4_ext_get_actual_len(ex); |
3123 | ee_pblock = ext4_ext_pblock(ex); | 3123 | ee_pblock = ext4_ext_pblock(ex); |
3124 | 3124 | ||
3125 | if (ext4_encrypted_inode(inode)) | ||
3126 | return ext4_encrypted_zeroout(inode, ex); | ||
3127 | |||
3125 | ret = sb_issue_zeroout(inode->i_sb, ee_pblock, ee_len, GFP_NOFS); | 3128 | ret = sb_issue_zeroout(inode->i_sb, ee_pblock, ee_len, GFP_NOFS); |
3126 | if (ret > 0) | 3129 | if (ret > 0) |
3127 | ret = 0; | 3130 | ret = 0; |
@@ -4898,6 +4901,20 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | |||
4898 | ext4_lblk_t lblk; | 4901 | ext4_lblk_t lblk; |
4899 | unsigned int blkbits = inode->i_blkbits; | 4902 | unsigned int blkbits = inode->i_blkbits; |
4900 | 4903 | ||
4904 | /* | ||
4905 | * Encrypted inodes can't handle collapse range or insert | ||
4906 | * range since we would need to re-encrypt blocks with a | ||
4907 | * different IV or XTS tweak (which are based on the logical | ||
4908 | * block number). | ||
4909 | * | ||
4910 | * XXX It's not clear why zero range isn't working, but we'll | ||
4911 | * leave it disabled for encrypted inodes for now. This is a | ||
4912 | * bug we should fix.... | ||
4913 | */ | ||
4914 | if (ext4_encrypted_inode(inode) && | ||
4915 | (mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE))) | ||
4916 | return -EOPNOTSUPP; | ||
4917 | |||
4901 | /* Return error if mode is not supported */ | 4918 | /* Return error if mode is not supported */ |
4902 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | | 4919 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | |
4903 | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) | 4920 | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 6ab6f639c70b..247737efd725 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -996,6 +996,11 @@ got: | |||
996 | ei->i_block_group = group; | 996 | ei->i_block_group = group; |
997 | ei->i_last_alloc_group = ~0; | 997 | ei->i_last_alloc_group = ~0; |
998 | 998 | ||
999 | /* If the directory encrypted, then we should encrypt the inode. */ | ||
1000 | if ((S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) && | ||
1001 | ext4_encrypted_inode(dir)) | ||
1002 | ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT); | ||
1003 | |||
999 | ext4_set_inode_flags(inode); | 1004 | ext4_set_inode_flags(inode); |
1000 | if (IS_DIRSYNC(inode)) | 1005 | if (IS_DIRSYNC(inode)) |
1001 | ext4_handle_sync(handle); | 1006 | ext4_handle_sync(handle); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index cd3009152ae2..7c4527e10ae4 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -886,6 +886,95 @@ int do_journal_get_write_access(handle_t *handle, | |||
886 | 886 | ||
887 | static int ext4_get_block_write_nolock(struct inode *inode, sector_t iblock, | 887 | static int ext4_get_block_write_nolock(struct inode *inode, sector_t iblock, |
888 | struct buffer_head *bh_result, int create); | 888 | struct buffer_head *bh_result, int create); |
889 | |||
890 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
891 | static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, | ||
892 | get_block_t *get_block) | ||
893 | { | ||
894 | unsigned from = pos & (PAGE_CACHE_SIZE - 1); | ||
895 | unsigned to = from + len; | ||
896 | struct inode *inode = page->mapping->host; | ||
897 | unsigned block_start, block_end; | ||
898 | sector_t block; | ||
899 | int err = 0; | ||
900 | unsigned blocksize = inode->i_sb->s_blocksize; | ||
901 | unsigned bbits; | ||
902 | struct buffer_head *bh, *head, *wait[2], **wait_bh = wait; | ||
903 | bool decrypt = false; | ||
904 | |||
905 | BUG_ON(!PageLocked(page)); | ||
906 | BUG_ON(from > PAGE_CACHE_SIZE); | ||
907 | BUG_ON(to > PAGE_CACHE_SIZE); | ||
908 | BUG_ON(from > to); | ||
909 | |||
910 | if (!page_has_buffers(page)) | ||
911 | create_empty_buffers(page, blocksize, 0); | ||
912 | head = page_buffers(page); | ||
913 | bbits = ilog2(blocksize); | ||
914 | block = (sector_t)page->index << (PAGE_CACHE_SHIFT - bbits); | ||
915 | |||
916 | for (bh = head, block_start = 0; bh != head || !block_start; | ||
917 | block++, block_start = block_end, bh = bh->b_this_page) { | ||
918 | block_end = block_start + blocksize; | ||
919 | if (block_end <= from || block_start >= to) { | ||
920 | if (PageUptodate(page)) { | ||
921 | if (!buffer_uptodate(bh)) | ||
922 | set_buffer_uptodate(bh); | ||
923 | } | ||
924 | continue; | ||
925 | } | ||
926 | if (buffer_new(bh)) | ||
927 | clear_buffer_new(bh); | ||
928 | if (!buffer_mapped(bh)) { | ||
929 | WARN_ON(bh->b_size != blocksize); | ||
930 | err = get_block(inode, block, bh, 1); | ||
931 | if (err) | ||
932 | break; | ||
933 | if (buffer_new(bh)) { | ||
934 | unmap_underlying_metadata(bh->b_bdev, | ||
935 | bh->b_blocknr); | ||
936 | if (PageUptodate(page)) { | ||
937 | clear_buffer_new(bh); | ||
938 | set_buffer_uptodate(bh); | ||
939 | mark_buffer_dirty(bh); | ||
940 | continue; | ||
941 | } | ||
942 | if (block_end > to || block_start < from) | ||
943 | zero_user_segments(page, to, block_end, | ||
944 | block_start, from); | ||
945 | continue; | ||
946 | } | ||
947 | } | ||
948 | if (PageUptodate(page)) { | ||
949 | if (!buffer_uptodate(bh)) | ||
950 | set_buffer_uptodate(bh); | ||
951 | continue; | ||
952 | } | ||
953 | if (!buffer_uptodate(bh) && !buffer_delay(bh) && | ||
954 | !buffer_unwritten(bh) && | ||
955 | (block_start < from || block_end > to)) { | ||
956 | ll_rw_block(READ, 1, &bh); | ||
957 | *wait_bh++ = bh; | ||
958 | decrypt = ext4_encrypted_inode(inode) && | ||
959 | S_ISREG(inode->i_mode); | ||
960 | } | ||
961 | } | ||
962 | /* | ||
963 | * If we issued read requests, let them complete. | ||
964 | */ | ||
965 | while (wait_bh > wait) { | ||
966 | wait_on_buffer(*--wait_bh); | ||
967 | if (!buffer_uptodate(*wait_bh)) | ||
968 | err = -EIO; | ||
969 | } | ||
970 | if (unlikely(err)) | ||
971 | page_zero_new_buffers(page, from, to); | ||
972 | else if (decrypt) | ||
973 | err = ext4_decrypt_one(inode, page); | ||
974 | return err; | ||
975 | } | ||
976 | #endif | ||
977 | |||
889 | static int ext4_write_begin(struct file *file, struct address_space *mapping, | 978 | static int ext4_write_begin(struct file *file, struct address_space *mapping, |
890 | loff_t pos, unsigned len, unsigned flags, | 979 | loff_t pos, unsigned len, unsigned flags, |
891 | struct page **pagep, void **fsdata) | 980 | struct page **pagep, void **fsdata) |
@@ -948,11 +1037,19 @@ retry_journal: | |||
948 | /* In case writeback began while the page was unlocked */ | 1037 | /* In case writeback began while the page was unlocked */ |
949 | wait_for_stable_page(page); | 1038 | wait_for_stable_page(page); |
950 | 1039 | ||
1040 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
1041 | if (ext4_should_dioread_nolock(inode)) | ||
1042 | ret = ext4_block_write_begin(page, pos, len, | ||
1043 | ext4_get_block_write); | ||
1044 | else | ||
1045 | ret = ext4_block_write_begin(page, pos, len, | ||
1046 | ext4_get_block); | ||
1047 | #else | ||
951 | if (ext4_should_dioread_nolock(inode)) | 1048 | if (ext4_should_dioread_nolock(inode)) |
952 | ret = __block_write_begin(page, pos, len, ext4_get_block_write); | 1049 | ret = __block_write_begin(page, pos, len, ext4_get_block_write); |
953 | else | 1050 | else |
954 | ret = __block_write_begin(page, pos, len, ext4_get_block); | 1051 | ret = __block_write_begin(page, pos, len, ext4_get_block); |
955 | 1052 | #endif | |
956 | if (!ret && ext4_should_journal_data(inode)) { | 1053 | if (!ret && ext4_should_journal_data(inode)) { |
957 | ret = ext4_walk_page_buffers(handle, page_buffers(page), | 1054 | ret = ext4_walk_page_buffers(handle, page_buffers(page), |
958 | from, to, NULL, | 1055 | from, to, NULL, |
@@ -2574,7 +2671,12 @@ retry_journal: | |||
2574 | /* In case writeback began while the page was unlocked */ | 2671 | /* In case writeback began while the page was unlocked */ |
2575 | wait_for_stable_page(page); | 2672 | wait_for_stable_page(page); |
2576 | 2673 | ||
2674 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
2675 | ret = ext4_block_write_begin(page, pos, len, | ||
2676 | ext4_da_get_block_prep); | ||
2677 | #else | ||
2577 | ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep); | 2678 | ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep); |
2679 | #endif | ||
2578 | if (ret < 0) { | 2680 | if (ret < 0) { |
2579 | unlock_page(page); | 2681 | unlock_page(page); |
2580 | ext4_journal_stop(handle); | 2682 | ext4_journal_stop(handle); |
@@ -3032,6 +3134,9 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb, | |||
3032 | get_block_func = ext4_get_block_write; | 3134 | get_block_func = ext4_get_block_write; |
3033 | dio_flags = DIO_LOCKING; | 3135 | dio_flags = DIO_LOCKING; |
3034 | } | 3136 | } |
3137 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
3138 | BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)); | ||
3139 | #endif | ||
3035 | if (IS_DAX(inode)) | 3140 | if (IS_DAX(inode)) |
3036 | ret = dax_do_io(rw, iocb, inode, iter, offset, get_block_func, | 3141 | ret = dax_do_io(rw, iocb, inode, iter, offset, get_block_func, |
3037 | ext4_end_io_dio, dio_flags); | 3142 | ext4_end_io_dio, dio_flags); |
@@ -3096,6 +3201,11 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, | |||
3096 | size_t count = iov_iter_count(iter); | 3201 | size_t count = iov_iter_count(iter); |
3097 | ssize_t ret; | 3202 | ssize_t ret; |
3098 | 3203 | ||
3204 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
3205 | if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) | ||
3206 | return 0; | ||
3207 | #endif | ||
3208 | |||
3099 | /* | 3209 | /* |
3100 | * If we are doing data journalling we don't support O_DIRECT | 3210 | * If we are doing data journalling we don't support O_DIRECT |
3101 | */ | 3211 | */ |
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 5687e4750c1e..51a5f1214f48 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c | |||
@@ -67,6 +67,10 @@ static void ext4_finish_bio(struct bio *bio) | |||
67 | 67 | ||
68 | bio_for_each_segment_all(bvec, bio, i) { | 68 | bio_for_each_segment_all(bvec, bio, i) { |
69 | struct page *page = bvec->bv_page; | 69 | struct page *page = bvec->bv_page; |
70 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
71 | struct page *data_page = NULL; | ||
72 | struct ext4_crypto_ctx *ctx = NULL; | ||
73 | #endif | ||
70 | struct buffer_head *bh, *head; | 74 | struct buffer_head *bh, *head; |
71 | unsigned bio_start = bvec->bv_offset; | 75 | unsigned bio_start = bvec->bv_offset; |
72 | unsigned bio_end = bio_start + bvec->bv_len; | 76 | unsigned bio_end = bio_start + bvec->bv_len; |
@@ -76,6 +80,15 @@ static void ext4_finish_bio(struct bio *bio) | |||
76 | if (!page) | 80 | if (!page) |
77 | continue; | 81 | continue; |
78 | 82 | ||
83 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
84 | if (!page->mapping) { | ||
85 | /* The bounce data pages are unmapped. */ | ||
86 | data_page = page; | ||
87 | ctx = (struct ext4_crypto_ctx *)page_private(data_page); | ||
88 | page = ctx->control_page; | ||
89 | } | ||
90 | #endif | ||
91 | |||
79 | if (error) { | 92 | if (error) { |
80 | SetPageError(page); | 93 | SetPageError(page); |
81 | set_bit(AS_EIO, &page->mapping->flags); | 94 | set_bit(AS_EIO, &page->mapping->flags); |
@@ -100,8 +113,13 @@ static void ext4_finish_bio(struct bio *bio) | |||
100 | } while ((bh = bh->b_this_page) != head); | 113 | } while ((bh = bh->b_this_page) != head); |
101 | bit_spin_unlock(BH_Uptodate_Lock, &head->b_state); | 114 | bit_spin_unlock(BH_Uptodate_Lock, &head->b_state); |
102 | local_irq_restore(flags); | 115 | local_irq_restore(flags); |
103 | if (!under_io) | 116 | if (!under_io) { |
117 | #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||
118 | if (ctx) | ||
119 | ext4_restore_control_page(data_page); | ||
120 | #endif | ||
104 | end_page_writeback(page); | 121 | end_page_writeback(page); |
122 | } | ||
105 | } | 123 | } |
106 | } | 124 | } |
107 | 125 | ||
@@ -376,6 +394,7 @@ static int io_submit_init_bio(struct ext4_io_submit *io, | |||
376 | 394 | ||
377 | static int io_submit_add_bh(struct ext4_io_submit *io, | 395 | static int io_submit_add_bh(struct ext4_io_submit *io, |
378 | struct inode *inode, | 396 | struct inode *inode, |
397 | struct page *page, | ||
379 | struct buffer_head *bh) | 398 | struct buffer_head *bh) |
380 | { | 399 | { |
381 | int ret; | 400 | int ret; |
@@ -389,7 +408,7 @@ submit_and_retry: | |||
389 | if (ret) | 408 | if (ret) |
390 | return ret; | 409 | return ret; |
391 | } | 410 | } |
392 | ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh)); | 411 | ret = bio_add_page(io->io_bio, page, bh->b_size, bh_offset(bh)); |
393 | if (ret != bh->b_size) | 412 | if (ret != bh->b_size) |
394 | goto submit_and_retry; | 413 | goto submit_and_retry; |
395 | io->io_next_block++; | 414 | io->io_next_block++; |
@@ -402,6 +421,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io, | |||
402 | struct writeback_control *wbc, | 421 | struct writeback_control *wbc, |
403 | bool keep_towrite) | 422 | bool keep_towrite) |
404 | { | 423 | { |
424 | struct page *data_page = NULL; | ||
405 | struct inode *inode = page->mapping->host; | 425 | struct inode *inode = page->mapping->host; |
406 | unsigned block_start, blocksize; | 426 | unsigned block_start, blocksize; |
407 | struct buffer_head *bh, *head; | 427 | struct buffer_head *bh, *head; |
@@ -461,19 +481,29 @@ int ext4_bio_write_page(struct ext4_io_submit *io, | |||
461 | set_buffer_async_write(bh); | 481 | set_buffer_async_write(bh); |
462 | } while ((bh = bh->b_this_page) != head); | 482 | } while ((bh = bh->b_this_page) != head); |
463 | 483 | ||
464 | /* Now submit buffers to write */ | ||
465 | bh = head = page_buffers(page); | 484 | bh = head = page_buffers(page); |
485 | |||
486 | if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) { | ||
487 | data_page = ext4_encrypt(inode, page); | ||
488 | if (IS_ERR(data_page)) { | ||
489 | ret = PTR_ERR(data_page); | ||
490 | data_page = NULL; | ||
491 | goto out; | ||
492 | } | ||
493 | } | ||
494 | |||
495 | /* Now submit buffers to write */ | ||
466 | do { | 496 | do { |
467 | if (!buffer_async_write(bh)) | 497 | if (!buffer_async_write(bh)) |
468 | continue; | 498 | continue; |
469 | ret = io_submit_add_bh(io, inode, bh); | 499 | ret = io_submit_add_bh(io, inode, |
500 | data_page ? data_page : page, bh); | ||
470 | if (ret) { | 501 | if (ret) { |
471 | /* | 502 | /* |
472 | * We only get here on ENOMEM. Not much else | 503 | * We only get here on ENOMEM. Not much else |
473 | * we can do but mark the page as dirty, and | 504 | * we can do but mark the page as dirty, and |
474 | * better luck next time. | 505 | * better luck next time. |
475 | */ | 506 | */ |
476 | redirty_page_for_writepage(wbc, page); | ||
477 | break; | 507 | break; |
478 | } | 508 | } |
479 | nr_submitted++; | 509 | nr_submitted++; |
@@ -482,6 +512,11 @@ int ext4_bio_write_page(struct ext4_io_submit *io, | |||
482 | 512 | ||
483 | /* Error stopped previous loop? Clean up buffers... */ | 513 | /* Error stopped previous loop? Clean up buffers... */ |
484 | if (ret) { | 514 | if (ret) { |
515 | out: | ||
516 | if (data_page) | ||
517 | ext4_restore_control_page(data_page); | ||
518 | printk_ratelimited(KERN_ERR "%s: ret = %d\n", __func__, ret); | ||
519 | redirty_page_for_writepage(wbc, page); | ||
485 | do { | 520 | do { |
486 | clear_buffer_async_write(bh); | 521 | clear_buffer_async_write(bh); |
487 | bh = bh->b_this_page; | 522 | bh = bh->b_this_page; |