* [PATCH 4/8] btrfs-progs: add inode encryption contexts
2023-10-10 20:28 [PATCH 0/8] btrfs-progs: add fscrypt support Josef Bacik
@ 2023-10-10 20:28 ` Josef Bacik
0 siblings, 0 replies; 34+ messages in thread
From: Josef Bacik @ 2023-10-10 20:28 UTC (permalink / raw)
To: linux-btrfs; +Cc: Sweet Tea Dorminy
From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Recapitulates relevant parts of kernel change 'btrfs: add inode
encryption contexts'.
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
kernel-shared/uapi/btrfs_tree.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
index f49ae534..37869fea 100644
--- a/kernel-shared/uapi/btrfs_tree.h
+++ b/kernel-shared/uapi/btrfs_tree.h
@@ -162,6 +162,8 @@
#define BTRFS_VERITY_DESC_ITEM_KEY 36
#define BTRFS_VERITY_MERKLE_ITEM_KEY 37
+#define BTRFS_FSCRYPT_CTXT_ITEM_KEY 41
+
#define BTRFS_ORPHAN_ITEM_KEY 48
/* reserve 2-15 close to the inode for later flexibility */
@@ -400,6 +402,7 @@ static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags)
#define BTRFS_INODE_NOATIME (1U << 9)
#define BTRFS_INODE_DIRSYNC (1U << 10)
#define BTRFS_INODE_COMPRESS (1U << 11)
+#define BTRFS_INODE_ENCRYPT (1U << 12)
#define BTRFS_INODE_ROOT_ITEM_INIT (1U << 31)
@@ -416,6 +419,7 @@ static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags)
BTRFS_INODE_NOATIME | \
BTRFS_INODE_DIRSYNC | \
BTRFS_INODE_COMPRESS | \
+ BTRFS_INODE_ENCRYPT | \
BTRFS_INODE_ROOT_ITEM_INIT)
#define BTRFS_INODE_RO_VERITY (1U << 0)
--
2.41.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 0/8] btrfs-progs: fscrypt updates
@ 2025-10-15 12:11 Daniel Vacek
2025-10-15 12:11 ` [PATCH 1/8] btrfs-progs: check: fix max inline extent size Daniel Vacek
` (10 more replies)
0 siblings, 11 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-10-15 12:11 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs, Daniel Vacek, Josef Bacik, Sweet Tea Dorminy
This series is a rebase of an older set of fscrypt related changes from
Sweet Tea Dorminy and Josef Bacik found here:
https://github.com/josefbacik/btrfs-progs/tree/fscrypt
The only difference is dropping of commit 56b7131 ("btrfs-progs: escape
unprintable characters in names") and a bit of code style changes.
The mentioned commit is no longer needed as a similar change was already
merged with commit ef7319362 ("btrfs-progs: dump-tree: escape special
characters in paths or xattrs").
I just had to add one trivial fixup so that the fstests could parse the
output correctly.
Daniel Vacek (1):
btrfs-progs: string-utils: do not escape space while printing
Josef Bacik (1):
btrfs-progs: check: fix max inline extent size
Sweet Tea Dorminy (6):
btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag
btrfs-progs: start tracking extent encryption context info
btrfs-progs: add inode encryption contexts
btrfs-progs: interpret encrypted file extents.
btrfs-progs: handle fscrypt context items
btrfs-progs: check: update inline extent length checking
check/main.c | 36 ++++++++++--------
common/string-utils.c | 1 -
kernel-shared/accessors.h | 43 ++++++++++++++++++++++
kernel-shared/ctree.h | 3 +-
kernel-shared/print-tree.c | 41 +++++++++++++++++++++
kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
kernel-shared/uapi/btrfs.h | 1 +
kernel-shared/uapi/btrfs_tree.h | 27 +++++++++++++-
8 files changed, 186 insertions(+), 31 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 1/8] btrfs-progs: check: fix max inline extent size
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
@ 2025-10-15 12:11 ` Daniel Vacek
2025-10-15 12:11 ` [PATCH 2/8] btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag Daniel Vacek
` (9 subsequent siblings)
10 siblings, 0 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-10-15 12:11 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs, Daniel Vacek, Josef Bacik, Sweet Tea Dorminy
From: Josef Bacik <josef@toxicpanda.com>
Fscrypt will use our entire inline extent range for symlinks, which
uncovered a bug in btrfs check where we set the maximum inline extent
size to
min(sectorsize - 1, BTRFS_MAX_INLINE_DATA_SIZE)
which isn't correct, we have always allowed sectorsize sized inline
extents, so fix check to use the correct maximum inline extent size.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
check/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/check/main.c b/check/main.c
index 91ce6d74..054a22d3 100644
--- a/check/main.c
+++ b/check/main.c
@@ -1719,7 +1719,7 @@ static int process_file_extent(struct btrfs_root *root,
u64 disk_bytenr = 0;
u64 extent_offset = 0;
u64 mask = gfs_info->sectorsize - 1;
- u32 max_inline_size = min_t(u32, mask,
+ u32 max_inline_size = min_t(u32, gfs_info->sectorsize,
BTRFS_MAX_INLINE_DATA_SIZE(gfs_info));
u8 compression;
int extent_type;
--
2.51.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 2/8] btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
2025-10-15 12:11 ` [PATCH 1/8] btrfs-progs: check: fix max inline extent size Daniel Vacek
@ 2025-10-15 12:11 ` Daniel Vacek
2025-10-24 21:16 ` David Sterba
2025-10-15 12:11 ` [PATCH 3/8] btrfs-progs: start tracking extent encryption context info Daniel Vacek
` (8 subsequent siblings)
10 siblings, 1 reply; 34+ messages in thread
From: Daniel Vacek @ 2025-10-15 12:11 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs, Daniel Vacek, Josef Bacik, Sweet Tea Dorminy
From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Matches kernel change by the same name.
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
kernel-shared/ctree.h | 3 ++-
kernel-shared/uapi/btrfs.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
index b08e078b..ccd39813 100644
--- a/kernel-shared/ctree.h
+++ b/kernel-shared/ctree.h
@@ -102,7 +102,8 @@ static inline u32 __BTRFS_LEAF_DATA_SIZE(u32 nodesize)
BTRFS_FEATURE_INCOMPAT_ZONED | \
BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 | \
BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE | \
- BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA)
+ BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA | \
+ BTRFS_FEATURE_INCOMPAT_ENCRYPT)
#else
#define BTRFS_FEATURE_INCOMPAT_SUPP \
(BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
diff --git a/kernel-shared/uapi/btrfs.h b/kernel-shared/uapi/btrfs.h
index d6eb4fb4..79963870 100644
--- a/kernel-shared/uapi/btrfs.h
+++ b/kernel-shared/uapi/btrfs.h
@@ -359,6 +359,7 @@ _static_assert(sizeof(struct btrfs_ioctl_fs_info_args) == 1024);
#define BTRFS_FEATURE_INCOMPAT_ZONED (1ULL << 12)
#define BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 (1ULL << 13)
#define BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE (1ULL << 14)
+#define BTRFS_FEATURE_INCOMPAT_ENCRYPT (1ULL << 15)
#define BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA (1ULL << 16)
struct btrfs_ioctl_feature_flags {
--
2.51.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 3/8] btrfs-progs: start tracking extent encryption context info
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
2025-10-15 12:11 ` [PATCH 1/8] btrfs-progs: check: fix max inline extent size Daniel Vacek
2025-10-15 12:11 ` [PATCH 2/8] btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag Daniel Vacek
@ 2025-10-15 12:11 ` Daniel Vacek
2025-10-24 21:29 ` David Sterba
2025-10-15 12:11 ` [PATCH 4/8] btrfs-progs: add inode encryption contexts Daniel Vacek
` (7 subsequent siblings)
10 siblings, 1 reply; 34+ messages in thread
From: Daniel Vacek @ 2025-10-15 12:11 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs, Daniel Vacek, Josef Bacik, Sweet Tea Dorminy
From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
This recapitulates the kernel change named 'btrfs: start tracking extent
encryption context info".
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
kernel-shared/accessors.h | 43 ++++++++++++++++++++++
kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
kernel-shared/uapi/btrfs_tree.h | 23 +++++++++++-
3 files changed, 118 insertions(+), 13 deletions(-)
diff --git a/kernel-shared/accessors.h b/kernel-shared/accessors.h
index cb96f3e2..5d90be76 100644
--- a/kernel-shared/accessors.h
+++ b/kernel-shared/accessors.h
@@ -935,6 +935,9 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
nr_global_roots, 64);
+/* struct btrfs_file_extent_encryption_info */
+BTRFS_SETGET_FUNCS(encryption_info_size, struct btrfs_encryption_info, size, 32);
+
/* struct btrfs_file_extent_item */
BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
type, 8);
@@ -973,6 +976,46 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
other_encoding, 16);
+static inline struct btrfs_encryption_info *btrfs_file_extent_encryption_info(
+ const struct btrfs_file_extent_item *ei)
+{
+ unsigned long offset = (unsigned long)ei;
+
+ offset += offsetof(struct btrfs_file_extent_item, encryption_info);
+ return (struct btrfs_encryption_info *)offset;
+}
+
+static inline unsigned long btrfs_file_extent_encryption_ctx_offset(
+ const struct btrfs_file_extent_item *ei)
+{
+ unsigned long offset = (unsigned long)ei;
+
+ offset += offsetof(struct btrfs_file_extent_item, encryption_info);
+ return offset + offsetof(struct btrfs_encryption_info, context);
+}
+
+static inline u32 btrfs_file_extent_encryption_ctx_size(
+ const struct extent_buffer *eb,
+ const struct btrfs_file_extent_item *ei)
+{
+ return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
+}
+
+static inline void btrfs_set_file_extent_encryption_ctx_size(
+ struct extent_buffer *eb,
+ struct btrfs_file_extent_item *ei,
+ u32 val)
+{
+ btrfs_set_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei), val);
+}
+
+static inline u32 btrfs_file_extent_encryption_info_size(
+ const struct extent_buffer *eb,
+ const struct btrfs_file_extent_item *ei)
+{
+ return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
+}
+
/* btrfs_qgroup_status_item */
BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
generation, 64);
diff --git a/kernel-shared/tree-checker.c b/kernel-shared/tree-checker.c
index ccc1f1ea..93073979 100644
--- a/kernel-shared/tree-checker.c
+++ b/kernel-shared/tree-checker.c
@@ -242,6 +242,8 @@ static int check_extent_data_item(struct extent_buffer *leaf,
u32 sectorsize = fs_info->sectorsize;
u32 item_size = btrfs_item_size(leaf, slot);
u64 extent_end;
+ u8 policy;
+ u8 fe_type;
if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
file_extent_err(leaf, slot,
@@ -272,12 +274,12 @@ static int check_extent_data_item(struct extent_buffer *leaf,
SZ_4K);
return -EUCLEAN;
}
- if (unlikely(btrfs_file_extent_type(leaf, fi) >=
- BTRFS_NR_FILE_EXTENT_TYPES)) {
+
+ fe_type = btrfs_file_extent_type(leaf, fi);
+ if (unlikely(fe_type >= BTRFS_NR_FILE_EXTENT_TYPES)) {
file_extent_err(leaf, slot,
"invalid type for file extent, have %u expect range [0, %u]",
- btrfs_file_extent_type(leaf, fi),
- BTRFS_NR_FILE_EXTENT_TYPES - 1);
+ fe_type, BTRFS_NR_FILE_EXTENT_TYPES - 1);
return -EUCLEAN;
}
@@ -293,10 +295,11 @@ static int check_extent_data_item(struct extent_buffer *leaf,
BTRFS_NR_COMPRESS_TYPES - 1);
return -EUCLEAN;
}
- if (unlikely(btrfs_file_extent_encryption(leaf, fi))) {
+ policy = btrfs_file_extent_encryption(leaf, fi);
+ if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) {
file_extent_err(leaf, slot,
- "invalid encryption for file extent, have %u expect 0",
- btrfs_file_extent_encryption(leaf, fi));
+ "invalid encryption for file extent, have %u expect range [0, %u]",
+ policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
return -EUCLEAN;
}
if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
@@ -325,12 +328,50 @@ static int check_extent_data_item(struct extent_buffer *leaf,
return 0;
}
- /* Regular or preallocated extent has fixed item size */
- if (unlikely(item_size != sizeof(*fi))) {
- file_extent_err(leaf, slot,
+ if (policy == BTRFS_ENCRYPTION_FSCRYPT) {
+ size_t fe_size = sizeof(*fi) + sizeof(struct btrfs_encryption_info);
+ u32 ctxsize;
+
+ if (unlikely(item_size < fe_size)) {
+ file_extent_err(leaf, slot,
+ "invalid item size for encrypted file extent, have %u expect = %zu + size of u32",
+ item_size, sizeof(*fi));
+ return -EUCLEAN;
+ }
+
+ ctxsize = btrfs_file_extent_encryption_info_size(leaf, fi);
+ if (unlikely(item_size != (fe_size + ctxsize))) {
+ file_extent_err(leaf, slot,
+ "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
+ item_size, fe_size, ctxsize);
+ return -EUCLEAN;
+ }
+
+ if (unlikely(ctxsize > BTRFS_MAX_EXTENT_CTX_SIZE)) {
+ file_extent_err(leaf, slot,
+ "invalid file extent context size, have %u expect a maximum of %u",
+ ctxsize, BTRFS_MAX_EXTENT_CTX_SIZE);
+ return -EUCLEAN;
+ }
+
+ /*
+ * Only regular and prealloc extents should have an encryption
+ * context.
+ */
+ if (unlikely(fe_type != BTRFS_FILE_EXTENT_REG &&
+ fe_type != BTRFS_FILE_EXTENT_PREALLOC)) {
+ file_extent_err(leaf, slot,
+ "invalid type for encrypted file extent, have %u",
+ btrfs_file_extent_type(leaf, fi));
+ return -EUCLEAN;
+ }
+ } else {
+ if (unlikely(item_size != sizeof(*fi))) {
+ file_extent_err(leaf, slot,
"invalid item size for reg/prealloc file extent, have %u expect %zu",
- item_size, sizeof(*fi));
- return -EUCLEAN;
+ item_size, sizeof(*fi));
+ return -EUCLEAN;
+ }
}
if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) ||
CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) ||
diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
index 7f3dffe6..4b4f45aa 100644
--- a/kernel-shared/uapi/btrfs_tree.h
+++ b/kernel-shared/uapi/btrfs_tree.h
@@ -1066,6 +1066,24 @@ enum {
BTRFS_NR_FILE_EXTENT_TYPES = 3,
};
+/*
+ * Currently just the FSCRYPT_SET_CONTEXT_MAX_SIZE, which is larger than the
+ * current extent context size from fscrypt, so this should give us plenty of
+ * breathing room for expansion later.
+ */
+#define BTRFS_MAX_EXTENT_CTX_SIZE 40
+
+enum {
+ BTRFS_ENCRYPTION_NONE,
+ BTRFS_ENCRYPTION_FSCRYPT,
+ BTRFS_NR_ENCRYPTION_TYPES,
+};
+
+struct btrfs_encryption_info {
+ __le32 size;
+ __u8 context[0];
+};
+
struct btrfs_file_extent_item {
/*
* transaction id that created this extent
@@ -1115,7 +1133,10 @@ struct btrfs_file_extent_item {
* always reflects the size uncompressed and without encoding.
*/
__le64 num_bytes;
-
+ /*
+ * the encryption info, if any
+ */
+ struct btrfs_encryption_info encryption_info[0];
} __attribute__ ((__packed__));
struct btrfs_csum_item {
--
2.51.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 4/8] btrfs-progs: add inode encryption contexts
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
` (2 preceding siblings ...)
2025-10-15 12:11 ` [PATCH 3/8] btrfs-progs: start tracking extent encryption context info Daniel Vacek
@ 2025-10-15 12:11 ` Daniel Vacek
2025-10-15 12:11 ` [PATCH 5/8] btrfs-progs: interpret encrypted file extents Daniel Vacek
` (6 subsequent siblings)
10 siblings, 0 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-10-15 12:11 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs, Daniel Vacek, Josef Bacik, Sweet Tea Dorminy
From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Recapitulates relevant parts of kernel change 'btrfs: add inode
encryption contexts'.
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
kernel-shared/uapi/btrfs_tree.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
index 4b4f45aa..e3a55665 100644
--- a/kernel-shared/uapi/btrfs_tree.h
+++ b/kernel-shared/uapi/btrfs_tree.h
@@ -165,6 +165,8 @@
#define BTRFS_VERITY_DESC_ITEM_KEY 36
#define BTRFS_VERITY_MERKLE_ITEM_KEY 37
+#define BTRFS_FSCRYPT_CTXT_ITEM_KEY 41
+
#define BTRFS_ORPHAN_ITEM_KEY 48
/* reserve 2-15 close to the inode for later flexibility */
@@ -425,6 +427,7 @@ static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags)
#define BTRFS_INODE_NOATIME (1U << 9)
#define BTRFS_INODE_DIRSYNC (1U << 10)
#define BTRFS_INODE_COMPRESS (1U << 11)
+#define BTRFS_INODE_ENCRYPT (1U << 12)
#define BTRFS_INODE_ROOT_ITEM_INIT (1U << 31)
@@ -441,6 +444,7 @@ static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags)
BTRFS_INODE_NOATIME | \
BTRFS_INODE_DIRSYNC | \
BTRFS_INODE_COMPRESS | \
+ BTRFS_INODE_ENCRYPT | \
BTRFS_INODE_ROOT_ITEM_INIT)
#define BTRFS_INODE_RO_VERITY (1U << 0)
--
2.51.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 5/8] btrfs-progs: interpret encrypted file extents.
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
` (3 preceding siblings ...)
2025-10-15 12:11 ` [PATCH 4/8] btrfs-progs: add inode encryption contexts Daniel Vacek
@ 2025-10-15 12:11 ` Daniel Vacek
2025-11-02 22:26 ` Qu Wenruo
2025-10-15 12:11 ` [PATCH 6/8] btrfs-progs: handle fscrypt context items Daniel Vacek
` (5 subsequent siblings)
10 siblings, 1 reply; 34+ messages in thread
From: Daniel Vacek @ 2025-10-15 12:11 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs, Daniel Vacek, Josef Bacik, Sweet Tea Dorminy
From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Encrypted file extents now have the 'encryption' field set to a
encryption type plus a context length, and have an extent context
appended to the item. This necessitates adjusting the struct to have a
variable-length fscrypt_context member at the end, and printing contexts
if one is provided.
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
check/main.c | 10 +++++++---
kernel-shared/print-tree.c | 23 +++++++++++++++++++++++
2 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/check/main.c b/check/main.c
index 054a22d3..d3d65854 100644
--- a/check/main.c
+++ b/check/main.c
@@ -1777,7 +1777,6 @@ static int process_file_extent(struct btrfs_root *root,
rec->errors |= I_ERR_BAD_FILE_EXTENT;
if (extent_type == BTRFS_FILE_EXTENT_PREALLOC &&
(btrfs_file_extent_compression(eb, fi) ||
- btrfs_file_extent_encryption(eb, fi) ||
btrfs_file_extent_other_encoding(eb, fi)))
rec->errors |= I_ERR_BAD_FILE_EXTENT;
if (compression && rec->nodatasum)
@@ -6495,6 +6494,7 @@ static int run_next_block(struct btrfs_root *root,
for (i = 0; i < nritems; i++) {
struct btrfs_file_extent_item *fi;
unsigned long inline_offset;
+ size_t extra_size = 0;
inline_offset = offsetof(struct btrfs_file_extent_item,
disk_bytenr);
@@ -6630,13 +6630,17 @@ static int run_next_block(struct btrfs_root *root,
continue;
/* Prealloc/regular extent must have fixed item size */
+ if (btrfs_file_extent_encryption(buf, fi))
+ extra_size = btrfs_file_extent_encryption_info_size(buf, fi) +
+ sizeof(struct btrfs_encryption_info);
+
if (btrfs_item_size(buf, i) !=
- sizeof(struct btrfs_file_extent_item)) {
+ (sizeof(struct btrfs_file_extent_item) + extra_size)) {
ret = -EUCLEAN;
error(
"invalid file extent item size, have %u expect %zu",
btrfs_item_size(buf, i),
- sizeof(struct btrfs_file_extent_item));
+ sizeof(struct btrfs_file_extent_item) + extra_size);
continue;
}
/* key.offset (file offset) must be aligned */
diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c
index 2a624a1c..060bf997 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -421,6 +421,25 @@ static void compress_type_to_str(u8 compress_type, char *ret)
}
}
+static void generate_encryption_string(struct extent_buffer *leaf,
+ struct btrfs_file_extent_item *fi,
+ char *ret)
+{
+ u8 policy = btrfs_file_extent_encryption(leaf, fi);
+ u32 ctxsize = btrfs_file_extent_encryption_ctx_size(leaf, fi);
+ const __u8 *ctx = (__u8 *)(leaf->data + btrfs_file_extent_encryption_ctx_offset(fi));
+
+ ret += sprintf(ret, "(%hhu, %u", policy, ctxsize);
+
+ if (ctxsize) {
+ int i;
+ ret += sprintf(ret, ": context ");
+ for (i = 0; i < ctxsize; i++)
+ ret += sprintf(ret, "%02hhx", ctx[i]);
+ }
+ sprintf(ret, ")");
+}
+
static const char* file_extent_type_to_str(u8 type)
{
switch (type) {
@@ -437,9 +456,11 @@ static void print_file_extent_item(struct extent_buffer *eb,
{
unsigned char extent_type = btrfs_file_extent_type(eb, fi);
char compress_str[16];
+ char encrypt_str[16];
compress_type_to_str(btrfs_file_extent_compression(eb, fi),
compress_str);
+ generate_encryption_string(eb, fi, encrypt_str);
printf("\t\tgeneration %llu type %hhu (%s)\n",
btrfs_file_extent_generation(eb, fi),
@@ -472,6 +493,8 @@ static void print_file_extent_item(struct extent_buffer *eb,
printf("\t\textent compression %hhu (%s)\n",
btrfs_file_extent_compression(eb, fi),
compress_str);
+ printf("\t\textent encryption %hhu (%s)\n",
+ btrfs_file_extent_encryption(eb, fi), encrypt_str);
}
/* Caller should ensure sizeof(*ret) >= 16("DATA|TREE_BLOCK") */
--
2.51.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 6/8] btrfs-progs: handle fscrypt context items
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
` (4 preceding siblings ...)
2025-10-15 12:11 ` [PATCH 5/8] btrfs-progs: interpret encrypted file extents Daniel Vacek
@ 2025-10-15 12:11 ` Daniel Vacek
2025-10-15 12:11 ` [PATCH 7/8] btrfs-progs: check: update inline extent length checking Daniel Vacek
` (4 subsequent siblings)
10 siblings, 0 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-10-15 12:11 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs, Daniel Vacek, Josef Bacik, Sweet Tea Dorminy
From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Encrypted inodes have a new associated item, the fscrypt context, which
can be printed as a pure hex string in dump-tree.
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
kernel-shared/print-tree.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c
index 060bf997..cde07ab1 100644
--- a/kernel-shared/print-tree.c
+++ b/kernel-shared/print-tree.c
@@ -117,6 +117,20 @@ static void print_dir_item(struct extent_buffer *eb, u32 size,
}
}
+static void print_fscrypt_context(struct extent_buffer *eb, int slot)
+{
+ int i;
+ unsigned long ptr = btrfs_item_ptr_offset(eb, slot);
+ u32 item_size = btrfs_item_size(eb, slot);
+ u8 ctx_buf[item_size];
+
+ read_extent_buffer(eb, ctx_buf, ptr, item_size);
+ printf("\t\tvalue: ");
+ for(i = 0; i < item_size; i++)
+ printf("%02x", ctx_buf[i]);
+ printf("\n");
+}
+
static void print_inode_extref_item(struct extent_buffer *eb, u32 size,
struct btrfs_inode_extref *extref)
{
@@ -756,6 +770,7 @@ void print_key_type(FILE *stream, u64 objectid, u8 type)
[BTRFS_DIR_LOG_ITEM_KEY] = "DIR_LOG_ITEM",
[BTRFS_DIR_LOG_INDEX_KEY] = "DIR_LOG_INDEX",
[BTRFS_XATTR_ITEM_KEY] = "XATTR_ITEM",
+ [BTRFS_FSCRYPT_CTXT_ITEM_KEY] = "FSCRYPT_CTXT_ITEM",
[BTRFS_VERITY_DESC_ITEM_KEY] = "VERITY_DESC_ITEM",
[BTRFS_VERITY_MERKLE_ITEM_KEY] = "VERITY_MERKLE_ITEM",
[BTRFS_ORPHAN_ITEM_KEY] = "ORPHAN_ITEM",
@@ -1566,6 +1581,9 @@ void __btrfs_print_leaf(struct extent_buffer *eb, unsigned int mode)
case BTRFS_XATTR_ITEM_KEY:
print_dir_item(eb, item_size, ptr);
break;
+ case BTRFS_FSCRYPT_CTXT_ITEM_KEY:
+ print_fscrypt_context(eb, i);
+ break;
case BTRFS_DIR_LOG_INDEX_KEY:
case BTRFS_DIR_LOG_ITEM_KEY: {
struct btrfs_dir_log_item *dlog;
--
2.51.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 7/8] btrfs-progs: check: update inline extent length checking
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
` (5 preceding siblings ...)
2025-10-15 12:11 ` [PATCH 6/8] btrfs-progs: handle fscrypt context items Daniel Vacek
@ 2025-10-15 12:11 ` Daniel Vacek
2025-10-15 12:11 ` [PATCH 8/8] btrfs-progs: string-utils: do not escape space while printing Daniel Vacek
` (3 subsequent siblings)
10 siblings, 0 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-10-15 12:11 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs, Daniel Vacek, Josef Bacik, Sweet Tea Dorminy
From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
As part of the encryption changes, encrypted inline file extents record
their actual data length in ram_bytes, like compressed inline file
extents, while the item's length records the actual size. As such,
encrypted inline extents must be treated like compressed ones for
inode length consistency checking.
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
check/main.c | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/check/main.c b/check/main.c
index d3d65854..e2ce277c 100644
--- a/check/main.c
+++ b/check/main.c
@@ -1721,7 +1721,7 @@ static int process_file_extent(struct btrfs_root *root,
u64 mask = gfs_info->sectorsize - 1;
u32 max_inline_size = min_t(u32, gfs_info->sectorsize,
BTRFS_MAX_INLINE_DATA_SIZE(gfs_info));
- u8 compression;
+ u8 compression, encryption;
int extent_type;
int ret;
@@ -1746,25 +1746,25 @@ static int process_file_extent(struct btrfs_root *root,
fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
extent_type = btrfs_file_extent_type(eb, fi);
compression = btrfs_file_extent_compression(eb, fi);
+ encryption = btrfs_file_extent_encryption(eb, fi);
if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
- num_bytes = btrfs_file_extent_ram_bytes(eb, fi);
- if (num_bytes == 0)
+ u64 num_decoded_bytes = btrfs_file_extent_ram_bytes(eb, fi);
+ u64 num_disk_bytes = btrfs_file_extent_inline_item_len(eb, slot);
+ if (num_decoded_bytes == 0)
rec->errors |= I_ERR_BAD_FILE_EXTENT;
- if (compression) {
- if (btrfs_file_extent_inline_item_len(eb, slot) >
- max_inline_size ||
- num_bytes > gfs_info->sectorsize)
+ if (compression || encryption) {
+ if (num_disk_bytes > max_inline_size ||
+ num_decoded_bytes > gfs_info->sectorsize)
rec->errors |= I_ERR_FILE_EXTENT_TOO_LARGE;
} else {
- if (num_bytes > max_inline_size)
+ if (num_decoded_bytes > max_inline_size)
rec->errors |= I_ERR_FILE_EXTENT_TOO_LARGE;
- if (btrfs_file_extent_inline_item_len(eb, slot) !=
- num_bytes)
+ if (num_disk_bytes != num_decoded_bytes)
rec->errors |= I_ERR_INLINE_RAM_BYTES_WRONG;
}
- rec->found_size += num_bytes;
- num_bytes = (num_bytes + mask) & ~mask;
+ rec->found_size += num_decoded_bytes;
+ num_bytes = (num_decoded_bytes + mask) & ~mask;
} else if (extent_type == BTRFS_FILE_EXTENT_REG ||
extent_type == BTRFS_FILE_EXTENT_PREALLOC) {
num_bytes = btrfs_file_extent_num_bytes(eb, fi);
--
2.51.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 8/8] btrfs-progs: string-utils: do not escape space while printing
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
` (6 preceding siblings ...)
2025-10-15 12:11 ` [PATCH 7/8] btrfs-progs: check: update inline extent length checking Daniel Vacek
@ 2025-10-15 12:11 ` Daniel Vacek
2025-10-17 16:43 ` David Sterba
2025-10-15 21:10 ` [PATCH 0/8] btrfs-progs: fscrypt updates Qu Wenruo
` (2 subsequent siblings)
10 siblings, 1 reply; 34+ messages in thread
From: Daniel Vacek @ 2025-10-15 12:11 UTC (permalink / raw)
To: David Sterba; +Cc: linux-btrfs, Daniel Vacek, Josef Bacik, Sweet Tea Dorminy
Space is a valid printable character in C. On the other hand
string "\ " in fact results in an unknown escape sequence.
Fixes: 637563be ("btrfs-progs: send dump: introduce helper for printing escaped path")
Signed-off-by: Daniel Vacek <neelx@suse.com>
---
common/string-utils.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/common/string-utils.c b/common/string-utils.c
index e55c10c5..794639a0 100644
--- a/common/string-utils.c
+++ b/common/string-utils.c
@@ -88,7 +88,6 @@ int string_print_escape_special_len(const char *str, size_t str_len)
case '\r': putchar('\\'); putchar('r'); len++; break;
case '\t': putchar('\\'); putchar('t'); len++; break;
case '\v': putchar('\\'); putchar('v'); len++; break;
- case ' ': putchar('\\'); putchar(' '); len++; break;
case '\\': putchar('\\'); putchar('\\'); len++; break;
default:
if (!isprint(c)) {
--
2.51.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH 0/8] btrfs-progs: fscrypt updates
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
` (7 preceding siblings ...)
2025-10-15 12:11 ` [PATCH 8/8] btrfs-progs: string-utils: do not escape space while printing Daniel Vacek
@ 2025-10-15 21:10 ` Qu Wenruo
2025-10-15 21:19 ` Daniel Vacek
2025-10-17 20:54 ` Mark Harmstone
2025-10-17 16:45 ` David Sterba
2025-11-04 14:56 ` David Sterba
10 siblings, 2 replies; 34+ messages in thread
From: Qu Wenruo @ 2025-10-15 21:10 UTC (permalink / raw)
To: Daniel Vacek, David Sterba; +Cc: linux-btrfs, Josef Bacik, Sweet Tea Dorminy
在 2025/10/15 22:41, Daniel Vacek 写道:
> This series is a rebase of an older set of fscrypt related changes from
> Sweet Tea Dorminy and Josef Bacik found here:
> https://github.com/josefbacik/btrfs-progs/tree/fscrypt
I'm wondering if encryption (fscrypt) for btrfs is still being pushed.
IIRC meta has given up the effort to push for this feature.
Thanks,
Qu
>
> The only difference is dropping of commit 56b7131 ("btrfs-progs: escape
> unprintable characters in names") and a bit of code style changes.
>
> The mentioned commit is no longer needed as a similar change was already
> merged with commit ef7319362 ("btrfs-progs: dump-tree: escape special
> characters in paths or xattrs").
>
> I just had to add one trivial fixup so that the fstests could parse the
> output correctly.
>
> Daniel Vacek (1):
> btrfs-progs: string-utils: do not escape space while printing
>
> Josef Bacik (1):
> btrfs-progs: check: fix max inline extent size
>
> Sweet Tea Dorminy (6):
> btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag
> btrfs-progs: start tracking extent encryption context info
> btrfs-progs: add inode encryption contexts
> btrfs-progs: interpret encrypted file extents.
> btrfs-progs: handle fscrypt context items
> btrfs-progs: check: update inline extent length checking
>
> check/main.c | 36 ++++++++++--------
> common/string-utils.c | 1 -
> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
> kernel-shared/ctree.h | 3 +-
> kernel-shared/print-tree.c | 41 +++++++++++++++++++++
> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
> kernel-shared/uapi/btrfs.h | 1 +
> kernel-shared/uapi/btrfs_tree.h | 27 +++++++++++++-
> 8 files changed, 186 insertions(+), 31 deletions(-)
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 0/8] btrfs-progs: fscrypt updates
2025-10-15 21:10 ` [PATCH 0/8] btrfs-progs: fscrypt updates Qu Wenruo
@ 2025-10-15 21:19 ` Daniel Vacek
2025-10-15 21:20 ` Qu Wenruo
2025-10-16 15:16 ` Johannes Thumshirn
2025-10-17 20:54 ` Mark Harmstone
1 sibling, 2 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-10-15 21:19 UTC (permalink / raw)
To: Qu Wenruo; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Wed, 15 Oct 2025 at 23:10, Qu Wenruo <quwenruo.btrfs@gmx.com> wrote:
>
>
>
> 在 2025/10/15 22:41, Daniel Vacek 写道:
> > This series is a rebase of an older set of fscrypt related changes from
> > Sweet Tea Dorminy and Josef Bacik found here:
> > https://github.com/josefbacik/btrfs-progs/tree/fscrypt
>
> I'm wondering if encryption (fscrypt) for btrfs is still being pushed.
> IIRC meta has given up the effort to push for this feature.
Yeah, I'm trying to finish it. This is part of the effort.
--nX
> Thanks,
> Qu
>
> >
> > The only difference is dropping of commit 56b7131 ("btrfs-progs: escape
> > unprintable characters in names") and a bit of code style changes.
> >
> > The mentioned commit is no longer needed as a similar change was already
> > merged with commit ef7319362 ("btrfs-progs: dump-tree: escape special
> > characters in paths or xattrs").
> >
> > I just had to add one trivial fixup so that the fstests could parse the
> > output correctly.
> >
> > Daniel Vacek (1):
> > btrfs-progs: string-utils: do not escape space while printing
> >
> > Josef Bacik (1):
> > btrfs-progs: check: fix max inline extent size
> >
> > Sweet Tea Dorminy (6):
> > btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag
> > btrfs-progs: start tracking extent encryption context info
> > btrfs-progs: add inode encryption contexts
> > btrfs-progs: interpret encrypted file extents.
> > btrfs-progs: handle fscrypt context items
> > btrfs-progs: check: update inline extent length checking
> >
> > check/main.c | 36 ++++++++++--------
> > common/string-utils.c | 1 -
> > kernel-shared/accessors.h | 43 ++++++++++++++++++++++
> > kernel-shared/ctree.h | 3 +-
> > kernel-shared/print-tree.c | 41 +++++++++++++++++++++
> > kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
> > kernel-shared/uapi/btrfs.h | 1 +
> > kernel-shared/uapi/btrfs_tree.h | 27 +++++++++++++-
> > 8 files changed, 186 insertions(+), 31 deletions(-)
> >
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 0/8] btrfs-progs: fscrypt updates
2025-10-15 21:19 ` Daniel Vacek
@ 2025-10-15 21:20 ` Qu Wenruo
2025-10-16 15:16 ` Johannes Thumshirn
1 sibling, 0 replies; 34+ messages in thread
From: Qu Wenruo @ 2025-10-15 21:20 UTC (permalink / raw)
To: Daniel Vacek, Qu Wenruo
Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
在 2025/10/16 07:49, Daniel Vacek 写道:
> On Wed, 15 Oct 2025 at 23:10, Qu Wenruo <quwenruo.btrfs@gmx.com> wrote:
>>
>>
>>
>> 在 2025/10/15 22:41, Daniel Vacek 写道:
>>> This series is a rebase of an older set of fscrypt related changes from
>>> Sweet Tea Dorminy and Josef Bacik found here:
>>> https://github.com/josefbacik/btrfs-progs/tree/fscrypt
>>
>> I'm wondering if encryption (fscrypt) for btrfs is still being pushed.
>> IIRC meta has given up the effort to push for this feature.
>
> Yeah, I'm trying to finish it. This is part of the effort.
Oh, that's awesome and great to know.
Thanks,
Qu
>
> --nX
>
>> Thanks,
>> Qu
>>
>>>
>>> The only difference is dropping of commit 56b7131 ("btrfs-progs: escape
>>> unprintable characters in names") and a bit of code style changes.
>>>
>>> The mentioned commit is no longer needed as a similar change was already
>>> merged with commit ef7319362 ("btrfs-progs: dump-tree: escape special
>>> characters in paths or xattrs").
>>>
>>> I just had to add one trivial fixup so that the fstests could parse the
>>> output correctly.
>>>
>>> Daniel Vacek (1):
>>> btrfs-progs: string-utils: do not escape space while printing
>>>
>>> Josef Bacik (1):
>>> btrfs-progs: check: fix max inline extent size
>>>
>>> Sweet Tea Dorminy (6):
>>> btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag
>>> btrfs-progs: start tracking extent encryption context info
>>> btrfs-progs: add inode encryption contexts
>>> btrfs-progs: interpret encrypted file extents.
>>> btrfs-progs: handle fscrypt context items
>>> btrfs-progs: check: update inline extent length checking
>>>
>>> check/main.c | 36 ++++++++++--------
>>> common/string-utils.c | 1 -
>>> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
>>> kernel-shared/ctree.h | 3 +-
>>> kernel-shared/print-tree.c | 41 +++++++++++++++++++++
>>> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
>>> kernel-shared/uapi/btrfs.h | 1 +
>>> kernel-shared/uapi/btrfs_tree.h | 27 +++++++++++++-
>>> 8 files changed, 186 insertions(+), 31 deletions(-)
>>>
>>
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 0/8] btrfs-progs: fscrypt updates
2025-10-15 21:19 ` Daniel Vacek
2025-10-15 21:20 ` Qu Wenruo
@ 2025-10-16 15:16 ` Johannes Thumshirn
1 sibling, 0 replies; 34+ messages in thread
From: Johannes Thumshirn @ 2025-10-16 15:16 UTC (permalink / raw)
To: Daniel Vacek, Qu Wenruo
Cc: David Sterba, linux-btrfs@vger.kernel.org, Josef Bacik,
Sweet Tea Dorminy
On 10/15/25 11:19 PM, Daniel Vacek wrote:
> On Wed, 15 Oct 2025 at 23:10, Qu Wenruo <quwenruo.btrfs@gmx.com> wrote:
>>
>>
>> 在 2025/10/15 22:41, Daniel Vacek 写道:
>>> This series is a rebase of an older set of fscrypt related changes from
>>> Sweet Tea Dorminy and Josef Bacik found here:
>>> https://github.com/josefbacik/btrfs-progs/tree/fscrypt
>> I'm wondering if encryption (fscrypt) for btrfs is still being pushed.
>> IIRC meta has given up the effort to push for this feature.
> Yeah, I'm trying to finish it. This is part of the effort.
Awesome!
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 8/8] btrfs-progs: string-utils: do not escape space while printing
2025-10-15 12:11 ` [PATCH 8/8] btrfs-progs: string-utils: do not escape space while printing Daniel Vacek
@ 2025-10-17 16:43 ` David Sterba
2025-10-18 17:50 ` Daniel Vacek
0 siblings, 1 reply; 34+ messages in thread
From: David Sterba @ 2025-10-17 16:43 UTC (permalink / raw)
To: Daniel Vacek; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Wed, Oct 15, 2025 at 02:11:56PM +0200, Daniel Vacek wrote:
> Space is a valid printable character in C. On the other hand
> string "\ " in fact results in an unknown escape sequence.
The space is escaped because the helper is used to print stream dump
or tree dump where space is the separator, so this patch would break it.
Unless there's another reason than esaped space is not valid in C then
we can't do that.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 0/8] btrfs-progs: fscrypt updates
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
` (8 preceding siblings ...)
2025-10-15 21:10 ` [PATCH 0/8] btrfs-progs: fscrypt updates Qu Wenruo
@ 2025-10-17 16:45 ` David Sterba
2025-10-18 18:01 ` Daniel Vacek
2025-11-04 14:56 ` David Sterba
10 siblings, 1 reply; 34+ messages in thread
From: David Sterba @ 2025-10-17 16:45 UTC (permalink / raw)
To: Daniel Vacek; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Wed, Oct 15, 2025 at 02:11:48PM +0200, Daniel Vacek wrote:
> This series is a rebase of an older set of fscrypt related changes from
> Sweet Tea Dorminy and Josef Bacik found here:
> https://github.com/josefbacik/btrfs-progs/tree/fscrypt
>
> The only difference is dropping of commit 56b7131 ("btrfs-progs: escape
> unprintable characters in names") and a bit of code style changes.
>
> The mentioned commit is no longer needed as a similar change was already
> merged with commit ef7319362 ("btrfs-progs: dump-tree: escape special
> characters in paths or xattrs").
>
> I just had to add one trivial fixup so that the fstests could parse the
> output correctly.
>
> Daniel Vacek (1):
> btrfs-progs: string-utils: do not escape space while printing
>
> Josef Bacik (1):
> btrfs-progs: check: fix max inline extent size
>
> Sweet Tea Dorminy (6):
> btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag
> btrfs-progs: start tracking extent encryption context info
> btrfs-progs: add inode encryption contexts
> btrfs-progs: interpret encrypted file extents.
> btrfs-progs: handle fscrypt context items
> btrfs-progs: check: update inline extent length checking
>
> check/main.c | 36 ++++++++++--------
> common/string-utils.c | 1 -
> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
> kernel-shared/ctree.h | 3 +-
> kernel-shared/print-tree.c | 41 +++++++++++++++++++++
> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
> kernel-shared/uapi/btrfs.h | 1 +
> kernel-shared/uapi/btrfs_tree.h | 27 +++++++++++++-
> 8 files changed, 186 insertions(+), 31 deletions(-)
Thanks, it's all preparatory stuff so I'll add it to devel. The escaping
may need another look so the fstests don't fail.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 0/8] btrfs-progs: fscrypt updates
2025-10-15 21:10 ` [PATCH 0/8] btrfs-progs: fscrypt updates Qu Wenruo
2025-10-15 21:19 ` Daniel Vacek
@ 2025-10-17 20:54 ` Mark Harmstone
2025-10-24 21:10 ` David Sterba
1 sibling, 1 reply; 34+ messages in thread
From: Mark Harmstone @ 2025-10-17 20:54 UTC (permalink / raw)
To: Qu Wenruo, Daniel Vacek, David Sterba
Cc: linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On 16/10/25 22:10, Qu Wenruo wrote:
>
>
> 在 2025/10/15 22:41, Daniel Vacek 写道:
>> This series is a rebase of an older set of fscrypt related changes from
>> Sweet Tea Dorminy and Josef Bacik found here:
>> https://github.com/josefbacik/btrfs-progs/tree/fscrypt
>
> I'm wondering if encryption (fscrypt) for btrfs is still being pushed.
> IIRC meta has given up the effort to push for this feature.
>
> Thanks,
> Qu
It's come up again recently, it's something I'm intending to look at
when I get the chance.
I'm hoping that remap-tree will make it a lot simpler: extents will have
an address that won't change with relocation, meaning that this fits
more nicely with fscrypt's design. IIRC Sweet Tea's design stores the
nonce/IVs in the extent tree, which wouldn't need to be the case with
remap-tree.
>>
>> The only difference is dropping of commit 56b7131 ("btrfs-progs: escape
>> unprintable characters in names") and a bit of code style changes.
>>
>> The mentioned commit is no longer needed as a similar change was already
>> merged with commit ef7319362 ("btrfs-progs: dump-tree: escape special
>> characters in paths or xattrs").
>>
>> I just had to add one trivial fixup so that the fstests could parse the
>> output correctly.
>>
>> Daniel Vacek (1):
>> btrfs-progs: string-utils: do not escape space while printing
>>
>> Josef Bacik (1):
>> btrfs-progs: check: fix max inline extent size
>>
>> Sweet Tea Dorminy (6):
>> btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag
>> btrfs-progs: start tracking extent encryption context info
>> btrfs-progs: add inode encryption contexts
>> btrfs-progs: interpret encrypted file extents.
>> btrfs-progs: handle fscrypt context items
>> btrfs-progs: check: update inline extent length checking
>>
>> check/main.c | 36 ++++++++++--------
>> common/string-utils.c | 1 -
>> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
>> kernel-shared/ctree.h | 3 +-
>> kernel-shared/print-tree.c | 41 +++++++++++++++++++++
>> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
>> kernel-shared/uapi/btrfs.h | 1 +
>> kernel-shared/uapi/btrfs_tree.h | 27 +++++++++++++-
>> 8 files changed, 186 insertions(+), 31 deletions(-)
>>
>
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 8/8] btrfs-progs: string-utils: do not escape space while printing
2025-10-17 16:43 ` David Sterba
@ 2025-10-18 17:50 ` Daniel Vacek
0 siblings, 0 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-10-18 17:50 UTC (permalink / raw)
To: dsterba; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Fri, 17 Oct 2025 at 18:43, David Sterba <dsterba@suse.cz> wrote:
>
> On Wed, Oct 15, 2025 at 02:11:56PM +0200, Daniel Vacek wrote:
> > Space is a valid printable character in C. On the other hand
> > string "\ " in fact results in an unknown escape sequence.
>
> The space is escaped because the helper is used to print stream dump
> or tree dump where space is the separator, so this patch would break it.
> Unless there's another reason than esaped space is not valid in C then
> we can't do that.
The reason is fstests are parsing the output of dump-tree and failing
on any space in the encrypted filename. That's how I found the bug.
Namely it's the generic/582 checking the encrypted filenames, well the
btrfs part of the test as I implemented it. It's the
get_ciphertext_filename() function in common/encrypt. I went through
several iterations but I could not come up with any better solution.
Hints are welcome here.
Thinking about it again, this is also missing correctly escaping %
into %% which I mangled in fstests. I should have really done it here.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 0/8] btrfs-progs: fscrypt updates
2025-10-17 16:45 ` David Sterba
@ 2025-10-18 18:01 ` Daniel Vacek
0 siblings, 0 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-10-18 18:01 UTC (permalink / raw)
To: dsterba; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Fri, 17 Oct 2025 at 18:45, David Sterba <dsterba@suse.cz> wrote:
>
> On Wed, Oct 15, 2025 at 02:11:48PM +0200, Daniel Vacek wrote:
> > This series is a rebase of an older set of fscrypt related changes from
> > Sweet Tea Dorminy and Josef Bacik found here:
> > https://github.com/josefbacik/btrfs-progs/tree/fscrypt
> >
> > The only difference is dropping of commit 56b7131 ("btrfs-progs: escape
> > unprintable characters in names") and a bit of code style changes.
> >
> > The mentioned commit is no longer needed as a similar change was already
> > merged with commit ef7319362 ("btrfs-progs: dump-tree: escape special
> > characters in paths or xattrs").
> >
> > I just had to add one trivial fixup so that the fstests could parse the
> > output correctly.
> >
> > Daniel Vacek (1):
> > btrfs-progs: string-utils: do not escape space while printing
> >
> > Josef Bacik (1):
> > btrfs-progs: check: fix max inline extent size
> >
> > Sweet Tea Dorminy (6):
> > btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag
> > btrfs-progs: start tracking extent encryption context info
> > btrfs-progs: add inode encryption contexts
> > btrfs-progs: interpret encrypted file extents.
> > btrfs-progs: handle fscrypt context items
> > btrfs-progs: check: update inline extent length checking
> >
> > check/main.c | 36 ++++++++++--------
> > common/string-utils.c | 1 -
> > kernel-shared/accessors.h | 43 ++++++++++++++++++++++
> > kernel-shared/ctree.h | 3 +-
> > kernel-shared/print-tree.c | 41 +++++++++++++++++++++
> > kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
> > kernel-shared/uapi/btrfs.h | 1 +
> > kernel-shared/uapi/btrfs_tree.h | 27 +++++++++++++-
> > 8 files changed, 186 insertions(+), 31 deletions(-)
>
> Thanks, it's all preparatory stuff so I'll add it to devel. The escaping
> may need another look so the fstests don't fail.
fstests may need to be fixed. The escaping is actually needed for
generic/582 to work correctly with btrfs. More details in the other
mail.
I'll double check with fstests again.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 0/8] btrfs-progs: fscrypt updates
2025-10-17 20:54 ` Mark Harmstone
@ 2025-10-24 21:10 ` David Sterba
0 siblings, 0 replies; 34+ messages in thread
From: David Sterba @ 2025-10-24 21:10 UTC (permalink / raw)
To: Mark Harmstone
Cc: Qu Wenruo, Daniel Vacek, David Sterba, linux-btrfs, Josef Bacik,
Sweet Tea Dorminy
On Fri, Oct 17, 2025 at 11:54:53PM +0300, Mark Harmstone wrote:
> On 16/10/25 22:10, Qu Wenruo wrote:
> > 在 2025/10/15 22:41, Daniel Vacek 写道:
> >> This series is a rebase of an older set of fscrypt related changes from
> >> Sweet Tea Dorminy and Josef Bacik found here:
> >> https://github.com/josefbacik/btrfs-progs/tree/fscrypt
> >
> > I'm wondering if encryption (fscrypt) for btrfs is still being pushed.
> > IIRC meta has given up the effort to push for this feature.
>
> It's come up again recently, it's something I'm intending to look at
> when I get the chance.
This is already work in progress, Daniel will send the kernel patches.
> I'm hoping that remap-tree will make it a lot simpler: extents will have
> an address that won't change with relocation, meaning that this fits
> more nicely with fscrypt's design. IIRC Sweet Tea's design stores the
> nonce/IVs in the extent tree, which wouldn't need to be the case with
> remap-tree.
Making fscrypt depend on the remap tree is more difficult as it needs
changes to the underlying structures rather than adding some keys. I'd
rather take the fscrypt independently.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 2/8] btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag
2025-10-15 12:11 ` [PATCH 2/8] btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag Daniel Vacek
@ 2025-10-24 21:16 ` David Sterba
0 siblings, 0 replies; 34+ messages in thread
From: David Sterba @ 2025-10-24 21:16 UTC (permalink / raw)
To: Daniel Vacek; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Wed, Oct 15, 2025 at 02:11:50PM +0200, Daniel Vacek wrote:
> From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
>
> Matches kernel change by the same name.
>
> Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> ---
> kernel-shared/ctree.h | 3 ++-
> kernel-shared/uapi/btrfs.h | 1 +
> 2 files changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h
> index b08e078b..ccd39813 100644
> --- a/kernel-shared/ctree.h
> +++ b/kernel-shared/ctree.h
> @@ -102,7 +102,8 @@ static inline u32 __BTRFS_LEAF_DATA_SIZE(u32 nodesize)
> BTRFS_FEATURE_INCOMPAT_ZONED | \
> BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 | \
> BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE | \
> - BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA)
> + BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA | \
> + BTRFS_FEATURE_INCOMPAT_ENCRYPT)
> #else
> #define BTRFS_FEATURE_INCOMPAT_SUPP \
> (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \
> diff --git a/kernel-shared/uapi/btrfs.h b/kernel-shared/uapi/btrfs.h
> index d6eb4fb4..79963870 100644
> --- a/kernel-shared/uapi/btrfs.h
> +++ b/kernel-shared/uapi/btrfs.h
> @@ -359,6 +359,7 @@ _static_assert(sizeof(struct btrfs_ioctl_fs_info_args) == 1024);
> #define BTRFS_FEATURE_INCOMPAT_ZONED (1ULL << 12)
> #define BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 (1ULL << 13)
> #define BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE (1ULL << 14)
> +#define BTRFS_FEATURE_INCOMPAT_ENCRYPT (1ULL << 15)
This definition has to be added to libbtrfsutil/btrfs.h as well, all the
headers are independent. And this also needs version bump but there's
already anoter change in devel so it's covered.
> #define BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA (1ULL << 16)
>
> struct btrfs_ioctl_feature_flags {
> --
> 2.51.0
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 3/8] btrfs-progs: start tracking extent encryption context info
2025-10-15 12:11 ` [PATCH 3/8] btrfs-progs: start tracking extent encryption context info Daniel Vacek
@ 2025-10-24 21:29 ` David Sterba
2025-10-24 22:43 ` Qu Wenruo
2025-11-05 8:22 ` Daniel Vacek
0 siblings, 2 replies; 34+ messages in thread
From: David Sterba @ 2025-10-24 21:29 UTC (permalink / raw)
To: Daniel Vacek; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Wed, Oct 15, 2025 at 02:11:51PM +0200, Daniel Vacek wrote:
> From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
>
> This recapitulates the kernel change named 'btrfs: start tracking extent
> encryption context info".
>
> Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> ---
> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
> kernel-shared/uapi/btrfs_tree.h | 23 +++++++++++-
> 3 files changed, 118 insertions(+), 13 deletions(-)
>
> diff --git a/kernel-shared/accessors.h b/kernel-shared/accessors.h
> index cb96f3e2..5d90be76 100644
> --- a/kernel-shared/accessors.h
> +++ b/kernel-shared/accessors.h
> @@ -935,6 +935,9 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
> BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
> nr_global_roots, 64);
>
> +/* struct btrfs_file_extent_encryption_info */
> +BTRFS_SETGET_FUNCS(encryption_info_size, struct btrfs_encryption_info, size, 32);
> +
> /* struct btrfs_file_extent_item */
> BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
> type, 8);
> @@ -973,6 +976,46 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
> BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
> other_encoding, 16);
>
> +static inline struct btrfs_encryption_info *btrfs_file_extent_encryption_info(
> + const struct btrfs_file_extent_item *ei)
> +{
> + unsigned long offset = (unsigned long)ei;
> +
> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> + return (struct btrfs_encryption_info *)offset;
> +}
> +
> +static inline unsigned long btrfs_file_extent_encryption_ctx_offset(
> + const struct btrfs_file_extent_item *ei)
> +{
> + unsigned long offset = (unsigned long)ei;
> +
> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> + return offset + offsetof(struct btrfs_encryption_info, context);
> +}
> +
> +static inline u32 btrfs_file_extent_encryption_ctx_size(
> + const struct extent_buffer *eb,
> + const struct btrfs_file_extent_item *ei)
> +{
> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> +}
> +
> +static inline void btrfs_set_file_extent_encryption_ctx_size(
> + struct extent_buffer *eb,
> + struct btrfs_file_extent_item *ei,
> + u32 val)
> +{
> + btrfs_set_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei), val);
> +}
> +
> +static inline u32 btrfs_file_extent_encryption_info_size(
> + const struct extent_buffer *eb,
> + const struct btrfs_file_extent_item *ei)
> +{
> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> +}
> +
> /* btrfs_qgroup_status_item */
> BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
> generation, 64);
> diff --git a/kernel-shared/tree-checker.c b/kernel-shared/tree-checker.c
> index ccc1f1ea..93073979 100644
> --- a/kernel-shared/tree-checker.c
> +++ b/kernel-shared/tree-checker.c
> @@ -242,6 +242,8 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> u32 sectorsize = fs_info->sectorsize;
> u32 item_size = btrfs_item_size(leaf, slot);
> u64 extent_end;
> + u8 policy;
> + u8 fe_type;
>
> if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
> file_extent_err(leaf, slot,
> @@ -272,12 +274,12 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> SZ_4K);
> return -EUCLEAN;
> }
> - if (unlikely(btrfs_file_extent_type(leaf, fi) >=
> - BTRFS_NR_FILE_EXTENT_TYPES)) {
> +
> + fe_type = btrfs_file_extent_type(leaf, fi);
> + if (unlikely(fe_type >= BTRFS_NR_FILE_EXTENT_TYPES)) {
> file_extent_err(leaf, slot,
> "invalid type for file extent, have %u expect range [0, %u]",
> - btrfs_file_extent_type(leaf, fi),
> - BTRFS_NR_FILE_EXTENT_TYPES - 1);
> + fe_type, BTRFS_NR_FILE_EXTENT_TYPES - 1);
> return -EUCLEAN;
> }
>
> @@ -293,10 +295,11 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> BTRFS_NR_COMPRESS_TYPES - 1);
> return -EUCLEAN;
> }
> - if (unlikely(btrfs_file_extent_encryption(leaf, fi))) {
> + policy = btrfs_file_extent_encryption(leaf, fi);
> + if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) {
> file_extent_err(leaf, slot,
> - "invalid encryption for file extent, have %u expect 0",
> - btrfs_file_extent_encryption(leaf, fi));
> + "invalid encryption for file extent, have %u expect range [0, %u]",
> + policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
> return -EUCLEAN;
> }
> if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
> @@ -325,12 +328,50 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> return 0;
> }
>
> - /* Regular or preallocated extent has fixed item size */
> - if (unlikely(item_size != sizeof(*fi))) {
> - file_extent_err(leaf, slot,
> + if (policy == BTRFS_ENCRYPTION_FSCRYPT) {
> + size_t fe_size = sizeof(*fi) + sizeof(struct btrfs_encryption_info);
> + u32 ctxsize;
> +
> + if (unlikely(item_size < fe_size)) {
> + file_extent_err(leaf, slot,
> + "invalid item size for encrypted file extent, have %u expect = %zu + size of u32",
> + item_size, sizeof(*fi));
> + return -EUCLEAN;
> + }
> +
> + ctxsize = btrfs_file_extent_encryption_info_size(leaf, fi);
> + if (unlikely(item_size != (fe_size + ctxsize))) {
> + file_extent_err(leaf, slot,
> + "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
> + item_size, fe_size, ctxsize);
> + return -EUCLEAN;
> + }
> +
> + if (unlikely(ctxsize > BTRFS_MAX_EXTENT_CTX_SIZE)) {
> + file_extent_err(leaf, slot,
> + "invalid file extent context size, have %u expect a maximum of %u",
> + ctxsize, BTRFS_MAX_EXTENT_CTX_SIZE);
> + return -EUCLEAN;
> + }
> +
> + /*
> + * Only regular and prealloc extents should have an encryption
> + * context.
> + */
> + if (unlikely(fe_type != BTRFS_FILE_EXTENT_REG &&
> + fe_type != BTRFS_FILE_EXTENT_PREALLOC)) {
> + file_extent_err(leaf, slot,
> + "invalid type for encrypted file extent, have %u",
> + btrfs_file_extent_type(leaf, fi));
> + return -EUCLEAN;
> + }
> + } else {
> + if (unlikely(item_size != sizeof(*fi))) {
> + file_extent_err(leaf, slot,
> "invalid item size for reg/prealloc file extent, have %u expect %zu",
> - item_size, sizeof(*fi));
> - return -EUCLEAN;
> + item_size, sizeof(*fi));
> + return -EUCLEAN;
> + }
> }
> if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) ||
> CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) ||
> diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
> index 7f3dffe6..4b4f45aa 100644
> --- a/kernel-shared/uapi/btrfs_tree.h
> +++ b/kernel-shared/uapi/btrfs_tree.h
> @@ -1066,6 +1066,24 @@ enum {
> BTRFS_NR_FILE_EXTENT_TYPES = 3,
> };
>
> +/*
> + * Currently just the FSCRYPT_SET_CONTEXT_MAX_SIZE, which is larger than the
> + * current extent context size from fscrypt, so this should give us plenty of
> + * breathing room for expansion later.
> + */
> +#define BTRFS_MAX_EXTENT_CTX_SIZE 40
> +
> +enum {
> + BTRFS_ENCRYPTION_NONE,
> + BTRFS_ENCRYPTION_FSCRYPT,
> + BTRFS_NR_ENCRYPTION_TYPES,
> +};
> +
> +struct btrfs_encryption_info {
> + __le32 size;
> + __u8 context[0];
> +};
> +
> struct btrfs_file_extent_item {
> /*
> * transaction id that created this extent
> @@ -1115,7 +1133,10 @@ struct btrfs_file_extent_item {
> * always reflects the size uncompressed and without encoding.
> */
> __le64 num_bytes;
> -
> + /*
> + * the encryption info, if any
> + */
> + struct btrfs_encryption_info encryption_info[0];
Looking at this again, adding variable length data will make it hard to
add more items to the file extent. We could not decide the version just
by the size, as done in other structures.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 3/8] btrfs-progs: start tracking extent encryption context info
2025-10-24 21:29 ` David Sterba
@ 2025-10-24 22:43 ` Qu Wenruo
2025-11-05 8:28 ` Daniel Vacek
2025-11-05 8:22 ` Daniel Vacek
1 sibling, 1 reply; 34+ messages in thread
From: Qu Wenruo @ 2025-10-24 22:43 UTC (permalink / raw)
To: dsterba, Daniel Vacek
Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
在 2025/10/25 07:59, David Sterba 写道:
> On Wed, Oct 15, 2025 at 02:11:51PM +0200, Daniel Vacek wrote:
>> From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
>>
>> This recapitulates the kernel change named 'btrfs: start tracking extent
>> encryption context info".
>>
>> Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
>> ---
>> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
>> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
>> kernel-shared/uapi/btrfs_tree.h | 23 +++++++++++-
>> 3 files changed, 118 insertions(+), 13 deletions(-)
>>
>> diff --git a/kernel-shared/accessors.h b/kernel-shared/accessors.h
>> index cb96f3e2..5d90be76 100644
>> --- a/kernel-shared/accessors.h
>> +++ b/kernel-shared/accessors.h
>> @@ -935,6 +935,9 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
>> BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
>> nr_global_roots, 64);
>>
>> +/* struct btrfs_file_extent_encryption_info */
>> +BTRFS_SETGET_FUNCS(encryption_info_size, struct btrfs_encryption_info, size, 32);
>> +
>> /* struct btrfs_file_extent_item */
>> BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
>> type, 8);
>> @@ -973,6 +976,46 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
>> BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
>> other_encoding, 16);
>>
>> +static inline struct btrfs_encryption_info *btrfs_file_extent_encryption_info(
>> + const struct btrfs_file_extent_item *ei)
>> +{
>> + unsigned long offset = (unsigned long)ei;
>> +
>> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
>> + return (struct btrfs_encryption_info *)offset;
>> +}
>> +
>> +static inline unsigned long btrfs_file_extent_encryption_ctx_offset(
>> + const struct btrfs_file_extent_item *ei)
>> +{
>> + unsigned long offset = (unsigned long)ei;
>> +
>> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
>> + return offset + offsetof(struct btrfs_encryption_info, context);
>> +}
>> +
>> +static inline u32 btrfs_file_extent_encryption_ctx_size(
>> + const struct extent_buffer *eb,
>> + const struct btrfs_file_extent_item *ei)
>> +{
>> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
>> +}
>> +
>> +static inline void btrfs_set_file_extent_encryption_ctx_size(
>> + struct extent_buffer *eb,
>> + struct btrfs_file_extent_item *ei,
>> + u32 val)
>> +{
>> + btrfs_set_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei), val);
>> +}
>> +
>> +static inline u32 btrfs_file_extent_encryption_info_size(
>> + const struct extent_buffer *eb,
>> + const struct btrfs_file_extent_item *ei)
>> +{
>> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
>> +}
>> +
>> /* btrfs_qgroup_status_item */
>> BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
>> generation, 64);
>> diff --git a/kernel-shared/tree-checker.c b/kernel-shared/tree-checker.c
>> index ccc1f1ea..93073979 100644
>> --- a/kernel-shared/tree-checker.c
>> +++ b/kernel-shared/tree-checker.c
>> @@ -242,6 +242,8 @@ static int check_extent_data_item(struct extent_buffer *leaf,
>> u32 sectorsize = fs_info->sectorsize;
>> u32 item_size = btrfs_item_size(leaf, slot);
>> u64 extent_end;
>> + u8 policy;
>> + u8 fe_type;
>>
>> if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
>> file_extent_err(leaf, slot,
>> @@ -272,12 +274,12 @@ static int check_extent_data_item(struct extent_buffer *leaf,
>> SZ_4K);
>> return -EUCLEAN;
>> }
>> - if (unlikely(btrfs_file_extent_type(leaf, fi) >=
>> - BTRFS_NR_FILE_EXTENT_TYPES)) {
>> +
>> + fe_type = btrfs_file_extent_type(leaf, fi);
>> + if (unlikely(fe_type >= BTRFS_NR_FILE_EXTENT_TYPES)) {
>> file_extent_err(leaf, slot,
>> "invalid type for file extent, have %u expect range [0, %u]",
>> - btrfs_file_extent_type(leaf, fi),
>> - BTRFS_NR_FILE_EXTENT_TYPES - 1);
>> + fe_type, BTRFS_NR_FILE_EXTENT_TYPES - 1);
>> return -EUCLEAN;
>> }
>>
>> @@ -293,10 +295,11 @@ static int check_extent_data_item(struct extent_buffer *leaf,
>> BTRFS_NR_COMPRESS_TYPES - 1);
>> return -EUCLEAN;
>> }
>> - if (unlikely(btrfs_file_extent_encryption(leaf, fi))) {
>> + policy = btrfs_file_extent_encryption(leaf, fi);
>> + if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) {
>> file_extent_err(leaf, slot,
>> - "invalid encryption for file extent, have %u expect 0",
>> - btrfs_file_extent_encryption(leaf, fi));
>> + "invalid encryption for file extent, have %u expect range [0, %u]",
>> + policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
>> return -EUCLEAN;
>> }
>> if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
>> @@ -325,12 +328,50 @@ static int check_extent_data_item(struct extent_buffer *leaf,
>> return 0;
>> }
>>
>> - /* Regular or preallocated extent has fixed item size */
>> - if (unlikely(item_size != sizeof(*fi))) {
>> - file_extent_err(leaf, slot,
>> + if (policy == BTRFS_ENCRYPTION_FSCRYPT) {
>> + size_t fe_size = sizeof(*fi) + sizeof(struct btrfs_encryption_info);
>> + u32 ctxsize;
>> +
>> + if (unlikely(item_size < fe_size)) {
>> + file_extent_err(leaf, slot,
>> + "invalid item size for encrypted file extent, have %u expect = %zu + size of u32",
>> + item_size, sizeof(*fi));
>> + return -EUCLEAN;
>> + }
>> +
>> + ctxsize = btrfs_file_extent_encryption_info_size(leaf, fi);
>> + if (unlikely(item_size != (fe_size + ctxsize))) {
>> + file_extent_err(leaf, slot,
>> + "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
>> + item_size, fe_size, ctxsize);
>> + return -EUCLEAN;
>> + }
>> +
>> + if (unlikely(ctxsize > BTRFS_MAX_EXTENT_CTX_SIZE)) {
>> + file_extent_err(leaf, slot,
>> + "invalid file extent context size, have %u expect a maximum of %u",
>> + ctxsize, BTRFS_MAX_EXTENT_CTX_SIZE);
>> + return -EUCLEAN;
>> + }
>> +
>> + /*
>> + * Only regular and prealloc extents should have an encryption
>> + * context.
>> + */
>> + if (unlikely(fe_type != BTRFS_FILE_EXTENT_REG &&
>> + fe_type != BTRFS_FILE_EXTENT_PREALLOC)) {
>> + file_extent_err(leaf, slot,
>> + "invalid type for encrypted file extent, have %u",
>> + btrfs_file_extent_type(leaf, fi));
>> + return -EUCLEAN;
>> + }
>> + } else {
>> + if (unlikely(item_size != sizeof(*fi))) {
>> + file_extent_err(leaf, slot,
>> "invalid item size for reg/prealloc file extent, have %u expect %zu",
>> - item_size, sizeof(*fi));
>> - return -EUCLEAN;
>> + item_size, sizeof(*fi));
>> + return -EUCLEAN;
>> + }
>> }
>> if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) ||
>> CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) ||
>> diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
>> index 7f3dffe6..4b4f45aa 100644
>> --- a/kernel-shared/uapi/btrfs_tree.h
>> +++ b/kernel-shared/uapi/btrfs_tree.h
>> @@ -1066,6 +1066,24 @@ enum {
>> BTRFS_NR_FILE_EXTENT_TYPES = 3,
>> };
>>
>> +/*
>> + * Currently just the FSCRYPT_SET_CONTEXT_MAX_SIZE, which is larger than the
>> + * current extent context size from fscrypt, so this should give us plenty of
>> + * breathing room for expansion later.
>> + */
>> +#define BTRFS_MAX_EXTENT_CTX_SIZE 40
>> +
>> +enum {
>> + BTRFS_ENCRYPTION_NONE,
>> + BTRFS_ENCRYPTION_FSCRYPT,
>> + BTRFS_NR_ENCRYPTION_TYPES,
>> +};
>> +
>> +struct btrfs_encryption_info {
>> + __le32 size;
>> + __u8 context[0];
>> +};
>> +
>> struct btrfs_file_extent_item {
>> /*
>> * transaction id that created this extent
>> @@ -1115,7 +1133,10 @@ struct btrfs_file_extent_item {
>> * always reflects the size uncompressed and without encoding.
>> */
>> __le64 num_bytes;
>> -
>> + /*
>> + * the encryption info, if any
>> + */
>> + struct btrfs_encryption_info encryption_info[0];
>
> Looking at this again, adding variable length data will make it hard to
> add more items to the file extent. We could not decide the version just
> by the size, as done in other structures.
>
Can we put the encryption structure into a dedicated key? Like (ino,
ENCRYPT_KEY, fileoff) key.
By this we gain the ability to grab the size through btrfs_item_size(),
and each file extent item also get their own encryption info.
Thanks,
Qu
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 5/8] btrfs-progs: interpret encrypted file extents.
2025-10-15 12:11 ` [PATCH 5/8] btrfs-progs: interpret encrypted file extents Daniel Vacek
@ 2025-11-02 22:26 ` Qu Wenruo
2025-11-03 9:57 ` Daniel Vacek
0 siblings, 1 reply; 34+ messages in thread
From: Qu Wenruo @ 2025-11-02 22:26 UTC (permalink / raw)
To: Daniel Vacek, David Sterba; +Cc: linux-btrfs, Josef Bacik, Sweet Tea Dorminy
在 2025/10/15 22:41, Daniel Vacek 写道:
> From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
>
> Encrypted file extents now have the 'encryption' field set to a
> encryption type plus a context length, and have an extent context
> appended to the item. This necessitates adjusting the struct to have a
> variable-length fscrypt_context member at the end, and printing contexts
> if one is provided.
Unfortunately this patch will cause CI failures on fuzzed/crafted images.
The most easy way to trigger it is using misc/032 test case from
btrfs-progs.
[...]
> diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c
> index 2a624a1c..060bf997 100644
> --- a/kernel-shared/print-tree.c
> +++ b/kernel-shared/print-tree.c
> @@ -421,6 +421,25 @@ static void compress_type_to_str(u8 compress_type, char *ret)
> }
> }
>
> +static void generate_encryption_string(struct extent_buffer *leaf,
> + struct btrfs_file_extent_item *fi,
> + char *ret)
> +{
> + u8 policy = btrfs_file_extent_encryption(leaf, fi);
> + u32 ctxsize = btrfs_file_extent_encryption_ctx_size(leaf, fi);
This is done without proper checks against current item size.
> + const __u8 *ctx = (__u8 *)(leaf->data + btrfs_file_extent_encryption_ctx_offset(fi));
And this can easily lead to read out of the eb boundary.
Overall we need extra tree-checker for the extra encryption info if we
want to stick to the variable file extent item size idea.
Thus I prefer to put the encryption info into a dedicated key other than
putting it after btrfs_file_extent_item.
So unfortunately I have to remove the series from devel branch for now.
Thanks,
Qu
> +
> + ret += sprintf(ret, "(%hhu, %u", policy, ctxsize);
> +
> + if (ctxsize) {
> + int i;
> + ret += sprintf(ret, ": context ");
> + for (i = 0; i < ctxsize; i++)
> + ret += sprintf(ret, "%02hhx", ctx[i]);
> + }
> + sprintf(ret, ")");
> +}
> +
> static const char* file_extent_type_to_str(u8 type)
> {
> switch (type) {
> @@ -437,9 +456,11 @@ static void print_file_extent_item(struct extent_buffer *eb,
> {
> unsigned char extent_type = btrfs_file_extent_type(eb, fi);
> char compress_str[16];
> + char encrypt_str[16];
>
> compress_type_to_str(btrfs_file_extent_compression(eb, fi),
> compress_str);
> + generate_encryption_string(eb, fi, encrypt_str);
>
> printf("\t\tgeneration %llu type %hhu (%s)\n",
> btrfs_file_extent_generation(eb, fi),
> @@ -472,6 +493,8 @@ static void print_file_extent_item(struct extent_buffer *eb,
> printf("\t\textent compression %hhu (%s)\n",
> btrfs_file_extent_compression(eb, fi),
> compress_str);
> + printf("\t\textent encryption %hhu (%s)\n",
> + btrfs_file_extent_encryption(eb, fi), encrypt_str);
> }
>
> /* Caller should ensure sizeof(*ret) >= 16("DATA|TREE_BLOCK") */
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 5/8] btrfs-progs: interpret encrypted file extents.
2025-11-02 22:26 ` Qu Wenruo
@ 2025-11-03 9:57 ` Daniel Vacek
2025-11-05 7:46 ` Daniel Vacek
0 siblings, 1 reply; 34+ messages in thread
From: Daniel Vacek @ 2025-11-03 9:57 UTC (permalink / raw)
To: Qu Wenruo; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Sun, 2 Nov 2025 at 23:26, Qu Wenruo <wqu@suse.com> wrote:
>
>
>
> 在 2025/10/15 22:41, Daniel Vacek 写道:
> > From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> >
> > Encrypted file extents now have the 'encryption' field set to a
> > encryption type plus a context length, and have an extent context
> > appended to the item. This necessitates adjusting the struct to have a
> > variable-length fscrypt_context member at the end, and printing contexts
> > if one is provided.
>
> Unfortunately this patch will cause CI failures on fuzzed/crafted images.
>
> The most easy way to trigger it is using misc/032 test case from
> btrfs-progs.
> [...]
> > diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c
> > index 2a624a1c..060bf997 100644
> > --- a/kernel-shared/print-tree.c
> > +++ b/kernel-shared/print-tree.c
> > @@ -421,6 +421,25 @@ static void compress_type_to_str(u8 compress_type, char *ret)
> > }
> > }
> >
> > +static void generate_encryption_string(struct extent_buffer *leaf,
> > + struct btrfs_file_extent_item *fi,
> > + char *ret)
> > +{
> > + u8 policy = btrfs_file_extent_encryption(leaf, fi);
> > + u32 ctxsize = btrfs_file_extent_encryption_ctx_size(leaf, fi);
>
> This is done without proper checks against current item size.
>
> > + const __u8 *ctx = (__u8 *)(leaf->data + btrfs_file_extent_encryption_ctx_offset(fi));
>
> And this can easily lead to read out of the eb boundary.
>
> Overall we need extra tree-checker for the extra encryption info if we
> want to stick to the variable file extent item size idea.
>
> Thus I prefer to put the encryption info into a dedicated key other than
> putting it after btrfs_file_extent_item.
Agreed. I'll do that in the next version.
> So unfortunately I have to remove the series from devel branch for now.
>
> Thanks,
> Qu
>
> > +
> > + ret += sprintf(ret, "(%hhu, %u", policy, ctxsize);
> > +
> > + if (ctxsize) {
> > + int i;
> > + ret += sprintf(ret, ": context ");
> > + for (i = 0; i < ctxsize; i++)
> > + ret += sprintf(ret, "%02hhx", ctx[i]);
> > + }
> > + sprintf(ret, ")");
> > +}
> > +
> > static const char* file_extent_type_to_str(u8 type)
> > {
> > switch (type) {
> > @@ -437,9 +456,11 @@ static void print_file_extent_item(struct extent_buffer *eb,
> > {
> > unsigned char extent_type = btrfs_file_extent_type(eb, fi);
> > char compress_str[16];
> > + char encrypt_str[16];
> >
> > compress_type_to_str(btrfs_file_extent_compression(eb, fi),
> > compress_str);
> > + generate_encryption_string(eb, fi, encrypt_str);
> >
> > printf("\t\tgeneration %llu type %hhu (%s)\n",
> > btrfs_file_extent_generation(eb, fi),
> > @@ -472,6 +493,8 @@ static void print_file_extent_item(struct extent_buffer *eb,
> > printf("\t\textent compression %hhu (%s)\n",
> > btrfs_file_extent_compression(eb, fi),
> > compress_str);
> > + printf("\t\textent encryption %hhu (%s)\n",
> > + btrfs_file_extent_encryption(eb, fi), encrypt_str);
> > }
> >
> > /* Caller should ensure sizeof(*ret) >= 16("DATA|TREE_BLOCK") */
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 0/8] btrfs-progs: fscrypt updates
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
` (9 preceding siblings ...)
2025-10-17 16:45 ` David Sterba
@ 2025-11-04 14:56 ` David Sterba
10 siblings, 0 replies; 34+ messages in thread
From: David Sterba @ 2025-11-04 14:56 UTC (permalink / raw)
To: Daniel Vacek; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Wed, Oct 15, 2025 at 02:11:48PM +0200, Daniel Vacek wrote:
> This series is a rebase of an older set of fscrypt related changes from
> Sweet Tea Dorminy and Josef Bacik found here:
> https://github.com/josefbacik/btrfs-progs/tree/fscrypt
>
> The only difference is dropping of commit 56b7131 ("btrfs-progs: escape
> unprintable characters in names") and a bit of code style changes.
>
> The mentioned commit is no longer needed as a similar change was already
> merged with commit ef7319362 ("btrfs-progs: dump-tree: escape special
> characters in paths or xattrs").
>
> I just had to add one trivial fixup so that the fstests could parse the
> output correctly.
>
> Daniel Vacek (1):
> btrfs-progs: string-utils: do not escape space while printing
>
> Josef Bacik (1):
> btrfs-progs: check: fix max inline extent size
>
> Sweet Tea Dorminy (6):
> btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag
> btrfs-progs: start tracking extent encryption context info
> btrfs-progs: add inode encryption contexts
> btrfs-progs: interpret encrypted file extents.
> btrfs-progs: handle fscrypt context items
> btrfs-progs: check: update inline extent length checking
I've added the patches to devel but they fail in the CI so they got
removed again. You can do a test build if you open a pull request.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 5/8] btrfs-progs: interpret encrypted file extents.
2025-11-03 9:57 ` Daniel Vacek
@ 2025-11-05 7:46 ` Daniel Vacek
0 siblings, 0 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-11-05 7:46 UTC (permalink / raw)
To: Qu Wenruo; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Mon, 3 Nov 2025 at 10:57, Daniel Vacek <neelx@suse.com> wrote:
>
> On Sun, 2 Nov 2025 at 23:26, Qu Wenruo <wqu@suse.com> wrote:
> >
> >
> >
> > 在 2025/10/15 22:41, Daniel Vacek 写道:
> > > From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> > >
> > > Encrypted file extents now have the 'encryption' field set to a
> > > encryption type plus a context length, and have an extent context
> > > appended to the item. This necessitates adjusting the struct to have a
> > > variable-length fscrypt_context member at the end, and printing contexts
> > > if one is provided.
> >
> > Unfortunately this patch will cause CI failures on fuzzed/crafted images.
> >
> > The most easy way to trigger it is using misc/032 test case from
> > btrfs-progs.
> > [...]
> > > diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c
> > > index 2a624a1c..060bf997 100644
> > > --- a/kernel-shared/print-tree.c
> > > +++ b/kernel-shared/print-tree.c
> > > @@ -421,6 +421,25 @@ static void compress_type_to_str(u8 compress_type, char *ret)
> > > }
> > > }
> > >
> > > +static void generate_encryption_string(struct extent_buffer *leaf,
> > > + struct btrfs_file_extent_item *fi,
> > > + char *ret)
> > > +{
> > > + u8 policy = btrfs_file_extent_encryption(leaf, fi);
> > > + u32 ctxsize = btrfs_file_extent_encryption_ctx_size(leaf, fi);
> >
> > This is done without proper checks against current item size.
> >
> > > + const __u8 *ctx = (__u8 *)(leaf->data + btrfs_file_extent_encryption_ctx_offset(fi));
> >
> > And this can easily lead to read out of the eb boundary.
> >
> > Overall we need extra tree-checker for the extra encryption info if we
> > want to stick to the variable file extent item size idea.
> >
> > Thus I prefer to put the encryption info into a dedicated key other than
> > putting it after btrfs_file_extent_item.
>
> Agreed. I'll do that in the next version.
Checking details about file extent item, it's already variable size in
case of inline data and the data are stored right after the structure
(more precisely the file data starts in the middle of the structure,
overlapping the members which are unused in case of inline extent -
this way the final item size can end up even shorter than the
btrfs_file_extent_item structure size).
With that respect using the same approach for the encryption context
in case of regular extent seems viable to me.
Validation of the size and offset should be added for sure.
> > So unfortunately I have to remove the series from devel branch for now.
> >
> > Thanks,
> > Qu
> >
> > > +
> > > + ret += sprintf(ret, "(%hhu, %u", policy, ctxsize);
> > > +
> > > + if (ctxsize) {
> > > + int i;
> > > + ret += sprintf(ret, ": context ");
> > > + for (i = 0; i < ctxsize; i++)
> > > + ret += sprintf(ret, "%02hhx", ctx[i]);
> > > + }
> > > + sprintf(ret, ")");
> > > +}
> > > +
> > > static const char* file_extent_type_to_str(u8 type)
> > > {
> > > switch (type) {
> > > @@ -437,9 +456,11 @@ static void print_file_extent_item(struct extent_buffer *eb,
> > > {
> > > unsigned char extent_type = btrfs_file_extent_type(eb, fi);
> > > char compress_str[16];
> > > + char encrypt_str[16];
> > >
> > > compress_type_to_str(btrfs_file_extent_compression(eb, fi),
> > > compress_str);
> > > + generate_encryption_string(eb, fi, encrypt_str);
> > >
> > > printf("\t\tgeneration %llu type %hhu (%s)\n",
> > > btrfs_file_extent_generation(eb, fi),
> > > @@ -472,6 +493,8 @@ static void print_file_extent_item(struct extent_buffer *eb,
> > > printf("\t\textent compression %hhu (%s)\n",
> > > btrfs_file_extent_compression(eb, fi),
> > > compress_str);
> > > + printf("\t\textent encryption %hhu (%s)\n",
> > > + btrfs_file_extent_encryption(eb, fi), encrypt_str);
> > > }
> > >
> > > /* Caller should ensure sizeof(*ret) >= 16("DATA|TREE_BLOCK") */
> >
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 3/8] btrfs-progs: start tracking extent encryption context info
2025-10-24 21:29 ` David Sterba
2025-10-24 22:43 ` Qu Wenruo
@ 2025-11-05 8:22 ` Daniel Vacek
2025-11-05 8:27 ` Daniel Vacek
2025-11-05 9:12 ` Qu Wenruo
1 sibling, 2 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-11-05 8:22 UTC (permalink / raw)
To: dsterba; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Fri, 24 Oct 2025 at 23:29, David Sterba <dsterba@suse.cz> wrote:
>
> On Wed, Oct 15, 2025 at 02:11:51PM +0200, Daniel Vacek wrote:
> > From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> >
> > This recapitulates the kernel change named 'btrfs: start tracking extent
> > encryption context info".
> >
> > Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> > ---
> > kernel-shared/accessors.h | 43 ++++++++++++++++++++++
> > kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
> > kernel-shared/uapi/btrfs_tree.h | 23 +++++++++++-
> > 3 files changed, 118 insertions(+), 13 deletions(-)
> >
> > diff --git a/kernel-shared/accessors.h b/kernel-shared/accessors.h
> > index cb96f3e2..5d90be76 100644
> > --- a/kernel-shared/accessors.h
> > +++ b/kernel-shared/accessors.h
> > @@ -935,6 +935,9 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
> > BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
> > nr_global_roots, 64);
> >
> > +/* struct btrfs_file_extent_encryption_info */
> > +BTRFS_SETGET_FUNCS(encryption_info_size, struct btrfs_encryption_info, size, 32);
> > +
> > /* struct btrfs_file_extent_item */
> > BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
> > type, 8);
> > @@ -973,6 +976,46 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
> > BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
> > other_encoding, 16);
> >
> > +static inline struct btrfs_encryption_info *btrfs_file_extent_encryption_info(
> > + const struct btrfs_file_extent_item *ei)
> > +{
> > + unsigned long offset = (unsigned long)ei;
> > +
> > + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> > + return (struct btrfs_encryption_info *)offset;
> > +}
> > +
> > +static inline unsigned long btrfs_file_extent_encryption_ctx_offset(
> > + const struct btrfs_file_extent_item *ei)
> > +{
> > + unsigned long offset = (unsigned long)ei;
> > +
> > + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> > + return offset + offsetof(struct btrfs_encryption_info, context);
> > +}
> > +
> > +static inline u32 btrfs_file_extent_encryption_ctx_size(
> > + const struct extent_buffer *eb,
> > + const struct btrfs_file_extent_item *ei)
> > +{
> > + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> > +}
> > +
> > +static inline void btrfs_set_file_extent_encryption_ctx_size(
> > + struct extent_buffer *eb,
> > + struct btrfs_file_extent_item *ei,
> > + u32 val)
> > +{
> > + btrfs_set_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei), val);
> > +}
> > +
> > +static inline u32 btrfs_file_extent_encryption_info_size(
> > + const struct extent_buffer *eb,
> > + const struct btrfs_file_extent_item *ei)
> > +{
> > + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> > +}
> > +
> > /* btrfs_qgroup_status_item */
> > BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
> > generation, 64);
> > diff --git a/kernel-shared/tree-checker.c b/kernel-shared/tree-checker.c
> > index ccc1f1ea..93073979 100644
> > --- a/kernel-shared/tree-checker.c
> > +++ b/kernel-shared/tree-checker.c
> > @@ -242,6 +242,8 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > u32 sectorsize = fs_info->sectorsize;
> > u32 item_size = btrfs_item_size(leaf, slot);
> > u64 extent_end;
> > + u8 policy;
> > + u8 fe_type;
> >
> > if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
> > file_extent_err(leaf, slot,
> > @@ -272,12 +274,12 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > SZ_4K);
> > return -EUCLEAN;
> > }
> > - if (unlikely(btrfs_file_extent_type(leaf, fi) >=
> > - BTRFS_NR_FILE_EXTENT_TYPES)) {
> > +
> > + fe_type = btrfs_file_extent_type(leaf, fi);
> > + if (unlikely(fe_type >= BTRFS_NR_FILE_EXTENT_TYPES)) {
> > file_extent_err(leaf, slot,
> > "invalid type for file extent, have %u expect range [0, %u]",
> > - btrfs_file_extent_type(leaf, fi),
> > - BTRFS_NR_FILE_EXTENT_TYPES - 1);
> > + fe_type, BTRFS_NR_FILE_EXTENT_TYPES - 1);
> > return -EUCLEAN;
> > }
> >
> > @@ -293,10 +295,11 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > BTRFS_NR_COMPRESS_TYPES - 1);
> > return -EUCLEAN;
> > }
> > - if (unlikely(btrfs_file_extent_encryption(leaf, fi))) {
> > + policy = btrfs_file_extent_encryption(leaf, fi);
> > + if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) {
> > file_extent_err(leaf, slot,
> > - "invalid encryption for file extent, have %u expect 0",
> > - btrfs_file_extent_encryption(leaf, fi));
> > + "invalid encryption for file extent, have %u expect range [0, %u]",
> > + policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
> > return -EUCLEAN;
> > }
> > if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
> > @@ -325,12 +328,50 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > return 0;
> > }
> >
> > - /* Regular or preallocated extent has fixed item size */
> > - if (unlikely(item_size != sizeof(*fi))) {
> > - file_extent_err(leaf, slot,
> > + if (policy == BTRFS_ENCRYPTION_FSCRYPT) {
> > + size_t fe_size = sizeof(*fi) + sizeof(struct btrfs_encryption_info);
> > + u32 ctxsize;
> > +
> > + if (unlikely(item_size < fe_size)) {
> > + file_extent_err(leaf, slot,
> > + "invalid item size for encrypted file extent, have %u expect = %zu + size of u32",
> > + item_size, sizeof(*fi));
> > + return -EUCLEAN;
> > + }
> > +
> > + ctxsize = btrfs_file_extent_encryption_info_size(leaf, fi);
> > + if (unlikely(item_size != (fe_size + ctxsize))) {
> > + file_extent_err(leaf, slot,
> > + "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
> > + item_size, fe_size, ctxsize);
> > + return -EUCLEAN;
> > + }
> > +
> > + if (unlikely(ctxsize > BTRFS_MAX_EXTENT_CTX_SIZE)) {
> > + file_extent_err(leaf, slot,
> > + "invalid file extent context size, have %u expect a maximum of %u",
> > + ctxsize, BTRFS_MAX_EXTENT_CTX_SIZE);
> > + return -EUCLEAN;
> > + }
> > +
> > + /*
> > + * Only regular and prealloc extents should have an encryption
> > + * context.
> > + */
> > + if (unlikely(fe_type != BTRFS_FILE_EXTENT_REG &&
> > + fe_type != BTRFS_FILE_EXTENT_PREALLOC)) {
> > + file_extent_err(leaf, slot,
> > + "invalid type for encrypted file extent, have %u",
> > + btrfs_file_extent_type(leaf, fi));
> > + return -EUCLEAN;
> > + }
> > + } else {
> > + if (unlikely(item_size != sizeof(*fi))) {
> > + file_extent_err(leaf, slot,
> > "invalid item size for reg/prealloc file extent, have %u expect %zu",
> > - item_size, sizeof(*fi));
> > - return -EUCLEAN;
> > + item_size, sizeof(*fi));
> > + return -EUCLEAN;
> > + }
> > }
> > if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) ||
> > CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) ||
> > diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
> > index 7f3dffe6..4b4f45aa 100644
> > --- a/kernel-shared/uapi/btrfs_tree.h
> > +++ b/kernel-shared/uapi/btrfs_tree.h
> > @@ -1066,6 +1066,24 @@ enum {
> > BTRFS_NR_FILE_EXTENT_TYPES = 3,
> > };
> >
> > +/*
> > + * Currently just the FSCRYPT_SET_CONTEXT_MAX_SIZE, which is larger than the
> > + * current extent context size from fscrypt, so this should give us plenty of
> > + * breathing room for expansion later.
> > + */
> > +#define BTRFS_MAX_EXTENT_CTX_SIZE 40
> > +
> > +enum {
> > + BTRFS_ENCRYPTION_NONE,
> > + BTRFS_ENCRYPTION_FSCRYPT,
> > + BTRFS_NR_ENCRYPTION_TYPES,
> > +};
> > +
> > +struct btrfs_encryption_info {
> > + __le32 size;
> > + __u8 context[0];
> > +};
> > +
> > struct btrfs_file_extent_item {
> > /*
> > * transaction id that created this extent
> > @@ -1115,7 +1133,10 @@ struct btrfs_file_extent_item {
> > * always reflects the size uncompressed and without encoding.
> > */
> > __le64 num_bytes;
> > -
> > + /*
> > + * the encryption info, if any
> > + */
> > + struct btrfs_encryption_info encryption_info[0];
>
> Looking at this again, adding variable length data will make it hard to
> add more items to the file extent. We could not decide the version just
> by the size, as done in other structures.
Checking the details of btrfs_file_extent_item I understand the item
is already variable size in case of inline extent.
IIUC, that means that versioning based purely on item size is already
not possible for inline file extents.
So in the case of regular one optionally adding the encryption context
seems similar to adding the file data for the inline case.
And it still makes sense to me keeping the
Perhaps the spare field `other_encoding` could eventually be used for
versioning if ever needed?
Let me know if you'd rather add a dedicated key for the encryption
context as Qu suggested. To me it still kind of makes sense to keep it
packed after the file extent info, but I'll be happy with both ways.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 3/8] btrfs-progs: start tracking extent encryption context info
2025-11-05 8:22 ` Daniel Vacek
@ 2025-11-05 8:27 ` Daniel Vacek
2025-11-05 9:12 ` Qu Wenruo
1 sibling, 0 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-11-05 8:27 UTC (permalink / raw)
To: dsterba; +Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
On Wed, 5 Nov 2025 at 09:22, Daniel Vacek <neelx@suse.com> wrote:
> And it still makes sense to me keeping the
This bit should have been deleted but somehow resurrected from the grave :/
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 3/8] btrfs-progs: start tracking extent encryption context info
2025-10-24 22:43 ` Qu Wenruo
@ 2025-11-05 8:28 ` Daniel Vacek
0 siblings, 0 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-11-05 8:28 UTC (permalink / raw)
To: Qu Wenruo
Cc: dsterba, David Sterba, linux-btrfs, Josef Bacik,
Sweet Tea Dorminy
On Sat, 25 Oct 2025 at 00:43, Qu Wenruo <quwenruo.btrfs@gmx.com> wrote:
>
>
>
> 在 2025/10/25 07:59, David Sterba 写道:
> > On Wed, Oct 15, 2025 at 02:11:51PM +0200, Daniel Vacek wrote:
> >> From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> >>
> >> This recapitulates the kernel change named 'btrfs: start tracking extent
> >> encryption context info".
> >>
> >> Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> >> ---
> >> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
> >> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
> >> kernel-shared/uapi/btrfs_tree.h | 23 +++++++++++-
> >> 3 files changed, 118 insertions(+), 13 deletions(-)
> >>
> >> diff --git a/kernel-shared/accessors.h b/kernel-shared/accessors.h
> >> index cb96f3e2..5d90be76 100644
> >> --- a/kernel-shared/accessors.h
> >> +++ b/kernel-shared/accessors.h
> >> @@ -935,6 +935,9 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
> >> BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
> >> nr_global_roots, 64);
> >>
> >> +/* struct btrfs_file_extent_encryption_info */
> >> +BTRFS_SETGET_FUNCS(encryption_info_size, struct btrfs_encryption_info, size, 32);
> >> +
> >> /* struct btrfs_file_extent_item */
> >> BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
> >> type, 8);
> >> @@ -973,6 +976,46 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
> >> BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
> >> other_encoding, 16);
> >>
> >> +static inline struct btrfs_encryption_info *btrfs_file_extent_encryption_info(
> >> + const struct btrfs_file_extent_item *ei)
> >> +{
> >> + unsigned long offset = (unsigned long)ei;
> >> +
> >> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> >> + return (struct btrfs_encryption_info *)offset;
> >> +}
> >> +
> >> +static inline unsigned long btrfs_file_extent_encryption_ctx_offset(
> >> + const struct btrfs_file_extent_item *ei)
> >> +{
> >> + unsigned long offset = (unsigned long)ei;
> >> +
> >> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> >> + return offset + offsetof(struct btrfs_encryption_info, context);
> >> +}
> >> +
> >> +static inline u32 btrfs_file_extent_encryption_ctx_size(
> >> + const struct extent_buffer *eb,
> >> + const struct btrfs_file_extent_item *ei)
> >> +{
> >> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> >> +}
> >> +
> >> +static inline void btrfs_set_file_extent_encryption_ctx_size(
> >> + struct extent_buffer *eb,
> >> + struct btrfs_file_extent_item *ei,
> >> + u32 val)
> >> +{
> >> + btrfs_set_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei), val);
> >> +}
> >> +
> >> +static inline u32 btrfs_file_extent_encryption_info_size(
> >> + const struct extent_buffer *eb,
> >> + const struct btrfs_file_extent_item *ei)
> >> +{
> >> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> >> +}
> >> +
> >> /* btrfs_qgroup_status_item */
> >> BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
> >> generation, 64);
> >> diff --git a/kernel-shared/tree-checker.c b/kernel-shared/tree-checker.c
> >> index ccc1f1ea..93073979 100644
> >> --- a/kernel-shared/tree-checker.c
> >> +++ b/kernel-shared/tree-checker.c
> >> @@ -242,6 +242,8 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> >> u32 sectorsize = fs_info->sectorsize;
> >> u32 item_size = btrfs_item_size(leaf, slot);
> >> u64 extent_end;
> >> + u8 policy;
> >> + u8 fe_type;
> >>
> >> if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
> >> file_extent_err(leaf, slot,
> >> @@ -272,12 +274,12 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> >> SZ_4K);
> >> return -EUCLEAN;
> >> }
> >> - if (unlikely(btrfs_file_extent_type(leaf, fi) >=
> >> - BTRFS_NR_FILE_EXTENT_TYPES)) {
> >> +
> >> + fe_type = btrfs_file_extent_type(leaf, fi);
> >> + if (unlikely(fe_type >= BTRFS_NR_FILE_EXTENT_TYPES)) {
> >> file_extent_err(leaf, slot,
> >> "invalid type for file extent, have %u expect range [0, %u]",
> >> - btrfs_file_extent_type(leaf, fi),
> >> - BTRFS_NR_FILE_EXTENT_TYPES - 1);
> >> + fe_type, BTRFS_NR_FILE_EXTENT_TYPES - 1);
> >> return -EUCLEAN;
> >> }
> >>
> >> @@ -293,10 +295,11 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> >> BTRFS_NR_COMPRESS_TYPES - 1);
> >> return -EUCLEAN;
> >> }
> >> - if (unlikely(btrfs_file_extent_encryption(leaf, fi))) {
> >> + policy = btrfs_file_extent_encryption(leaf, fi);
> >> + if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) {
> >> file_extent_err(leaf, slot,
> >> - "invalid encryption for file extent, have %u expect 0",
> >> - btrfs_file_extent_encryption(leaf, fi));
> >> + "invalid encryption for file extent, have %u expect range [0, %u]",
> >> + policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
> >> return -EUCLEAN;
> >> }
> >> if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
> >> @@ -325,12 +328,50 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> >> return 0;
> >> }
> >>
> >> - /* Regular or preallocated extent has fixed item size */
> >> - if (unlikely(item_size != sizeof(*fi))) {
> >> - file_extent_err(leaf, slot,
> >> + if (policy == BTRFS_ENCRYPTION_FSCRYPT) {
> >> + size_t fe_size = sizeof(*fi) + sizeof(struct btrfs_encryption_info);
> >> + u32 ctxsize;
> >> +
> >> + if (unlikely(item_size < fe_size)) {
> >> + file_extent_err(leaf, slot,
> >> + "invalid item size for encrypted file extent, have %u expect = %zu + size of u32",
> >> + item_size, sizeof(*fi));
> >> + return -EUCLEAN;
> >> + }
> >> +
> >> + ctxsize = btrfs_file_extent_encryption_info_size(leaf, fi);
> >> + if (unlikely(item_size != (fe_size + ctxsize))) {
> >> + file_extent_err(leaf, slot,
> >> + "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
> >> + item_size, fe_size, ctxsize);
> >> + return -EUCLEAN;
> >> + }
> >> +
> >> + if (unlikely(ctxsize > BTRFS_MAX_EXTENT_CTX_SIZE)) {
> >> + file_extent_err(leaf, slot,
> >> + "invalid file extent context size, have %u expect a maximum of %u",
> >> + ctxsize, BTRFS_MAX_EXTENT_CTX_SIZE);
> >> + return -EUCLEAN;
> >> + }
> >> +
> >> + /*
> >> + * Only regular and prealloc extents should have an encryption
> >> + * context.
> >> + */
> >> + if (unlikely(fe_type != BTRFS_FILE_EXTENT_REG &&
> >> + fe_type != BTRFS_FILE_EXTENT_PREALLOC)) {
> >> + file_extent_err(leaf, slot,
> >> + "invalid type for encrypted file extent, have %u",
> >> + btrfs_file_extent_type(leaf, fi));
> >> + return -EUCLEAN;
> >> + }
> >> + } else {
> >> + if (unlikely(item_size != sizeof(*fi))) {
> >> + file_extent_err(leaf, slot,
> >> "invalid item size for reg/prealloc file extent, have %u expect %zu",
> >> - item_size, sizeof(*fi));
> >> - return -EUCLEAN;
> >> + item_size, sizeof(*fi));
> >> + return -EUCLEAN;
> >> + }
> >> }
> >> if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) ||
> >> CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) ||
> >> diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
> >> index 7f3dffe6..4b4f45aa 100644
> >> --- a/kernel-shared/uapi/btrfs_tree.h
> >> +++ b/kernel-shared/uapi/btrfs_tree.h
> >> @@ -1066,6 +1066,24 @@ enum {
> >> BTRFS_NR_FILE_EXTENT_TYPES = 3,
> >> };
> >>
> >> +/*
> >> + * Currently just the FSCRYPT_SET_CONTEXT_MAX_SIZE, which is larger than the
> >> + * current extent context size from fscrypt, so this should give us plenty of
> >> + * breathing room for expansion later.
> >> + */
> >> +#define BTRFS_MAX_EXTENT_CTX_SIZE 40
> >> +
> >> +enum {
> >> + BTRFS_ENCRYPTION_NONE,
> >> + BTRFS_ENCRYPTION_FSCRYPT,
> >> + BTRFS_NR_ENCRYPTION_TYPES,
> >> +};
> >> +
> >> +struct btrfs_encryption_info {
> >> + __le32 size;
> >> + __u8 context[0];
> >> +};
> >> +
> >> struct btrfs_file_extent_item {
> >> /*
> >> * transaction id that created this extent
> >> @@ -1115,7 +1133,10 @@ struct btrfs_file_extent_item {
> >> * always reflects the size uncompressed and without encoding.
> >> */
> >> __le64 num_bytes;
> >> -
> >> + /*
> >> + * the encryption info, if any
> >> + */
> >> + struct btrfs_encryption_info encryption_info[0];
> >
> > Looking at this again, adding variable length data will make it hard to
> > add more items to the file extent. We could not decide the version just
> > by the size, as done in other structures.
> >
>
> Can we put the encryption structure into a dedicated key? Like (ino,
> ENCRYPT_KEY, fileoff) key.
>
> By this we gain the ability to grab the size through btrfs_item_size(),
> and each file extent item also get their own encryption info.
Yeah, that would be definitely possible, but I'm not sure it is really
needed or we gain much this way. I'm open to suggestions here, check
the other email with further details.
> Thanks,
> Qu
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 3/8] btrfs-progs: start tracking extent encryption context info
2025-11-05 8:22 ` Daniel Vacek
2025-11-05 8:27 ` Daniel Vacek
@ 2025-11-05 9:12 ` Qu Wenruo
2025-11-05 10:55 ` Daniel Vacek
1 sibling, 1 reply; 34+ messages in thread
From: Qu Wenruo @ 2025-11-05 9:12 UTC (permalink / raw)
To: Daniel Vacek, dsterba
Cc: David Sterba, linux-btrfs, Josef Bacik, Sweet Tea Dorminy
在 2025/11/5 18:52, Daniel Vacek 写道:
> On Fri, 24 Oct 2025 at 23:29, David Sterba <dsterba@suse.cz> wrote:
>>
>> On Wed, Oct 15, 2025 at 02:11:51PM +0200, Daniel Vacek wrote:
>>> From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
>>>
>>> This recapitulates the kernel change named 'btrfs: start tracking extent
>>> encryption context info".
>>>
>>> Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
>>> ---
>>> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
>>> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
>>> kernel-shared/uapi/btrfs_tree.h | 23 +++++++++++-
>>> 3 files changed, 118 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/kernel-shared/accessors.h b/kernel-shared/accessors.h
>>> index cb96f3e2..5d90be76 100644
>>> --- a/kernel-shared/accessors.h
>>> +++ b/kernel-shared/accessors.h
>>> @@ -935,6 +935,9 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
>>> BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
>>> nr_global_roots, 64);
>>>
>>> +/* struct btrfs_file_extent_encryption_info */
>>> +BTRFS_SETGET_FUNCS(encryption_info_size, struct btrfs_encryption_info, size, 32);
>>> +
>>> /* struct btrfs_file_extent_item */
>>> BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
>>> type, 8);
>>> @@ -973,6 +976,46 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
>>> BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
>>> other_encoding, 16);
>>>
>>> +static inline struct btrfs_encryption_info *btrfs_file_extent_encryption_info(
>>> + const struct btrfs_file_extent_item *ei)
>>> +{
>>> + unsigned long offset = (unsigned long)ei;
>>> +
>>> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
>>> + return (struct btrfs_encryption_info *)offset;
>>> +}
>>> +
>>> +static inline unsigned long btrfs_file_extent_encryption_ctx_offset(
>>> + const struct btrfs_file_extent_item *ei)
>>> +{
>>> + unsigned long offset = (unsigned long)ei;
>>> +
>>> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
>>> + return offset + offsetof(struct btrfs_encryption_info, context);
>>> +}
>>> +
>>> +static inline u32 btrfs_file_extent_encryption_ctx_size(
>>> + const struct extent_buffer *eb,
>>> + const struct btrfs_file_extent_item *ei)
>>> +{
>>> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
>>> +}
>>> +
>>> +static inline void btrfs_set_file_extent_encryption_ctx_size(
>>> + struct extent_buffer *eb,
>>> + struct btrfs_file_extent_item *ei,
>>> + u32 val)
>>> +{
>>> + btrfs_set_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei), val);
>>> +}
>>> +
>>> +static inline u32 btrfs_file_extent_encryption_info_size(
>>> + const struct extent_buffer *eb,
>>> + const struct btrfs_file_extent_item *ei)
>>> +{
>>> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
>>> +}
>>> +
>>> /* btrfs_qgroup_status_item */
>>> BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
>>> generation, 64);
>>> diff --git a/kernel-shared/tree-checker.c b/kernel-shared/tree-checker.c
>>> index ccc1f1ea..93073979 100644
>>> --- a/kernel-shared/tree-checker.c
>>> +++ b/kernel-shared/tree-checker.c
>>> @@ -242,6 +242,8 @@ static int check_extent_data_item(struct extent_buffer *leaf,
>>> u32 sectorsize = fs_info->sectorsize;
>>> u32 item_size = btrfs_item_size(leaf, slot);
>>> u64 extent_end;
>>> + u8 policy;
>>> + u8 fe_type;
>>>
>>> if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
>>> file_extent_err(leaf, slot,
>>> @@ -272,12 +274,12 @@ static int check_extent_data_item(struct extent_buffer *leaf,
>>> SZ_4K);
>>> return -EUCLEAN;
>>> }
>>> - if (unlikely(btrfs_file_extent_type(leaf, fi) >=
>>> - BTRFS_NR_FILE_EXTENT_TYPES)) {
>>> +
>>> + fe_type = btrfs_file_extent_type(leaf, fi);
>>> + if (unlikely(fe_type >= BTRFS_NR_FILE_EXTENT_TYPES)) {
>>> file_extent_err(leaf, slot,
>>> "invalid type for file extent, have %u expect range [0, %u]",
>>> - btrfs_file_extent_type(leaf, fi),
>>> - BTRFS_NR_FILE_EXTENT_TYPES - 1);
>>> + fe_type, BTRFS_NR_FILE_EXTENT_TYPES - 1);
>>> return -EUCLEAN;
>>> }
>>>
>>> @@ -293,10 +295,11 @@ static int check_extent_data_item(struct extent_buffer *leaf,
>>> BTRFS_NR_COMPRESS_TYPES - 1);
>>> return -EUCLEAN;
>>> }
>>> - if (unlikely(btrfs_file_extent_encryption(leaf, fi))) {
>>> + policy = btrfs_file_extent_encryption(leaf, fi);
>>> + if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) {
>>> file_extent_err(leaf, slot,
>>> - "invalid encryption for file extent, have %u expect 0",
>>> - btrfs_file_extent_encryption(leaf, fi));
>>> + "invalid encryption for file extent, have %u expect range [0, %u]",
>>> + policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
>>> return -EUCLEAN;
>>> }
>>> if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
>>> @@ -325,12 +328,50 @@ static int check_extent_data_item(struct extent_buffer *leaf,
>>> return 0;
>>> }
>>>
>>> - /* Regular or preallocated extent has fixed item size */
>>> - if (unlikely(item_size != sizeof(*fi))) {
>>> - file_extent_err(leaf, slot,
>>> + if (policy == BTRFS_ENCRYPTION_FSCRYPT) {
>>> + size_t fe_size = sizeof(*fi) + sizeof(struct btrfs_encryption_info);
>>> + u32 ctxsize;
>>> +
>>> + if (unlikely(item_size < fe_size)) {
>>> + file_extent_err(leaf, slot,
>>> + "invalid item size for encrypted file extent, have %u expect = %zu + size of u32",
>>> + item_size, sizeof(*fi));
>>> + return -EUCLEAN;
>>> + }
>>> +
>>> + ctxsize = btrfs_file_extent_encryption_info_size(leaf, fi);
>>> + if (unlikely(item_size != (fe_size + ctxsize))) {
>>> + file_extent_err(leaf, slot,
>>> + "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
>>> + item_size, fe_size, ctxsize);
>>> + return -EUCLEAN;
>>> + }
>>> +
>>> + if (unlikely(ctxsize > BTRFS_MAX_EXTENT_CTX_SIZE)) {
>>> + file_extent_err(leaf, slot,
>>> + "invalid file extent context size, have %u expect a maximum of %u",
>>> + ctxsize, BTRFS_MAX_EXTENT_CTX_SIZE);
>>> + return -EUCLEAN;
>>> + }
>>> +
>>> + /*
>>> + * Only regular and prealloc extents should have an encryption
>>> + * context.
>>> + */
>>> + if (unlikely(fe_type != BTRFS_FILE_EXTENT_REG &&
>>> + fe_type != BTRFS_FILE_EXTENT_PREALLOC)) {
>>> + file_extent_err(leaf, slot,
>>> + "invalid type for encrypted file extent, have %u",
>>> + btrfs_file_extent_type(leaf, fi));
>>> + return -EUCLEAN;
>>> + }
>>> + } else {
>>> + if (unlikely(item_size != sizeof(*fi))) {
>>> + file_extent_err(leaf, slot,
>>> "invalid item size for reg/prealloc file extent, have %u expect %zu",
>>> - item_size, sizeof(*fi));
>>> - return -EUCLEAN;
>>> + item_size, sizeof(*fi));
>>> + return -EUCLEAN;
>>> + }
>>> }
>>> if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) ||
>>> CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) ||
>>> diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
>>> index 7f3dffe6..4b4f45aa 100644
>>> --- a/kernel-shared/uapi/btrfs_tree.h
>>> +++ b/kernel-shared/uapi/btrfs_tree.h
>>> @@ -1066,6 +1066,24 @@ enum {
>>> BTRFS_NR_FILE_EXTENT_TYPES = 3,
>>> };
>>>
>>> +/*
>>> + * Currently just the FSCRYPT_SET_CONTEXT_MAX_SIZE, which is larger than the
>>> + * current extent context size from fscrypt, so this should give us plenty of
>>> + * breathing room for expansion later.
>>> + */
>>> +#define BTRFS_MAX_EXTENT_CTX_SIZE 40
>>> +
>>> +enum {
>>> + BTRFS_ENCRYPTION_NONE,
>>> + BTRFS_ENCRYPTION_FSCRYPT,
>>> + BTRFS_NR_ENCRYPTION_TYPES,
>>> +};
>>> +
>>> +struct btrfs_encryption_info {
>>> + __le32 size;
>>> + __u8 context[0];
>>> +};
>>> +
>>> struct btrfs_file_extent_item {
>>> /*
>>> * transaction id that created this extent
>>> @@ -1115,7 +1133,10 @@ struct btrfs_file_extent_item {
>>> * always reflects the size uncompressed and without encoding.
>>> */
>>> __le64 num_bytes;
>>> -
>>> + /*
>>> + * the encryption info, if any
>>> + */
>>> + struct btrfs_encryption_info encryption_info[0];
>>
>> Looking at this again, adding variable length data will make it hard to
>> add more items to the file extent. We could not decide the version just
>> by the size, as done in other structures.
>
> Checking the details of btrfs_file_extent_item I understand the item
> is already variable size in case of inline extent.
Yeah, but I'm not sure if that is a good example to follow, or a bad
example to avoid.
The biggest concern is for encrypted inline data extents.
We need to put two variable sized data into a single item.
(I know there are examples like btrfs_dir_item for XATTR, but again not
sure if we should really follow that)
In that case the structure definition will not help, and you have to
determine where to put the appended encryption info, either before the
inlined data, or before it.
And all the extra sequence info must be implemented in extra comments,
which is way harder to read/understand.
From this point of view, the original inline extent usage of
btrfs_file_extent_item is already an example to avoid.
But sure, the appending solution will save us 25 bytes per file extent
item, thus it definitely has its benefit.
I belive David will do final call, trading off between readability or
space saving (and more locality and less key search for encrypted file
extents).
Although I prefer the dedicated key solution for readability, I'm fine
to accept either solution.
Thanks,
Qu
> IIUC, that means that versioning based purely on item size is already
> not possible for inline file extents.
> So in the case of regular one optionally adding the encryption context
> seems similar to adding the file data for the inline case.
> And it still makes sense to me keeping the
>
> Perhaps the spare field `other_encoding` could eventually be used for
> versioning if ever needed?
>
> Let me know if you'd rather add a dedicated key for the encryption
> context as Qu suggested. To me it still kind of makes sense to keep it
> packed after the file extent info, but I'll be happy with both ways.
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 3/8] btrfs-progs: start tracking extent encryption context info
2025-11-05 9:12 ` Qu Wenruo
@ 2025-11-05 10:55 ` Daniel Vacek
2025-11-26 14:11 ` David Sterba
0 siblings, 1 reply; 34+ messages in thread
From: Daniel Vacek @ 2025-11-05 10:55 UTC (permalink / raw)
To: Qu Wenruo
Cc: dsterba, David Sterba, linux-btrfs, Josef Bacik,
Sweet Tea Dorminy
On Wed, 5 Nov 2025 at 10:12, Qu Wenruo <quwenruo.btrfs@gmx.com> wrote:
> 在 2025/11/5 18:52, Daniel Vacek 写道:
> > On Fri, 24 Oct 2025 at 23:29, David Sterba <dsterba@suse.cz> wrote:
> >>
> >> On Wed, Oct 15, 2025 at 02:11:51PM +0200, Daniel Vacek wrote:
> >>> From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> >>>
> >>> This recapitulates the kernel change named 'btrfs: start tracking extent
> >>> encryption context info".
> >>>
> >>> Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> >>> ---
> >>> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
> >>> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
> >>> kernel-shared/uapi/btrfs_tree.h | 23 +++++++++++-
> >>> 3 files changed, 118 insertions(+), 13 deletions(-)
> >>>
> >>> diff --git a/kernel-shared/accessors.h b/kernel-shared/accessors.h
> >>> index cb96f3e2..5d90be76 100644
> >>> --- a/kernel-shared/accessors.h
> >>> +++ b/kernel-shared/accessors.h
> >>> @@ -935,6 +935,9 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
> >>> BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
> >>> nr_global_roots, 64);
> >>>
> >>> +/* struct btrfs_file_extent_encryption_info */
> >>> +BTRFS_SETGET_FUNCS(encryption_info_size, struct btrfs_encryption_info, size, 32);
> >>> +
> >>> /* struct btrfs_file_extent_item */
> >>> BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
> >>> type, 8);
> >>> @@ -973,6 +976,46 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
> >>> BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
> >>> other_encoding, 16);
> >>>
> >>> +static inline struct btrfs_encryption_info *btrfs_file_extent_encryption_info(
> >>> + const struct btrfs_file_extent_item *ei)
> >>> +{
> >>> + unsigned long offset = (unsigned long)ei;
> >>> +
> >>> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> >>> + return (struct btrfs_encryption_info *)offset;
> >>> +}
> >>> +
> >>> +static inline unsigned long btrfs_file_extent_encryption_ctx_offset(
> >>> + const struct btrfs_file_extent_item *ei)
> >>> +{
> >>> + unsigned long offset = (unsigned long)ei;
> >>> +
> >>> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> >>> + return offset + offsetof(struct btrfs_encryption_info, context);
> >>> +}
> >>> +
> >>> +static inline u32 btrfs_file_extent_encryption_ctx_size(
> >>> + const struct extent_buffer *eb,
> >>> + const struct btrfs_file_extent_item *ei)
> >>> +{
> >>> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> >>> +}
> >>> +
> >>> +static inline void btrfs_set_file_extent_encryption_ctx_size(
> >>> + struct extent_buffer *eb,
> >>> + struct btrfs_file_extent_item *ei,
> >>> + u32 val)
> >>> +{
> >>> + btrfs_set_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei), val);
> >>> +}
> >>> +
> >>> +static inline u32 btrfs_file_extent_encryption_info_size(
> >>> + const struct extent_buffer *eb,
> >>> + const struct btrfs_file_extent_item *ei)
> >>> +{
> >>> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> >>> +}
> >>> +
> >>> /* btrfs_qgroup_status_item */
> >>> BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
> >>> generation, 64);
> >>> diff --git a/kernel-shared/tree-checker.c b/kernel-shared/tree-checker.c
> >>> index ccc1f1ea..93073979 100644
> >>> --- a/kernel-shared/tree-checker.c
> >>> +++ b/kernel-shared/tree-checker.c
> >>> @@ -242,6 +242,8 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> >>> u32 sectorsize = fs_info->sectorsize;
> >>> u32 item_size = btrfs_item_size(leaf, slot);
> >>> u64 extent_end;
> >>> + u8 policy;
> >>> + u8 fe_type;
> >>>
> >>> if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
> >>> file_extent_err(leaf, slot,
> >>> @@ -272,12 +274,12 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> >>> SZ_4K);
> >>> return -EUCLEAN;
> >>> }
> >>> - if (unlikely(btrfs_file_extent_type(leaf, fi) >=
> >>> - BTRFS_NR_FILE_EXTENT_TYPES)) {
> >>> +
> >>> + fe_type = btrfs_file_extent_type(leaf, fi);
> >>> + if (unlikely(fe_type >= BTRFS_NR_FILE_EXTENT_TYPES)) {
> >>> file_extent_err(leaf, slot,
> >>> "invalid type for file extent, have %u expect range [0, %u]",
> >>> - btrfs_file_extent_type(leaf, fi),
> >>> - BTRFS_NR_FILE_EXTENT_TYPES - 1);
> >>> + fe_type, BTRFS_NR_FILE_EXTENT_TYPES - 1);
> >>> return -EUCLEAN;
> >>> }
> >>>
> >>> @@ -293,10 +295,11 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> >>> BTRFS_NR_COMPRESS_TYPES - 1);
> >>> return -EUCLEAN;
> >>> }
> >>> - if (unlikely(btrfs_file_extent_encryption(leaf, fi))) {
> >>> + policy = btrfs_file_extent_encryption(leaf, fi);
> >>> + if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) {
> >>> file_extent_err(leaf, slot,
> >>> - "invalid encryption for file extent, have %u expect 0",
> >>> - btrfs_file_extent_encryption(leaf, fi));
> >>> + "invalid encryption for file extent, have %u expect range [0, %u]",
> >>> + policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
> >>> return -EUCLEAN;
> >>> }
> >>> if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
> >>> @@ -325,12 +328,50 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> >>> return 0;
> >>> }
> >>>
> >>> - /* Regular or preallocated extent has fixed item size */
> >>> - if (unlikely(item_size != sizeof(*fi))) {
> >>> - file_extent_err(leaf, slot,
> >>> + if (policy == BTRFS_ENCRYPTION_FSCRYPT) {
> >>> + size_t fe_size = sizeof(*fi) + sizeof(struct btrfs_encryption_info);
> >>> + u32 ctxsize;
> >>> +
> >>> + if (unlikely(item_size < fe_size)) {
> >>> + file_extent_err(leaf, slot,
> >>> + "invalid item size for encrypted file extent, have %u expect = %zu + size of u32",
> >>> + item_size, sizeof(*fi));
> >>> + return -EUCLEAN;
> >>> + }
> >>> +
> >>> + ctxsize = btrfs_file_extent_encryption_info_size(leaf, fi);
> >>> + if (unlikely(item_size != (fe_size + ctxsize))) {
> >>> + file_extent_err(leaf, slot,
> >>> + "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
> >>> + item_size, fe_size, ctxsize);
> >>> + return -EUCLEAN;
> >>> + }
> >>> +
> >>> + if (unlikely(ctxsize > BTRFS_MAX_EXTENT_CTX_SIZE)) {
> >>> + file_extent_err(leaf, slot,
> >>> + "invalid file extent context size, have %u expect a maximum of %u",
> >>> + ctxsize, BTRFS_MAX_EXTENT_CTX_SIZE);
> >>> + return -EUCLEAN;
> >>> + }
> >>> +
> >>> + /*
> >>> + * Only regular and prealloc extents should have an encryption
> >>> + * context.
> >>> + */
> >>> + if (unlikely(fe_type != BTRFS_FILE_EXTENT_REG &&
> >>> + fe_type != BTRFS_FILE_EXTENT_PREALLOC)) {
> >>> + file_extent_err(leaf, slot,
> >>> + "invalid type for encrypted file extent, have %u",
> >>> + btrfs_file_extent_type(leaf, fi));
> >>> + return -EUCLEAN;
> >>> + }
> >>> + } else {
> >>> + if (unlikely(item_size != sizeof(*fi))) {
> >>> + file_extent_err(leaf, slot,
> >>> "invalid item size for reg/prealloc file extent, have %u expect %zu",
> >>> - item_size, sizeof(*fi));
> >>> - return -EUCLEAN;
> >>> + item_size, sizeof(*fi));
> >>> + return -EUCLEAN;
> >>> + }
> >>> }
> >>> if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) ||
> >>> CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) ||
> >>> diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
> >>> index 7f3dffe6..4b4f45aa 100644
> >>> --- a/kernel-shared/uapi/btrfs_tree.h
> >>> +++ b/kernel-shared/uapi/btrfs_tree.h
> >>> @@ -1066,6 +1066,24 @@ enum {
> >>> BTRFS_NR_FILE_EXTENT_TYPES = 3,
> >>> };
> >>>
> >>> +/*
> >>> + * Currently just the FSCRYPT_SET_CONTEXT_MAX_SIZE, which is larger than the
> >>> + * current extent context size from fscrypt, so this should give us plenty of
> >>> + * breathing room for expansion later.
> >>> + */
> >>> +#define BTRFS_MAX_EXTENT_CTX_SIZE 40
> >>> +
> >>> +enum {
> >>> + BTRFS_ENCRYPTION_NONE,
> >>> + BTRFS_ENCRYPTION_FSCRYPT,
> >>> + BTRFS_NR_ENCRYPTION_TYPES,
> >>> +};
> >>> +
> >>> +struct btrfs_encryption_info {
> >>> + __le32 size;
> >>> + __u8 context[0];
> >>> +};
> >>> +
> >>> struct btrfs_file_extent_item {
> >>> /*
> >>> * transaction id that created this extent
> >>> @@ -1115,7 +1133,10 @@ struct btrfs_file_extent_item {
> >>> * always reflects the size uncompressed and without encoding.
> >>> */
> >>> __le64 num_bytes;
> >>> -
> >>> + /*
> >>> + * the encryption info, if any
> >>> + */
> >>> + struct btrfs_encryption_info encryption_info[0];
> >>
> >> Looking at this again, adding variable length data will make it hard to
> >> add more items to the file extent. We could not decide the version just
> >> by the size, as done in other structures.
> >
> > Checking the details of btrfs_file_extent_item I understand the item
> > is already variable size in case of inline extent.
>
> Yeah, but I'm not sure if that is a good example to follow, or a bad
> example to avoid.
>
> The biggest concern is for encrypted inline data extents.
> We need to put two variable sized data into a single item.
> (I know there are examples like btrfs_dir_item for XATTR, but again not
> sure if we should really follow that)
Just for the record, with the state of the patches as of now, inline
extent encryption is not supported. And for example ext4 also merges
the encryption context with the inline data.
But if we wanted to implement encrypted inline extents it may be
easier for us to just add a new key storing the context. So perhaps we
can do it right away to cover all the cases in a generic way.
> In that case the structure definition will not help, and you have to
> determine where to put the appended encryption info, either before the
> inlined data, or before it.
>
> And all the extra sequence info must be implemented in extra comments,
> which is way harder to read/understand.
> From this point of view, the original inline extent usage of
> btrfs_file_extent_item is already an example to avoid.
>
>
> But sure, the appending solution will save us 25 bytes per file extent
> item, thus it definitely has its benefit.
>
> I belive David will do final call, trading off between readability or
> space saving (and more locality and less key search for encrypted file
> extents).
>
> Although I prefer the dedicated key solution for readability, I'm fine
> to accept either solution.
>
> Thanks,
> Qu
>
>
> > IIUC, that means that versioning based purely on item size is already
> > not possible for inline file extents.
> > So in the case of regular one optionally adding the encryption context
> > seems similar to adding the file data for the inline case.
> > And it still makes sense to me keeping the
> >
> > Perhaps the spare field `other_encoding` could eventually be used for
> > versioning if ever needed?
> >
> > Let me know if you'd rather add a dedicated key for the encryption
> > context as Qu suggested. To me it still kind of makes sense to keep it
> > packed after the file extent info, but I'll be happy with both ways.
> >
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 3/8] btrfs-progs: start tracking extent encryption context info
2025-11-05 10:55 ` Daniel Vacek
@ 2025-11-26 14:11 ` David Sterba
2025-11-27 8:40 ` Daniel Vacek
0 siblings, 1 reply; 34+ messages in thread
From: David Sterba @ 2025-11-26 14:11 UTC (permalink / raw)
To: Daniel Vacek
Cc: Qu Wenruo, David Sterba, linux-btrfs, Josef Bacik,
Sweet Tea Dorminy
On Wed, Nov 05, 2025 at 11:55:15AM +0100, Daniel Vacek wrote:
> On Wed, 5 Nov 2025 at 10:12, Qu Wenruo <quwenruo.btrfs@gmx.com> wrote:
> > 在 2025/11/5 18:52, Daniel Vacek 写道:
> > > On Fri, 24 Oct 2025 at 23:29, David Sterba <dsterba@suse.cz> wrote:
> > >>
> > >> On Wed, Oct 15, 2025 at 02:11:51PM +0200, Daniel Vacek wrote:
> > >>> From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> > >>>
> > >>> This recapitulates the kernel change named 'btrfs: start tracking extent
> > >>> encryption context info".
> > >>>
> > >>> Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> > >>> ---
> > >>> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
> > >>> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
> > >>> kernel-shared/uapi/btrfs_tree.h | 23 +++++++++++-
> > >>> 3 files changed, 118 insertions(+), 13 deletions(-)
> > >>>
> > >>> diff --git a/kernel-shared/accessors.h b/kernel-shared/accessors.h
> > >>> index cb96f3e2..5d90be76 100644
> > >>> --- a/kernel-shared/accessors.h
> > >>> +++ b/kernel-shared/accessors.h
> > >>> @@ -935,6 +935,9 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
> > >>> BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
> > >>> nr_global_roots, 64);
> > >>>
> > >>> +/* struct btrfs_file_extent_encryption_info */
> > >>> +BTRFS_SETGET_FUNCS(encryption_info_size, struct btrfs_encryption_info, size, 32);
> > >>> +
> > >>> /* struct btrfs_file_extent_item */
> > >>> BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
> > >>> type, 8);
> > >>> @@ -973,6 +976,46 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
> > >>> BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
> > >>> other_encoding, 16);
> > >>>
> > >>> +static inline struct btrfs_encryption_info *btrfs_file_extent_encryption_info(
> > >>> + const struct btrfs_file_extent_item *ei)
> > >>> +{
> > >>> + unsigned long offset = (unsigned long)ei;
> > >>> +
> > >>> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> > >>> + return (struct btrfs_encryption_info *)offset;
> > >>> +}
> > >>> +
> > >>> +static inline unsigned long btrfs_file_extent_encryption_ctx_offset(
> > >>> + const struct btrfs_file_extent_item *ei)
> > >>> +{
> > >>> + unsigned long offset = (unsigned long)ei;
> > >>> +
> > >>> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> > >>> + return offset + offsetof(struct btrfs_encryption_info, context);
> > >>> +}
> > >>> +
> > >>> +static inline u32 btrfs_file_extent_encryption_ctx_size(
> > >>> + const struct extent_buffer *eb,
> > >>> + const struct btrfs_file_extent_item *ei)
> > >>> +{
> > >>> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> > >>> +}
> > >>> +
> > >>> +static inline void btrfs_set_file_extent_encryption_ctx_size(
> > >>> + struct extent_buffer *eb,
> > >>> + struct btrfs_file_extent_item *ei,
> > >>> + u32 val)
> > >>> +{
> > >>> + btrfs_set_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei), val);
> > >>> +}
> > >>> +
> > >>> +static inline u32 btrfs_file_extent_encryption_info_size(
> > >>> + const struct extent_buffer *eb,
> > >>> + const struct btrfs_file_extent_item *ei)
> > >>> +{
> > >>> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> > >>> +}
> > >>> +
> > >>> /* btrfs_qgroup_status_item */
> > >>> BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
> > >>> generation, 64);
> > >>> diff --git a/kernel-shared/tree-checker.c b/kernel-shared/tree-checker.c
> > >>> index ccc1f1ea..93073979 100644
> > >>> --- a/kernel-shared/tree-checker.c
> > >>> +++ b/kernel-shared/tree-checker.c
> > >>> @@ -242,6 +242,8 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > >>> u32 sectorsize = fs_info->sectorsize;
> > >>> u32 item_size = btrfs_item_size(leaf, slot);
> > >>> u64 extent_end;
> > >>> + u8 policy;
> > >>> + u8 fe_type;
> > >>>
> > >>> if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
> > >>> file_extent_err(leaf, slot,
> > >>> @@ -272,12 +274,12 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > >>> SZ_4K);
> > >>> return -EUCLEAN;
> > >>> }
> > >>> - if (unlikely(btrfs_file_extent_type(leaf, fi) >=
> > >>> - BTRFS_NR_FILE_EXTENT_TYPES)) {
> > >>> +
> > >>> + fe_type = btrfs_file_extent_type(leaf, fi);
> > >>> + if (unlikely(fe_type >= BTRFS_NR_FILE_EXTENT_TYPES)) {
> > >>> file_extent_err(leaf, slot,
> > >>> "invalid type for file extent, have %u expect range [0, %u]",
> > >>> - btrfs_file_extent_type(leaf, fi),
> > >>> - BTRFS_NR_FILE_EXTENT_TYPES - 1);
> > >>> + fe_type, BTRFS_NR_FILE_EXTENT_TYPES - 1);
> > >>> return -EUCLEAN;
> > >>> }
> > >>>
> > >>> @@ -293,10 +295,11 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > >>> BTRFS_NR_COMPRESS_TYPES - 1);
> > >>> return -EUCLEAN;
> > >>> }
> > >>> - if (unlikely(btrfs_file_extent_encryption(leaf, fi))) {
> > >>> + policy = btrfs_file_extent_encryption(leaf, fi);
> > >>> + if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) {
> > >>> file_extent_err(leaf, slot,
> > >>> - "invalid encryption for file extent, have %u expect 0",
> > >>> - btrfs_file_extent_encryption(leaf, fi));
> > >>> + "invalid encryption for file extent, have %u expect range [0, %u]",
> > >>> + policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
> > >>> return -EUCLEAN;
> > >>> }
> > >>> if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
> > >>> @@ -325,12 +328,50 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > >>> return 0;
> > >>> }
> > >>>
> > >>> - /* Regular or preallocated extent has fixed item size */
> > >>> - if (unlikely(item_size != sizeof(*fi))) {
> > >>> - file_extent_err(leaf, slot,
> > >>> + if (policy == BTRFS_ENCRYPTION_FSCRYPT) {
> > >>> + size_t fe_size = sizeof(*fi) + sizeof(struct btrfs_encryption_info);
> > >>> + u32 ctxsize;
> > >>> +
> > >>> + if (unlikely(item_size < fe_size)) {
> > >>> + file_extent_err(leaf, slot,
> > >>> + "invalid item size for encrypted file extent, have %u expect = %zu + size of u32",
> > >>> + item_size, sizeof(*fi));
> > >>> + return -EUCLEAN;
> > >>> + }
> > >>> +
> > >>> + ctxsize = btrfs_file_extent_encryption_info_size(leaf, fi);
> > >>> + if (unlikely(item_size != (fe_size + ctxsize))) {
> > >>> + file_extent_err(leaf, slot,
> > >>> + "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
> > >>> + item_size, fe_size, ctxsize);
> > >>> + return -EUCLEAN;
> > >>> + }
> > >>> +
> > >>> + if (unlikely(ctxsize > BTRFS_MAX_EXTENT_CTX_SIZE)) {
> > >>> + file_extent_err(leaf, slot,
> > >>> + "invalid file extent context size, have %u expect a maximum of %u",
> > >>> + ctxsize, BTRFS_MAX_EXTENT_CTX_SIZE);
> > >>> + return -EUCLEAN;
> > >>> + }
> > >>> +
> > >>> + /*
> > >>> + * Only regular and prealloc extents should have an encryption
> > >>> + * context.
> > >>> + */
> > >>> + if (unlikely(fe_type != BTRFS_FILE_EXTENT_REG &&
> > >>> + fe_type != BTRFS_FILE_EXTENT_PREALLOC)) {
> > >>> + file_extent_err(leaf, slot,
> > >>> + "invalid type for encrypted file extent, have %u",
> > >>> + btrfs_file_extent_type(leaf, fi));
> > >>> + return -EUCLEAN;
> > >>> + }
> > >>> + } else {
> > >>> + if (unlikely(item_size != sizeof(*fi))) {
> > >>> + file_extent_err(leaf, slot,
> > >>> "invalid item size for reg/prealloc file extent, have %u expect %zu",
> > >>> - item_size, sizeof(*fi));
> > >>> - return -EUCLEAN;
> > >>> + item_size, sizeof(*fi));
> > >>> + return -EUCLEAN;
> > >>> + }
> > >>> }
> > >>> if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) ||
> > >>> CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) ||
> > >>> diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
> > >>> index 7f3dffe6..4b4f45aa 100644
> > >>> --- a/kernel-shared/uapi/btrfs_tree.h
> > >>> +++ b/kernel-shared/uapi/btrfs_tree.h
> > >>> @@ -1066,6 +1066,24 @@ enum {
> > >>> BTRFS_NR_FILE_EXTENT_TYPES = 3,
> > >>> };
> > >>>
> > >>> +/*
> > >>> + * Currently just the FSCRYPT_SET_CONTEXT_MAX_SIZE, which is larger than the
> > >>> + * current extent context size from fscrypt, so this should give us plenty of
> > >>> + * breathing room for expansion later.
> > >>> + */
> > >>> +#define BTRFS_MAX_EXTENT_CTX_SIZE 40
> > >>> +
> > >>> +enum {
> > >>> + BTRFS_ENCRYPTION_NONE,
> > >>> + BTRFS_ENCRYPTION_FSCRYPT,
> > >>> + BTRFS_NR_ENCRYPTION_TYPES,
> > >>> +};
> > >>> +
> > >>> +struct btrfs_encryption_info {
> > >>> + __le32 size;
> > >>> + __u8 context[0];
> > >>> +};
> > >>> +
> > >>> struct btrfs_file_extent_item {
> > >>> /*
> > >>> * transaction id that created this extent
> > >>> @@ -1115,7 +1133,10 @@ struct btrfs_file_extent_item {
> > >>> * always reflects the size uncompressed and without encoding.
> > >>> */
> > >>> __le64 num_bytes;
> > >>> -
> > >>> + /*
> > >>> + * the encryption info, if any
> > >>> + */
> > >>> + struct btrfs_encryption_info encryption_info[0];
> > >>
> > >> Looking at this again, adding variable length data will make it hard to
> > >> add more items to the file extent. We could not decide the version just
> > >> by the size, as done in other structures.
> > >
> > > Checking the details of btrfs_file_extent_item I understand the item
> > > is already variable size in case of inline extent.
> >
> > Yeah, but I'm not sure if that is a good example to follow, or a bad
> > example to avoid.
> >
> > The biggest concern is for encrypted inline data extents.
> > We need to put two variable sized data into a single item.
> > (I know there are examples like btrfs_dir_item for XATTR, but again not
> > sure if we should really follow that)
>
> Just for the record, with the state of the patches as of now, inline
> extent encryption is not supported. And for example ext4 also merges
> the encryption context with the inline data.
> But if we wanted to implement encrypted inline extents it may be
> easier for us to just add a new key storing the context. So perhaps we
> can do it right away to cover all the cases in a generic way.
For the record, I think separate key/item is a better option.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 3/8] btrfs-progs: start tracking extent encryption context info
2025-11-26 14:11 ` David Sterba
@ 2025-11-27 8:40 ` Daniel Vacek
0 siblings, 0 replies; 34+ messages in thread
From: Daniel Vacek @ 2025-11-27 8:40 UTC (permalink / raw)
To: dsterba
Cc: Qu Wenruo, David Sterba, linux-btrfs, Josef Bacik,
Sweet Tea Dorminy
On Wed, 26 Nov 2025 at 15:11, David Sterba <dsterba@suse.cz> wrote:
> On Wed, Nov 05, 2025 at 11:55:15AM +0100, Daniel Vacek wrote:
> > On Wed, 5 Nov 2025 at 10:12, Qu Wenruo <quwenruo.btrfs@gmx.com> wrote:
> > > 在 2025/11/5 18:52, Daniel Vacek 写道:
> > > > On Fri, 24 Oct 2025 at 23:29, David Sterba <dsterba@suse.cz> wrote:
> > > >>
> > > >> On Wed, Oct 15, 2025 at 02:11:51PM +0200, Daniel Vacek wrote:
> > > >>> From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> > > >>>
> > > >>> This recapitulates the kernel change named 'btrfs: start tracking extent
> > > >>> encryption context info".
> > > >>>
> > > >>> Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> > > >>> ---
> > > >>> kernel-shared/accessors.h | 43 ++++++++++++++++++++++
> > > >>> kernel-shared/tree-checker.c | 65 +++++++++++++++++++++++++++------
> > > >>> kernel-shared/uapi/btrfs_tree.h | 23 +++++++++++-
> > > >>> 3 files changed, 118 insertions(+), 13 deletions(-)
> > > >>>
> > > >>> diff --git a/kernel-shared/accessors.h b/kernel-shared/accessors.h
> > > >>> index cb96f3e2..5d90be76 100644
> > > >>> --- a/kernel-shared/accessors.h
> > > >>> +++ b/kernel-shared/accessors.h
> > > >>> @@ -935,6 +935,9 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
> > > >>> BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block,
> > > >>> nr_global_roots, 64);
> > > >>>
> > > >>> +/* struct btrfs_file_extent_encryption_info */
> > > >>> +BTRFS_SETGET_FUNCS(encryption_info_size, struct btrfs_encryption_info, size, 32);
> > > >>> +
> > > >>> /* struct btrfs_file_extent_item */
> > > >>> BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item,
> > > >>> type, 8);
> > > >>> @@ -973,6 +976,46 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
> > > >>> BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
> > > >>> other_encoding, 16);
> > > >>>
> > > >>> +static inline struct btrfs_encryption_info *btrfs_file_extent_encryption_info(
> > > >>> + const struct btrfs_file_extent_item *ei)
> > > >>> +{
> > > >>> + unsigned long offset = (unsigned long)ei;
> > > >>> +
> > > >>> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> > > >>> + return (struct btrfs_encryption_info *)offset;
> > > >>> +}
> > > >>> +
> > > >>> +static inline unsigned long btrfs_file_extent_encryption_ctx_offset(
> > > >>> + const struct btrfs_file_extent_item *ei)
> > > >>> +{
> > > >>> + unsigned long offset = (unsigned long)ei;
> > > >>> +
> > > >>> + offset += offsetof(struct btrfs_file_extent_item, encryption_info);
> > > >>> + return offset + offsetof(struct btrfs_encryption_info, context);
> > > >>> +}
> > > >>> +
> > > >>> +static inline u32 btrfs_file_extent_encryption_ctx_size(
> > > >>> + const struct extent_buffer *eb,
> > > >>> + const struct btrfs_file_extent_item *ei)
> > > >>> +{
> > > >>> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> > > >>> +}
> > > >>> +
> > > >>> +static inline void btrfs_set_file_extent_encryption_ctx_size(
> > > >>> + struct extent_buffer *eb,
> > > >>> + struct btrfs_file_extent_item *ei,
> > > >>> + u32 val)
> > > >>> +{
> > > >>> + btrfs_set_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei), val);
> > > >>> +}
> > > >>> +
> > > >>> +static inline u32 btrfs_file_extent_encryption_info_size(
> > > >>> + const struct extent_buffer *eb,
> > > >>> + const struct btrfs_file_extent_item *ei)
> > > >>> +{
> > > >>> + return btrfs_encryption_info_size(eb, btrfs_file_extent_encryption_info(ei));
> > > >>> +}
> > > >>> +
> > > >>> /* btrfs_qgroup_status_item */
> > > >>> BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item,
> > > >>> generation, 64);
> > > >>> diff --git a/kernel-shared/tree-checker.c b/kernel-shared/tree-checker.c
> > > >>> index ccc1f1ea..93073979 100644
> > > >>> --- a/kernel-shared/tree-checker.c
> > > >>> +++ b/kernel-shared/tree-checker.c
> > > >>> @@ -242,6 +242,8 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > > >>> u32 sectorsize = fs_info->sectorsize;
> > > >>> u32 item_size = btrfs_item_size(leaf, slot);
> > > >>> u64 extent_end;
> > > >>> + u8 policy;
> > > >>> + u8 fe_type;
> > > >>>
> > > >>> if (unlikely(!IS_ALIGNED(key->offset, sectorsize))) {
> > > >>> file_extent_err(leaf, slot,
> > > >>> @@ -272,12 +274,12 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > > >>> SZ_4K);
> > > >>> return -EUCLEAN;
> > > >>> }
> > > >>> - if (unlikely(btrfs_file_extent_type(leaf, fi) >=
> > > >>> - BTRFS_NR_FILE_EXTENT_TYPES)) {
> > > >>> +
> > > >>> + fe_type = btrfs_file_extent_type(leaf, fi);
> > > >>> + if (unlikely(fe_type >= BTRFS_NR_FILE_EXTENT_TYPES)) {
> > > >>> file_extent_err(leaf, slot,
> > > >>> "invalid type for file extent, have %u expect range [0, %u]",
> > > >>> - btrfs_file_extent_type(leaf, fi),
> > > >>> - BTRFS_NR_FILE_EXTENT_TYPES - 1);
> > > >>> + fe_type, BTRFS_NR_FILE_EXTENT_TYPES - 1);
> > > >>> return -EUCLEAN;
> > > >>> }
> > > >>>
> > > >>> @@ -293,10 +295,11 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > > >>> BTRFS_NR_COMPRESS_TYPES - 1);
> > > >>> return -EUCLEAN;
> > > >>> }
> > > >>> - if (unlikely(btrfs_file_extent_encryption(leaf, fi))) {
> > > >>> + policy = btrfs_file_extent_encryption(leaf, fi);
> > > >>> + if (unlikely(policy >= BTRFS_NR_ENCRYPTION_TYPES)) {
> > > >>> file_extent_err(leaf, slot,
> > > >>> - "invalid encryption for file extent, have %u expect 0",
> > > >>> - btrfs_file_extent_encryption(leaf, fi));
> > > >>> + "invalid encryption for file extent, have %u expect range [0, %u]",
> > > >>> + policy, BTRFS_NR_ENCRYPTION_TYPES - 1);
> > > >>> return -EUCLEAN;
> > > >>> }
> > > >>> if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) {
> > > >>> @@ -325,12 +328,50 @@ static int check_extent_data_item(struct extent_buffer *leaf,
> > > >>> return 0;
> > > >>> }
> > > >>>
> > > >>> - /* Regular or preallocated extent has fixed item size */
> > > >>> - if (unlikely(item_size != sizeof(*fi))) {
> > > >>> - file_extent_err(leaf, slot,
> > > >>> + if (policy == BTRFS_ENCRYPTION_FSCRYPT) {
> > > >>> + size_t fe_size = sizeof(*fi) + sizeof(struct btrfs_encryption_info);
> > > >>> + u32 ctxsize;
> > > >>> +
> > > >>> + if (unlikely(item_size < fe_size)) {
> > > >>> + file_extent_err(leaf, slot,
> > > >>> + "invalid item size for encrypted file extent, have %u expect = %zu + size of u32",
> > > >>> + item_size, sizeof(*fi));
> > > >>> + return -EUCLEAN;
> > > >>> + }
> > > >>> +
> > > >>> + ctxsize = btrfs_file_extent_encryption_info_size(leaf, fi);
> > > >>> + if (unlikely(item_size != (fe_size + ctxsize))) {
> > > >>> + file_extent_err(leaf, slot,
> > > >>> + "invalid item size for encrypted file extent, have %u expect = %zu + context of size %u",
> > > >>> + item_size, fe_size, ctxsize);
> > > >>> + return -EUCLEAN;
> > > >>> + }
> > > >>> +
> > > >>> + if (unlikely(ctxsize > BTRFS_MAX_EXTENT_CTX_SIZE)) {
> > > >>> + file_extent_err(leaf, slot,
> > > >>> + "invalid file extent context size, have %u expect a maximum of %u",
> > > >>> + ctxsize, BTRFS_MAX_EXTENT_CTX_SIZE);
> > > >>> + return -EUCLEAN;
> > > >>> + }
> > > >>> +
> > > >>> + /*
> > > >>> + * Only regular and prealloc extents should have an encryption
> > > >>> + * context.
> > > >>> + */
> > > >>> + if (unlikely(fe_type != BTRFS_FILE_EXTENT_REG &&
> > > >>> + fe_type != BTRFS_FILE_EXTENT_PREALLOC)) {
> > > >>> + file_extent_err(leaf, slot,
> > > >>> + "invalid type for encrypted file extent, have %u",
> > > >>> + btrfs_file_extent_type(leaf, fi));
> > > >>> + return -EUCLEAN;
> > > >>> + }
> > > >>> + } else {
> > > >>> + if (unlikely(item_size != sizeof(*fi))) {
> > > >>> + file_extent_err(leaf, slot,
> > > >>> "invalid item size for reg/prealloc file extent, have %u expect %zu",
> > > >>> - item_size, sizeof(*fi));
> > > >>> - return -EUCLEAN;
> > > >>> + item_size, sizeof(*fi));
> > > >>> + return -EUCLEAN;
> > > >>> + }
> > > >>> }
> > > >>> if (unlikely(CHECK_FE_ALIGNED(leaf, slot, fi, ram_bytes, sectorsize) ||
> > > >>> CHECK_FE_ALIGNED(leaf, slot, fi, disk_bytenr, sectorsize) ||
> > > >>> diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h
> > > >>> index 7f3dffe6..4b4f45aa 100644
> > > >>> --- a/kernel-shared/uapi/btrfs_tree.h
> > > >>> +++ b/kernel-shared/uapi/btrfs_tree.h
> > > >>> @@ -1066,6 +1066,24 @@ enum {
> > > >>> BTRFS_NR_FILE_EXTENT_TYPES = 3,
> > > >>> };
> > > >>>
> > > >>> +/*
> > > >>> + * Currently just the FSCRYPT_SET_CONTEXT_MAX_SIZE, which is larger than the
> > > >>> + * current extent context size from fscrypt, so this should give us plenty of
> > > >>> + * breathing room for expansion later.
> > > >>> + */
> > > >>> +#define BTRFS_MAX_EXTENT_CTX_SIZE 40
> > > >>> +
> > > >>> +enum {
> > > >>> + BTRFS_ENCRYPTION_NONE,
> > > >>> + BTRFS_ENCRYPTION_FSCRYPT,
> > > >>> + BTRFS_NR_ENCRYPTION_TYPES,
> > > >>> +};
> > > >>> +
> > > >>> +struct btrfs_encryption_info {
> > > >>> + __le32 size;
> > > >>> + __u8 context[0];
> > > >>> +};
> > > >>> +
> > > >>> struct btrfs_file_extent_item {
> > > >>> /*
> > > >>> * transaction id that created this extent
> > > >>> @@ -1115,7 +1133,10 @@ struct btrfs_file_extent_item {
> > > >>> * always reflects the size uncompressed and without encoding.
> > > >>> */
> > > >>> __le64 num_bytes;
> > > >>> -
> > > >>> + /*
> > > >>> + * the encryption info, if any
> > > >>> + */
> > > >>> + struct btrfs_encryption_info encryption_info[0];
> > > >>
> > > >> Looking at this again, adding variable length data will make it hard to
> > > >> add more items to the file extent. We could not decide the version just
> > > >> by the size, as done in other structures.
> > > >
> > > > Checking the details of btrfs_file_extent_item I understand the item
> > > > is already variable size in case of inline extent.
> > >
> > > Yeah, but I'm not sure if that is a good example to follow, or a bad
> > > example to avoid.
> > >
> > > The biggest concern is for encrypted inline data extents.
> > > We need to put two variable sized data into a single item.
> > > (I know there are examples like btrfs_dir_item for XATTR, but again not
> > > sure if we should really follow that)
> >
> > Just for the record, with the state of the patches as of now, inline
> > extent encryption is not supported. And for example ext4 also merges
> > the encryption context with the inline data.
> > But if we wanted to implement encrypted inline extents it may be
> > easier for us to just add a new key storing the context. So perhaps we
> > can do it right away to cover all the cases in a generic way.
>
> For the record, I think separate key/item is a better option.
I have got this implemented. Though I'm not sure I like the end
result. Basically each extent now creates two items for the meta
needed for an extent. This doubles tree operations and example result
looks like this (with patched btrfs-progs):
> item 105 key (257 INODE_ITEM 0) itemoff 11219 itemsize 160
> generation 9 transid 9 size 86016 nbytes 81920
> block group 0 mode 100600 links 1 uid 0 gid 0 rdev 0
> sequence 95 flags 0x1000(UNKNOWN: 0x1000)
> atime 1764179848.703684571 (2025-11-26 18:57:28)
> ctime 1764179848.789259149 (2025-11-26 18:57:28)
> mtime 1764179848.789259149 (2025-11-26 18:57:28)
> otime 1764179848.703684571 (2025-11-26 18:57:28)
> item 106 key (257 INODE_REF 256) itemoff 11193 itemsize 26
> index 2 namelen 16 name: \270\2439\t\005\342\230\243\301~\363\f$\3608g
> item 107 key (257 FSCRYPT_INODE_CTX 0) itemoff 11153 itemsize 40
> value: 020104020000000069b2f6edeee720cce0577937eb8a675177d5a7f82d59cb4c7c8c5a33fde3c603
> item 108 key (257 FSCRYPT_CTX 4096) itemoff 11119 itemsize 34
> value: 010169b2f6edeee720cce0577937eb8a6751d0dd42ea7ba43ee8c55a2f79cbc890bd
> item 109 key (257 FSCRYPT_CTX 8192) itemoff 11085 itemsize 34
> value: 010169b2f6edeee720cce0577937eb8a6751c49b3ed9999cfb684992b30e01cabab2
> <snip>
> item 124 key (257 FSCRYPT_CTX 69632) itemoff 10575 itemsize 34
> value: 010169b2f6edeee720cce0577937eb8a6751da3728d22c66c1ae40d92d8b283cb393
> item 125 key (257 FSCRYPT_CTX 73728) itemoff 10541 itemsize 34
> value: 010169b2f6edeee720cce0577937eb8a675189848f22c27c6bbbfb06fe521571658c
> item 126 key (257 FSCRYPT_CTX 77824) itemoff 10507 itemsize 34
> value: 010169b2f6edeee720cce0577937eb8a67516c546baab142d3c37e64439c5d90f609
> item 127 key (257 FSCRYPT_CTX 81920) itemoff 10473 itemsize 34
> value: 010169b2f6edeee720cce0577937eb8a6751d1a28c6fcd2ce16b02858d614645f314
> item 128 key (257 EXTENT_DATA 4096) itemoff 10420 itemsize 53
> generation 9 type 1 (regular)
> extent data disk byte 13787136 nr 4096
> extent data offset 0 nr 4096 ram 4096
> extent compression 0 (none)
> extent encryption 1 (fscrypt)
> item 129 key (257 EXTENT_DATA 8192) itemoff 10367 itemsize 53
> generation 9 type 1 (regular)
> extent data disk byte 13778944 nr 4096
> extent data offset 0 nr 4096 ram 4096
> extent compression 0 (none)
> extent encryption 1 (fscrypt)
> item 130 key (257 EXTENT_DATA 12288) itemoff 10314 itemsize 53
> generation 9 type 1 (regular)
> extent data disk byte 13770752 nr 4096
> extent data offset 0 nr 4096 ram 4096
> extent compression 0 (none)
> extent encryption 1 (fscrypt)
> item 131 key (257 EXTENT_DATA 16384) itemoff 10261 itemsize 53
> generation 9 type 1 (regular)
> extent data disk byte 13762560 nr 4096
> extent data offset 0 nr 4096 ram 4096
> extent compression 0 (none)
> extent encryption 1 (fscrypt)
> <snip>
> item 144 key (257 EXTENT_DATA 69632) itemoff 9572 itemsize 53
> generation 9 type 1 (regular)
> extent data disk byte 13656064 nr 4096
> extent data offset 0 nr 4096 ram 4096
> extent compression 0 (none)
> extent encryption 1 (fscrypt)
> item 145 key (257 EXTENT_DATA 73728) itemoff 9519 itemsize 53
> generation 9 type 1 (regular)
> extent data disk byte 13647872 nr 4096
> extent data offset 0 nr 4096 ram 4096
> extent compression 0 (none)
> extent encryption 1 (fscrypt)
> item 146 key (257 EXTENT_DATA 77824) itemoff 9466 itemsize 53
> generation 9 type 1 (regular)
> extent data disk byte 13639680 nr 4096
> extent data offset 0 nr 4096 ram 4096
> extent compression 0 (none)
> extent encryption 1 (fscrypt)
> item 147 key (257 EXTENT_DATA 81920) itemoff 9413 itemsize 53
> generation 9 type 1 (regular)
> extent data disk byte 13631488 nr 4096
> extent data offset 0 nr 4096 ram 4096
> extent compression 0 (none)
> extent encryption 1 (fscrypt)
Basically the metadata needed for each extent is split into two keys.
That means that in some cases (which could actually be many cases)
getting the needed data for a given extent would end up reading from
two leaf nodes.
With this insight it actually makes more sense to append the
encryption context to the file extent item itself. We do this in a lot
of other keys as well. xattr dir items for another example. inode ref
itself as well. inlined data. Plain (not file) extent items, metadata
items... And so on and so on.
It seems to me we do this all the time, I'm not sure why the
opposition in this case?
The call is on you. I can send this version (after I make sure nothing
else broke) or the former one.
I'll also be happy to hear opinions from others. Qu expressed concerns
against inline crypt context before (the btrfs-progs implementation
needs to be further debugged for sure). Does it still hold with the
above being said?
--nX
^ permalink raw reply [flat|nested] 34+ messages in thread
end of thread, other threads:[~2025-11-27 8:40 UTC | newest]
Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-15 12:11 [PATCH 0/8] btrfs-progs: fscrypt updates Daniel Vacek
2025-10-15 12:11 ` [PATCH 1/8] btrfs-progs: check: fix max inline extent size Daniel Vacek
2025-10-15 12:11 ` [PATCH 2/8] btrfs-progs: add new FEATURE_INCOMPAT_ENCRYPT flag Daniel Vacek
2025-10-24 21:16 ` David Sterba
2025-10-15 12:11 ` [PATCH 3/8] btrfs-progs: start tracking extent encryption context info Daniel Vacek
2025-10-24 21:29 ` David Sterba
2025-10-24 22:43 ` Qu Wenruo
2025-11-05 8:28 ` Daniel Vacek
2025-11-05 8:22 ` Daniel Vacek
2025-11-05 8:27 ` Daniel Vacek
2025-11-05 9:12 ` Qu Wenruo
2025-11-05 10:55 ` Daniel Vacek
2025-11-26 14:11 ` David Sterba
2025-11-27 8:40 ` Daniel Vacek
2025-10-15 12:11 ` [PATCH 4/8] btrfs-progs: add inode encryption contexts Daniel Vacek
2025-10-15 12:11 ` [PATCH 5/8] btrfs-progs: interpret encrypted file extents Daniel Vacek
2025-11-02 22:26 ` Qu Wenruo
2025-11-03 9:57 ` Daniel Vacek
2025-11-05 7:46 ` Daniel Vacek
2025-10-15 12:11 ` [PATCH 6/8] btrfs-progs: handle fscrypt context items Daniel Vacek
2025-10-15 12:11 ` [PATCH 7/8] btrfs-progs: check: update inline extent length checking Daniel Vacek
2025-10-15 12:11 ` [PATCH 8/8] btrfs-progs: string-utils: do not escape space while printing Daniel Vacek
2025-10-17 16:43 ` David Sterba
2025-10-18 17:50 ` Daniel Vacek
2025-10-15 21:10 ` [PATCH 0/8] btrfs-progs: fscrypt updates Qu Wenruo
2025-10-15 21:19 ` Daniel Vacek
2025-10-15 21:20 ` Qu Wenruo
2025-10-16 15:16 ` Johannes Thumshirn
2025-10-17 20:54 ` Mark Harmstone
2025-10-24 21:10 ` David Sterba
2025-10-17 16:45 ` David Sterba
2025-10-18 18:01 ` Daniel Vacek
2025-11-04 14:56 ` David Sterba
-- strict thread matches above, loose matches on Subject: below --
2023-10-10 20:28 [PATCH 0/8] btrfs-progs: add fscrypt support Josef Bacik
2023-10-10 20:28 ` [PATCH 4/8] btrfs-progs: add inode encryption contexts Josef Bacik
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).