ext4: Set the bio REQ_NOENCRYPT flag

Sets the REQ_NOENCRYPT flag for I/O requests that ext4 has already
encrypted.  Lower layers such as dm-crypt can observe that flag to
avoid encrypting again if that's how the user configures the
environment.

Change-Id: I62a93e480a9f5788070446bd94694dfb9f83c277
Signed-off-by: Michael Halcrow <mhalcrow@google.com>
Git-repo: https://android.googlesource.com/kernel/common/
Git-commit: 7af2a1358e1577379c04d08b5c1d2ac4565c9418
[stummala@codeaurora.org: resolve merge conflicts]
Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index c629e97..c74e9ac 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -131,7 +131,7 @@
 		bio->bi_bdev = inode->i_sb->s_bdev;
 		bio->bi_iter.bi_sector =
 			pblk << (inode->i_sb->s_blocksize_bits - 9);
-		bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+		bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_NOENCRYPT);
 		ret = bio_add_page(bio, ciphertext_page,
 					inode->i_sb->s_blocksize, 0);
 		if (ret != inode->i_sb->s_blocksize) {
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 0647538..f0d3daa 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -203,7 +203,10 @@
 	ssize_t			size;		/* size of the extent */
 } ext4_io_end_t;
 
+#define EXT4_IO_ENCRYPTED	1
+
 struct ext4_io_submit {
+	unsigned int		io_flags;
 	struct writeback_control *io_wbc;
 	struct bio		*io_bio;
 	ext4_io_end_t		*io_end;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c38245d..2e4428c 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1150,11 +1150,12 @@
 		if (!buffer_uptodate(bh) && !buffer_delay(bh) &&
 		    !buffer_unwritten(bh) &&
 		    (block_start < from || block_end > to)) {
-			ll_rw_block(REQ_OP_READ, 0, 1, &bh);
-			*wait_bh++ = bh;
 			decrypt = ext4_encrypted_inode(inode) &&
 				S_ISREG(inode->i_mode) &&
 				!fscrypt_using_hardware_encryption(inode);
+			ll_rw_block(REQ_OP_READ, (decrypt ? REQ_NOENCRYPT : 0),
+				    1, &bh);
+			*wait_bh++ = bh;
 		}
 	}
 	/*
@@ -3772,6 +3773,7 @@
 	struct inode *inode = mapping->host;
 	struct buffer_head *bh;
 	struct page *page;
+	bool decrypt;
 	int err = 0;
 
 	page = find_or_create_page(mapping, from >> PAGE_SHIFT,
@@ -3814,14 +3816,15 @@
 
 	if (!buffer_uptodate(bh)) {
 		err = -EIO;
-		ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+		decrypt = S_ISREG(inode->i_mode) &&
+			ext4_encrypted_inode(inode) &&
+			!fscrypt_using_hardware_encryption(inode);
+		ll_rw_block(REQ_OP_READ, (decrypt ? REQ_NOENCRYPT : 0), 1, &bh);
 		wait_on_buffer(bh);
 		/* Uhhuh. Read error. Complain and punt. */
 		if (!buffer_uptodate(bh))
 			goto unlock;
-		if (S_ISREG(inode->i_mode) &&
-		    ext4_encrypted_inode(inode) &&
-		    !fscrypt_using_hardware_encryption(inode)) {
+		if (decrypt) {
 			/* We expect the key to be set. */
 			BUG_ON(!fscrypt_has_encryption_key(inode));
 			BUG_ON(blocksize != PAGE_SIZE);
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 8d4ec1a..228baa5 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -341,6 +341,8 @@
 	if (bio) {
 		int io_op_flags = io->io_wbc->sync_mode == WB_SYNC_ALL ?
 				  WRITE_SYNC : 0;
+		if (io->io_flags & EXT4_IO_ENCRYPTED)
+			io_op_flags |= REQ_NOENCRYPT;
 		bio_set_op_attrs(io->io_bio, REQ_OP_WRITE, io_op_flags);
 		submit_bio(io->io_bio);
 	}
@@ -350,6 +352,7 @@
 void ext4_io_submit_init(struct ext4_io_submit *io,
 			 struct writeback_control *wbc)
 {
+	io->io_flags = 0;
 	io->io_wbc = wbc;
 	io->io_bio = NULL;
 	io->io_end = NULL;
@@ -492,6 +495,8 @@
 	do {
 		if (!buffer_async_write(bh))
 			continue;
+		if (data_page)
+			io->io_flags |= EXT4_IO_ENCRYPTED;
 		ret = io_submit_add_bh(io, inode,
 				       data_page ? data_page : page, bh);
 		if (ret) {
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index c39a12d..270c4f4 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -297,7 +297,8 @@
 			bio->bi_iter.bi_sector = blocks[0] << (blkbits - 9);
 			bio->bi_end_io = mpage_end_io;
 			bio->bi_private = ctx;
-			bio_set_op_attrs(bio, REQ_OP_READ, 0);
+			bio_set_op_attrs(bio, REQ_OP_READ,
+					 ctx ? REQ_NOENCRYPT : 0);
 		}
 
 		length = first_hole << blkbits;