[RFC PATCH 13/19] btrfs: allow writing normal and compressed encrypted extents

From: Mark Harmstone
Date: Tue Jan 08 2019 - 20:27:52 EST


Signed-off-by: Mark Harmstone <mark@xxxxxxxxxxxxx>
---
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