@@ -1302,6 +1302,27 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
ctxsize = btrfs_file_extent_ctxsize_from_item(leaf, path);
ASSERT(ctxsize == btrfs_file_extent_encryption_ctxsize(leaf, fi));
+
+#ifdef CONFIG_FS_ENCRYPTION
+ if (ctxsize) {
+ u8 context[FSCRYPT_SET_CONTEXT_MAX_SIZE];
+ int res;
+ unsigned int nofs_flag;
+
+ read_extent_buffer(leaf, context,
+ (unsigned long)fi->fscrypt_context,
+ ctxsize);
+ nofs_flag = memalloc_nofs_save();
+ res = fscrypt_load_extent_info(&inode->vfs_inode,
+ context, ctxsize,
+ &em->fscrypt_info);
+ memalloc_nofs_restore(nofs_flag);
+ if (res)
+ btrfs_err(fs_info,
+ "Unable to load fscrypt info: %d",
+ res);
+ }
+#endif /* CONFIG_FS_ENCRYPTION */
} else if (type == BTRFS_FILE_EXTENT_INLINE) {
em->block_start = EXTENT_MAP_INLINE;
em->start = extent_start;
@@ -164,6 +164,41 @@ static bool btrfs_fscrypt_empty_dir(struct inode *inode)
return inode->i_size == BTRFS_EMPTY_DIR_SIZE;
}
+int btrfs_fscrypt_get_extent_info(const struct inode *inode,
+ u64 lblk_num,
+ struct fscrypt_info **info_ptr,
+ u64 *extent_offset,
+ u64 *extent_length)
+{
+ u64 offset = lblk_num << inode->i_blkbits;
+ struct extent_map *em;
+
+ /* Since IO must be in progress on this extent, this must succeed */
+ em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, PAGE_SIZE);
+ if (!em)
+ return -EINVAL;
+
+ if (em->block_start == EXTENT_MAP_HOLE) {
+ btrfs_info(BTRFS_I(inode)->root->fs_info,
+ "extent context requested for block %llu of inode %lu without an extent",
+ lblk_num, inode->i_ino);
+ free_extent_map(em);
+ return -ENOENT;
+ }
+
+ *info_ptr = em->fscrypt_info;
+
+ if (extent_offset)
+ *extent_offset
+ = (offset - em->start) >> inode->i_blkbits;
+
+ if (extent_length)
+ *extent_length = em->len >> inode->i_blkbits;
+
+ free_extent_map(em);
+ return 0;
+}
+
static struct block_device **btrfs_fscrypt_get_devices(struct super_block *sb,
unsigned int *num_devs)
{
@@ -195,6 +230,7 @@ const struct fscrypt_operations btrfs_fscrypt_ops = {
.get_context = btrfs_fscrypt_get_context,
.set_context = btrfs_fscrypt_set_context,
.empty_dir = btrfs_fscrypt_empty_dir,
+ .get_extent_info = btrfs_fscrypt_get_extent_info,
.get_devices = btrfs_fscrypt_get_devices,
.key_prefix = "btrfs:"
};
@@ -50,6 +50,12 @@ static inline bool btrfs_fscrypt_match_name(struct fscrypt_name *fname,
}
#endif /* CONFIG_FS_ENCRYPTION */
+int btrfs_fscrypt_get_extent_info(const struct inode *inode,
+ u64 lblk_num,
+ struct fscrypt_info **info_ptr,
+ u64 *extent_offset,
+ u64 *extent_length);
+
extern const struct fscrypt_operations btrfs_fscrypt_ops;
#endif /* BTRFS_FSCRYPT_H */
@@ -3036,17 +3036,46 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
u64 num_bytes = btrfs_stack_file_extent_num_bytes(stack_fi);
u64 ram_bytes = btrfs_stack_file_extent_ram_bytes(stack_fi);
struct btrfs_drop_extents_args drop_args = { 0 };
- size_t fscrypt_context_size =
- btrfs_stack_file_extent_encryption(stack_fi) ?
- FSCRYPT_SET_CONTEXT_MAX_SIZE : 0;
+ size_t fscrypt_context_size = 0;
+#ifdef CONFIG_FS_ENCRYPTION
+ u8 context[FSCRYPT_SET_CONTEXT_MAX_SIZE];
+#endif /* CONFIG_FS_ENCRYPTION */
+
int ret;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
+#ifdef CONFIG_FS_ENCRYPTION
+ if (IS_ENCRYPTED(&inode->vfs_inode)) {
+ u8 encryption;
+ struct fscrypt_info *fscrypt_info;
+ u64 lblk_num = file_pos >> root->fs_info->sectorsize_bits;
+
+ ret = btrfs_fscrypt_get_extent_info(&inode->vfs_inode,
+ lblk_num, &fscrypt_info,
+ NULL, NULL);
+ if (ret) {
+ btrfs_err(root->fs_info, "No fscrypt context found");
+ goto out;
+ }
+
+ fscrypt_context_size =
+ fscrypt_set_extent_context(fscrypt_info, context,
+ FSCRYPT_SET_CONTEXT_MAX_SIZE);
+ if (fscrypt_context_size < 0) {
+ ret = fscrypt_context_size;
+ goto out;
+ }
+ encryption = btrfs_pack_encryption(BTRFS_ENCRYPTION_FSCRYPT,
+ fscrypt_context_size);
+ btrfs_set_stack_file_extent_encryption(stack_fi, encryption);
+ }
+#endif /* CONFIG_FS_ENCRYPTION */
+
/*
- * we may be replacing one extent in the tree with another.
+ * 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
* to drop it from the cache until it is completely in the btree.
*
@@ -3079,6 +3108,13 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
btrfs_item_ptr_offset(leaf, path->slots[0]),
sizeof(struct btrfs_file_extent_item));
+#ifdef CONFIG_FS_ENCRYPTION
+ write_extent_buffer(leaf, context,
+ btrfs_item_ptr_offset(leaf, path->slots[0]) +
+ sizeof(struct btrfs_file_extent_item),
+ fscrypt_context_size);
+#endif /* CONFIG_FS_ENCRYPTION */
+
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(path);
@@ -4634,8 +4634,22 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
u64 extent_offset = em->start - em->orig_start;
u64 block_len;
int ret;
- u8 encryption = btrfs_pack_encryption(IS_ENCRYPTED(&inode->vfs_inode) ?
- BTRFS_ENCRYPTION_FSCRYPT : 0, 0);
+ u8 encryption = 0;
+ size_t fscrypt_context_size = 0;
+#ifdef CONFIG_FS_ENCRYPTION
+ u8 context[FSCRYPT_SET_CONTEXT_MAX_SIZE];
+
+ if (em->fscrypt_info) {
+ fscrypt_context_size =
+ fscrypt_set_extent_context(em->fscrypt_info, context,
+ FSCRYPT_SET_CONTEXT_MAX_SIZE);
+ if (fscrypt_context_size < 0)
+ return fscrypt_context_size;
+
+ encryption = btrfs_pack_encryption(BTRFS_ENCRYPTION_FSCRYPT,
+ fscrypt_context_size);
+ }
+#endif /* CONFIG_FS_ENCRYPTION */
btrfs_set_stack_file_extent_generation(&fi, trans->transid);
if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
@@ -4697,6 +4711,12 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
write_extent_buffer(leaf, &fi,
btrfs_item_ptr_offset(leaf, path->slots[0]),
sizeof(fi));
+#ifdef CONFIG_FS_ENCRYPTION
+ write_extent_buffer(leaf, context,
+ btrfs_item_ptr_offset(leaf, path->slots[0]) +
+ sizeof(fi), fscrypt_context_size);
+#endif /* CONFIG_FS_ENCRYPTION */
+
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(path);
@@ -1080,6 +1080,11 @@ struct btrfs_file_extent_item {
* always reflects the size uncompressed and without encoding.
*/
__le64 num_bytes;
+ /*
+ * fscrypt extent encryption context. Only present if extent is
+ * encrypted (as per the encryption field).
+ */
+ __u8 fscrypt_context[0];
} __attribute__ ((__packed__));
This change actually saves and loads the extent contexts created and freed by the last change. Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> --- fs/btrfs/file-item.c | 21 ++++++++++++++++ fs/btrfs/fscrypt.c | 36 +++++++++++++++++++++++++++ fs/btrfs/fscrypt.h | 6 +++++ fs/btrfs/inode.c | 44 ++++++++++++++++++++++++++++++--- fs/btrfs/tree-log.c | 24 ++++++++++++++++-- include/uapi/linux/btrfs_tree.h | 5 ++++ 6 files changed, 130 insertions(+), 6 deletions(-)