lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed,  9 Jan 2019 01:26:55 +0000
From:   Mark Harmstone <mark@...mstone.com>
To:     unlisted-recipients:; (no To-header on input)
Cc:     mark@...mstone.com, Chris Mason <clm@...com>,
        Josef Bacik <josef@...icpanda.com>,
        David Sterba <dsterba@...e.com>, linux-btrfs@...r.kernel.org,
        linux-kernel@...r.kernel.org
Subject: [RFC PATCH 13/19] btrfs: allow writing normal and compressed encrypted extents

Signed-off-by: Mark Harmstone <mark@...mstone.com>
---
 fs/btrfs/encryption.c   | 125 ++++++++++++++++++++++++++++
 fs/btrfs/encryption.h   |   8 ++
 fs/btrfs/extent_io.c    |  20 +++--
 fs/btrfs/inode.c        | 180 ++++++++++++++++++++++++++++++++++------
 fs/btrfs/ordered-data.c |  19 +++--
 fs/btrfs/ordered-data.h |  12 ++-
 6 files changed, 320 insertions(+), 44 deletions(-)

diff --git a/fs/btrfs/encryption.c b/fs/btrfs/encryption.c
index 41c001339cc7..2bf45c9f96fa 100644
--- a/fs/btrfs/encryption.c
+++ b/fs/btrfs/encryption.c
@@ -552,3 +552,128 @@ int btrfs_encrypt_inline(struct extent_buffer *eb, char *plaintext,
 	kfree(tmp);
 	return ret;
 }
+
+static int btrfs_encrypt_page(char *src, char *dest,
+			      struct btrfs_enc_key *key, char *iv)
+{
+	struct scatterlist sg;
+	struct scatterlist sg2;
+	struct skcipher_request *req = NULL;
+	int ret = -EFAULT;
+
+	req = skcipher_request_alloc(key->skcipher, GFP_KERNEL);
+	if (!req) {
+		pr_info("could not allocate skcipher request\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	sg_init_one(&sg, src, PAGE_SIZE);
+	sg_init_one(&sg2, dest, PAGE_SIZE);
+	skcipher_request_set_crypt(req, &sg, &sg2, PAGE_SIZE, iv);
+
+	ret = crypto_skcipher_encrypt(req);
+
+	if (ret < 0)
+		goto out;
+
+out:
+	if (req)
+		skcipher_request_free(req);
+	return ret;
+}
+
+int btrfs_encrypt_pages(struct address_space *mapping, struct page **pages,
+			unsigned long *nr_pages, u64 start,
+			struct btrfs_enc_key *key, char *iv)
+{
+	int ret;
+	unsigned int i;
+	char ctr[BTRFS_ENCRYPTION_BLOCK_LENGTH];
+
+	if (!key->loaded) {
+		mutex_lock(&key->lock);
+		ret = btrfs_load_key(key);
+		mutex_unlock(&key->lock);
+
+		if (ret) {
+			*nr_pages = 0;
+			return ret;
+		}
+	}
+
+	key->used = true;
+
+	memcpy(ctr, iv, BTRFS_ENCRYPTION_BLOCK_LENGTH);
+
+	for (i = 0; i < *nr_pages; i++) {
+		struct page *in_page;
+		char *src, *dest;
+
+		in_page = find_get_page(mapping, start >> PAGE_SHIFT);
+
+		pages[i] = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+		if (!pages[i]) {
+			*nr_pages = i;
+			return -ENOMEM;
+		}
+
+		src = kmap(in_page);
+		dest = kmap(pages[i]);
+
+		ret = btrfs_encrypt_page(src, dest, key, ctr);
+
+		kunmap(pages[i]);
+		kunmap(in_page);
+
+		if (ret) {
+			*nr_pages = i;
+			return ret;
+		}
+
+		start += PAGE_SIZE;
+	}
+
+	return 0;
+}
+
+int btrfs_encrypt_compressed_pages(struct page **pages,
+				   unsigned long *nr_pages,
+				   struct btrfs_enc_key *key, char *iv)
+{
+	int ret;
+	unsigned int i;
+	char ctr[BTRFS_ENCRYPTION_BLOCK_LENGTH];
+
+	if (!key->loaded) {
+		mutex_lock(&key->lock);
+		ret = btrfs_load_key(key);
+		mutex_unlock(&key->lock);
+
+		if (ret) {
+			*nr_pages = 0;
+			return ret;
+		}
+	}
+
+	key->used = true;
+
+	memcpy(ctr, iv, BTRFS_ENCRYPTION_BLOCK_LENGTH);
+
+	for (i = 0; i < *nr_pages; i++) {
+		char *buf;
+
+		buf = kmap(pages[i]);
+
+		ret = btrfs_encrypt_page(buf, buf, key, ctr);
+
+		kunmap(pages[i]);
+
+		if (ret) {
+			*nr_pages = i;
+			return ret;
+		}
+	}
+
+	return 0;
+}
diff --git a/fs/btrfs/encryption.h b/fs/btrfs/encryption.h
index 0d24dc51793c..cf10859fafe1 100644
--- a/fs/btrfs/encryption.h
+++ b/fs/btrfs/encryption.h
@@ -46,6 +46,14 @@ int btrfs_encrypt_inline(struct extent_buffer *eb, char *plaintext,
 			 unsigned long start, unsigned long len,
 			 struct btrfs_enc_key *key, char *iv);
 
+int btrfs_encrypt_pages(struct address_space *mapping, struct page **pages,
+			unsigned long *nr_pages, u64 start,
+			struct btrfs_enc_key *key, char *iv);
+
+int btrfs_encrypt_compressed_pages(struct page **pages,
+				   unsigned long *nr_pages,
+				   struct btrfs_enc_key *key, char *iv);
+
 int btrfs_load_key(struct btrfs_enc_key *k);
 
 #endif
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 73fb0af50da8..92bc9924c001 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -3407,7 +3407,7 @@ static noinline_for_stack int __extent_writepage_io(struct inode *inode,
 	size_t blocksize;
 	int ret = 0;
 	int nr = 0;
-	bool compressed;
+	bool compressed, encrypted;
 
 	if (tree->ops && tree->ops->writepage_start_hook) {
 		ret = tree->ops->writepage_start_hook(page, start,
@@ -3469,28 +3469,30 @@ static noinline_for_stack int __extent_writepage_io(struct inode *inode,
 		bdev = em->bdev;
 		block_start = em->block_start;
 		compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
+		encrypted = test_bit(EXTENT_FLAG_ENCRYPTED, &em->flags);
 		free_extent_map(em);
 		em = NULL;
 
 		/*
-		 * compressed and inline extents are written through other
-		 * paths in the FS
+		 * compressed, encrypted, or inline extents are written through
+		 * other paths in the FS
 		 */
-		if (compressed || block_start == EXTENT_MAP_HOLE ||
-		    block_start == EXTENT_MAP_INLINE) {
+		if (compressed || encrypted ||
+			block_start == EXTENT_MAP_HOLE ||
+			block_start == EXTENT_MAP_INLINE) {
 			/*
 			 * end_io notification does not happen here for
 			 * compressed extents
 			 */
-			if (!compressed && tree->ops &&
+			if (!compressed && !encrypted && tree->ops &&
 			    tree->ops->writepage_end_io_hook)
 				tree->ops->writepage_end_io_hook(page, cur,
 							 cur + iosize - 1,
 							 NULL, 1);
-			else if (compressed) {
+			else if (compressed || encrypted) {
 				/* we don't want to end_page_writeback on
-				 * a compressed extent.  this happens
-				 * elsewhere
+				 * a compressed or encrypted extent.
+				 * This happens elsewhere
 				 */
 				nr++;
 			}
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 52ea7d7c880b..61481833f5e4 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -97,7 +97,8 @@ static struct extent_map *create_io_em(struct inode *inode, u64 start, u64 len,
 				       u64 orig_start, u64 block_start,
 				       u64 block_len, u64 orig_block_len,
 				       u64 ram_bytes, int compress_type,
-				       int type);
+				       int type, struct btrfs_enc_key *enc_key,
+				       char *iv);
 
 static void __endio_write_update_ordered(struct inode *inode,
 					 const u64 offset, const u64 bytes,
@@ -375,6 +376,8 @@ struct async_extent {
 	struct page **pages;
 	unsigned long nr_pages;
 	int compress_type;
+	struct btrfs_enc_key *key;
+	char iv[BTRFS_ENCRYPTION_BLOCK_LENGTH];
 	struct list_head list;
 };
 
@@ -394,7 +397,8 @@ static noinline int add_async_extent(struct async_cow *cow,
 				     u64 compressed_size,
 				     struct page **pages,
 				     unsigned long nr_pages,
-				     int compress_type)
+				     int compress_type,
+				     struct btrfs_enc_key *key, char *iv)
 {
 	struct async_extent *async_extent;
 
@@ -406,6 +410,11 @@ static noinline int add_async_extent(struct async_cow *cow,
 	async_extent->pages = pages;
 	async_extent->nr_pages = nr_pages;
 	async_extent->compress_type = compress_type;
+	async_extent->key = key;
+
+	if (key)
+		memcpy(async_extent->iv, iv, BTRFS_ENCRYPTION_BLOCK_LENGTH);
+
 	list_add_tail(&async_extent->list, &cow->extents);
 	return 0;
 }
@@ -498,8 +507,6 @@ static noinline void compress_file_range(struct inode *inode,
 	will_compress = 0;
 	nr_pages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1;
 	BUILD_BUG_ON((BTRFS_MAX_COMPRESSED % PAGE_SIZE) != 0);
-	nr_pages = min_t(unsigned long, nr_pages,
-			BTRFS_MAX_COMPRESSED / PAGE_SIZE);
 
 	/*
 	 * we don't want to send crud past the end of i_size through
@@ -526,8 +533,6 @@ static noinline void compress_file_range(struct inode *inode,
 	   (start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size))
 		goto cleanup_and_bail_uncompressed;
 
-	total_compressed = min_t(unsigned long, total_compressed,
-			BTRFS_MAX_UNCOMPRESSED);
 	total_in = 0;
 	ret = 0;
 
@@ -537,6 +542,8 @@ static noinline void compress_file_range(struct inode *inode,
 	 * change at any time if we discover bad compression ratios.
 	 */
 	if (inode_need_compress(inode, start, end)) {
+		nr_pages = min_t(unsigned long, nr_pages,
+				 BTRFS_MAX_COMPRESSED / PAGE_SIZE);
 		WARN_ON(pages);
 		pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
 		if (!pages) {
@@ -567,6 +574,9 @@ static noinline void compress_file_range(struct inode *inode,
 			redirty = 1;
 		}
 
+		total_compressed = min_t(unsigned long, total_compressed,
+					 BTRFS_MAX_UNCOMPRESSED);
+
 		/* Compression level is applied here and only here */
 		ret = btrfs_compress_pages(
 			compress_type | (fs_info->compress_level << 4),
@@ -594,6 +604,37 @@ static noinline void compress_file_range(struct inode *inode,
 			will_compress = 1;
 		}
 	}
+
+	if (key) {
+		if (!pages) {
+			pages = kcalloc(nr_pages,
+					sizeof(struct page *), GFP_NOFS);
+			if (!pages)
+				goto cont;
+		}
+
+		if (!redirty) {
+			extent_range_clear_dirty_for_io(inode, start, end);
+			redirty = 1;
+		}
+
+		ret = crypto_rng_get_bytes(crypto_default_rng, iv,
+					   BTRFS_ENCRYPTION_BLOCK_LENGTH);
+
+		if (ret)
+			goto cont;
+
+		if (will_compress) {
+			ret = btrfs_encrypt_compressed_pages(pages, &nr_pages,
+							     key, iv);
+		} else {
+			ret = btrfs_encrypt_pages(inode->i_mapping, pages,
+						  &nr_pages, start, key, iv);
+		}
+
+		if (ret)
+			key = NULL;
+	}
 cont:
 	if (start == 0) {
 		/* lets try to make an inline extent */
@@ -664,7 +705,7 @@ static noinline void compress_file_range(struct inode *inode,
 			 */
 			add_async_extent(async_cow, start, total_in,
 					total_compressed, pages, nr_pages,
-					compress_type);
+					compress_type, key, iv);
 
 			if (start + total_in < end) {
 				start += total_in;
@@ -675,6 +716,29 @@ static noinline void compress_file_range(struct inode *inode,
 			return;
 		}
 	}
+
+	if (key) {
+		total_in = ALIGN(end - start, PAGE_SIZE);
+
+		if (total_in == 0)
+			return;
+
+		total_compressed = ALIGN(total_compressed, blocksize);
+
+		*num_added += 1;
+
+		if (!will_compress) {
+			compress_type = BTRFS_COMPRESS_NONE;
+			total_compressed = total_in;
+		}
+
+		add_async_extent(async_cow, start, total_in,
+				 total_compressed, pages, nr_pages,
+				 compress_type, key, iv);
+
+		return;
+	}
+
 	if (pages) {
 		/*
 		 * the compression code ran but failed to make things smaller,
@@ -710,7 +774,7 @@ static noinline void compress_file_range(struct inode *inode,
 	if (redirty)
 		extent_range_redirty_for_io(inode, start, end);
 	add_async_extent(async_cow, start, end - start + 1, 0, NULL, 0,
-			 BTRFS_COMPRESS_NONE);
+			 BTRFS_COMPRESS_NONE, NULL, NULL);
 	*num_added += 1;
 
 	return;
@@ -848,7 +912,8 @@ static noinline void submit_compressed_extents(struct inode *inode,
 				  ins.offset, /* orig_block_len */
 				  async_extent->ram_size, /* ram_bytes */
 				  async_extent->compress_type,
-				  BTRFS_ORDERED_COMPRESSED);
+				  BTRFS_ORDERED_COMPRESSED,
+				  async_extent->key, async_extent->iv);
 		if (IS_ERR(em))
 			/* ret value is not necessary due to void function */
 			goto out_free_reserve;
@@ -860,7 +925,9 @@ static noinline void submit_compressed_extents(struct inode *inode,
 						async_extent->ram_size,
 						ins.offset,
 						BTRFS_ORDERED_COMPRESSED,
-						async_extent->compress_type);
+						async_extent->compress_type,
+						async_extent->key,
+						async_extent->iv);
 		if (ret) {
 			btrfs_drop_extent_cache(BTRFS_I(inode),
 						async_extent->start,
@@ -1051,6 +1118,8 @@ static noinline int cow_file_range(struct inode *inode,
 			start + num_bytes - 1, 0);
 
 	while (num_bytes > 0) {
+		char iv[BTRFS_ENCRYPTION_BLOCK_LENGTH];
+
 		cur_alloc_size = num_bytes;
 		ret = btrfs_reserve_extent(root, cur_alloc_size, cur_alloc_size,
 					   fs_info->sectorsize, 0, alloc_hint,
@@ -1060,6 +1129,14 @@ static noinline int cow_file_range(struct inode *inode,
 		cur_alloc_size = ins.offset;
 		extent_reserved = true;
 
+		if (key) {
+			ret = crypto_rng_get_bytes(crypto_default_rng, iv,
+						BTRFS_ENCRYPTION_BLOCK_LENGTH);
+
+			if (ret)
+				goto out_reserve;
+		}
+
 		ram_size = ins.offset;
 		em = create_io_em(inode, start, ins.offset, /* len */
 				  start, /* orig_start */
@@ -1068,7 +1145,8 @@ static noinline int cow_file_range(struct inode *inode,
 				  ins.offset, /* orig_block_len */
 				  ram_size, /* ram_bytes */
 				  BTRFS_COMPRESS_NONE, /* compress_type */
-				  BTRFS_ORDERED_REGULAR /* type */);
+				  BTRFS_ORDERED_REGULAR /* type */,
+				  key, iv);
 		if (IS_ERR(em)) {
 			ret = PTR_ERR(em);
 			goto out_reserve;
@@ -1076,7 +1154,8 @@ static noinline int cow_file_range(struct inode *inode,
 		free_extent_map(em);
 
 		ret = btrfs_add_ordered_extent(inode, start, ins.objectid,
-					       ram_size, cur_alloc_size, 0);
+					       ram_size, cur_alloc_size, 0,
+					       key, iv);
 		if (ret)
 			goto out_drop_extent_cache;
 
@@ -1249,8 +1328,10 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
 		async_cow->start = start;
 		async_cow->write_flags = write_flags;
 
-		if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS &&
-		    !btrfs_test_opt(fs_info, FORCE_COMPRESS))
+		if ((inode_need_encrypt(inode) &&
+			!inode_need_compress(inode, start, end)) ||
+		   (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS &&
+		    !btrfs_test_opt(fs_info, FORCE_COMPRESS)))
 			cur_end = end;
 		else
 			cur_end = min(end, start + SZ_512K - 1);
@@ -1532,7 +1613,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
 					  num_bytes, /* block_len */
 					  disk_num_bytes, /* orig_block_len */
 					  ram_bytes, BTRFS_COMPRESS_NONE,
-					  BTRFS_ORDERED_PREALLOC);
+					  BTRFS_ORDERED_PREALLOC, NULL, NULL);
 			if (IS_ERR(em)) {
 				if (nocow)
 					btrfs_dec_nocow_writers(fs_info,
@@ -1550,7 +1631,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
 		}
 
 		ret = btrfs_add_ordered_extent(inode, cur_offset, disk_bytenr,
-					       num_bytes, num_bytes, type);
+					       num_bytes, num_bytes, type,
+					       NULL, NULL);
 		if (nocow)
 			btrfs_dec_nocow_writers(fs_info, disk_bytenr);
 		BUG_ON(ret); /* -ENOMEM */
@@ -1642,14 +1724,17 @@ static int run_delalloc_range(void *private_data, struct page *locked_page,
 	int ret;
 	int force_cow = need_force_cow(inode, start, end);
 	unsigned int write_flags = wbc_to_write_flags(wbc);
+	bool encrypt = inode_need_encrypt(inode);
 
-	if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW && !force_cow) {
+	if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW && !force_cow &&
+	    !encrypt) {
 		ret = run_delalloc_nocow(inode, locked_page, start, end,
 					 page_started, 1, nr_written);
-	} else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC && !force_cow) {
+	} else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC &&
+		!force_cow && !encrypt) {
 		ret = run_delalloc_nocow(inode, locked_page, start, end,
 					 page_started, 0, nr_written);
-	} else if (!inode_need_compress(inode, start, end)) {
+	} else if (!inode_need_compress(inode, start, end) && !encrypt) {
 		ret = cow_file_range(inode, locked_page, start, end, end,
 				      page_started, nr_written, 1, NULL);
 	} else {
@@ -2238,7 +2323,8 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
 				       u64 disk_bytenr, u64 disk_num_bytes,
 				       u64 num_bytes, u64 ram_bytes,
 				       u8 compression, u8 encryption,
-				       u16 other_encoding, int extent_type)
+				       u16 other_encoding, int extent_type,
+				       u64 key_number, char *iv)
 {
 	struct btrfs_root *root = BTRFS_I(inode)->root;
 	struct btrfs_file_extent_item *fi;
@@ -2248,11 +2334,17 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
 	u64 qg_released;
 	int extent_inserted = 0;
 	int ret;
+	size_t item_size;
 
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
 
+	if (encryption != BTRFS_ENCRYPTION_NONE)
+		item_size = sizeof(struct btrfs_file_extent_item_enc);
+	else
+		item_size = sizeof(*fi);
+
 	/*
 	 * we may be replacing one extent in the tree with another.
 	 * The new extent is pinned in the extent map, and we don't want
@@ -2264,7 +2356,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
 	 */
 	ret = __btrfs_drop_extents(trans, root, inode, path, file_pos,
 				   file_pos + num_bytes, NULL, 0,
-				   1, sizeof(*fi), &extent_inserted);
+				   1, item_size, &extent_inserted);
 	if (ret)
 		goto out;
 
@@ -2275,7 +2367,7 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
 
 		path->leave_spinning = 1;
 		ret = btrfs_insert_empty_item(trans, root, path, &ins,
-					      sizeof(*fi));
+					      item_size);
 		if (ret)
 			goto out;
 	}
@@ -2293,6 +2385,17 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
 	btrfs_set_file_extent_encryption(leaf, fi, encryption);
 	btrfs_set_file_extent_other_encoding(leaf, fi, other_encoding);
 
+	if (encryption != BTRFS_ENCRYPTION_NONE) {
+		struct btrfs_file_extent_item_enc *fi_enc;
+
+		fi_enc = (struct btrfs_file_extent_item_enc *)fi;
+
+		btrfs_set_file_extent_enc_key_number(leaf, fi_enc, key_number);
+
+		write_eb_member(leaf, fi_enc, struct btrfs_file_extent_item_enc,
+				iv, iv);
+	}
+
 	btrfs_mark_buffer_dirty(leaf);
 	btrfs_release_path(path);
 
@@ -3091,14 +3194,27 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
 						ordered_extent->file_offset +
 						logical_len);
 	} else {
+		u32 encrypt_type;
+		u64 key_number;
+
+		if (ordered_extent->key) {
+			encrypt_type = BTRFS_ENCRYPTION_AES256CTR;
+			key_number = ordered_extent->key->key_number;
+		} else {
+			encrypt_type = BTRFS_ENCRYPTION_NONE;
+			key_number = 0;
+		}
+
 		BUG_ON(root == fs_info->tree_root);
 		ret = insert_reserved_file_extent(trans, inode,
 						ordered_extent->file_offset,
 						ordered_extent->start,
 						ordered_extent->disk_len,
 						logical_len, logical_len,
-						compress_type, 0, 0,
-						BTRFS_FILE_EXTENT_REG);
+						compress_type, encrypt_type, 0,
+						BTRFS_FILE_EXTENT_REG,
+						key_number,
+						ordered_extent->iv);
 		if (!ret) {
 			clear_reserved_extent = false;
 			btrfs_release_delalloc_bytes(fs_info,
@@ -7283,7 +7399,7 @@ static struct extent_map *btrfs_create_dio_extent(struct inode *inode,
 				  block_start, block_len, orig_block_len,
 				  ram_bytes,
 				  BTRFS_COMPRESS_NONE, /* compress_type */
-				  type);
+				  type, NULL, NULL);
 		if (IS_ERR(em))
 			goto out;
 	}
@@ -7562,7 +7678,8 @@ static struct extent_map *create_io_em(struct inode *inode, u64 start, u64 len,
 				       u64 orig_start, u64 block_start,
 				       u64 block_len, u64 orig_block_len,
 				       u64 ram_bytes, int compress_type,
-				       int type)
+				       int type, struct btrfs_enc_key *enc_key,
+				       char *iv)
 {
 	struct extent_map_tree *em_tree;
 	struct extent_map *em;
@@ -7596,6 +7713,14 @@ static struct extent_map *create_io_em(struct inode *inode, u64 start, u64 len,
 		em->compress_type = compress_type;
 	}
 
+	if (enc_key) {
+		em->encrypt_type = BTRFS_ENCRYPTION_AES256CTR;
+		em->key_number = enc_key->key_number;
+		memcpy(em->iv, iv, BTRFS_ENCRYPTION_BLOCK_LENGTH);
+	} else {
+		em->encrypt_type = BTRFS_ENCRYPTION_NONE;
+	}
+
 	do {
 		btrfs_drop_extent_cache(BTRFS_I(inode), em->start,
 				em->start + em->len - 1, 0);
@@ -10413,7 +10538,8 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
 						  cur_offset, ins.objectid,
 						  ins.offset, ins.offset,
 						  ins.offset, 0, 0, 0,
-						  BTRFS_FILE_EXTENT_PREALLOC);
+						  BTRFS_FILE_EXTENT_PREALLOC,
+						  0, NULL);
 		if (ret) {
 			btrfs_free_reserved_extent(fs_info, ins.objectid,
 						   ins.offset, 0);
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 0c4ef208b8b9..5fbb60b5ddbe 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -170,7 +170,8 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree,
  */
 static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
 				      u64 start, u64 len, u64 disk_len,
-				      int type, int dio, int compress_type)
+				      int type, int dio, int compress_type,
+				      struct btrfs_enc_key *key, char *iv)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
 	struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -190,10 +191,14 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
 	entry->bytes_left = len;
 	entry->inode = igrab(inode);
 	entry->compress_type = compress_type;
+	entry->key = key;
 	entry->truncated_len = (u64)-1;
 	if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE)
 		set_bit(type, &entry->flags);
 
+	if (key)
+		memcpy(entry->iv, iv, BTRFS_ENCRYPTION_BLOCK_LENGTH);
+
 	if (dio)
 		set_bit(BTRFS_ORDERED_DIRECT, &entry->flags);
 
@@ -241,11 +246,12 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
 }
 
 int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
-			     u64 start, u64 len, u64 disk_len, int type)
+			     u64 start, u64 len, u64 disk_len, int type,
+			     struct btrfs_enc_key *key, char *iv)
 {
 	return __btrfs_add_ordered_extent(inode, file_offset, start, len,
 					  disk_len, type, 0,
-					  BTRFS_COMPRESS_NONE);
+					  BTRFS_COMPRESS_NONE, key, iv);
 }
 
 int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset,
@@ -253,16 +259,17 @@ int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset,
 {
 	return __btrfs_add_ordered_extent(inode, file_offset, start, len,
 					  disk_len, type, 1,
-					  BTRFS_COMPRESS_NONE);
+					  BTRFS_COMPRESS_NONE, NULL, NULL);
 }
 
 int btrfs_add_ordered_extent_compress(struct inode *inode, u64 file_offset,
 				      u64 start, u64 len, u64 disk_len,
-				      int type, int compress_type)
+				      int type, int compress_type,
+				      struct btrfs_enc_key *key, char *iv)
 {
 	return __btrfs_add_ordered_extent(inode, file_offset, start, len,
 					  disk_len, type, 0,
-					  compress_type);
+					  compress_type, key, iv);
 }
 
 /*
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index 02d813aaa261..563d882fdd16 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -95,6 +95,12 @@ struct btrfs_ordered_extent {
 	/* compression algorithm */
 	int compress_type;
 
+	/* encryption key */
+	struct btrfs_enc_key *key;
+
+	/* encryption initialization vector */
+	char iv[BTRFS_ENCRYPTION_BLOCK_LENGTH];
+
 	/* reference count */
 	refcount_t refs;
 
@@ -158,12 +164,14 @@ int btrfs_dec_test_first_ordered_pending(struct inode *inode,
 				   u64 *file_offset, u64 io_size,
 				   int uptodate);
 int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
-			     u64 start, u64 len, u64 disk_len, int type);
+			     u64 start, u64 len, u64 disk_len, int type,
+			     struct btrfs_enc_key *key, char *iv);
 int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset,
 				 u64 start, u64 len, u64 disk_len, int type);
 int btrfs_add_ordered_extent_compress(struct inode *inode, u64 file_offset,
 				      u64 start, u64 len, u64 disk_len,
-				      int type, int compress_type);
+				      int type, int compress_type,
+				      struct btrfs_enc_key *key, char *iv);
 void btrfs_add_ordered_sum(struct inode *inode,
 			   struct btrfs_ordered_extent *entry,
 			   struct btrfs_ordered_sum *sum);
-- 
2.19.2

Powered by blists - more mailing lists