* [PATCH v7 1/6] btrfs: disable various operations on encrypted inodes
2025-11-18 16:00 [PATCH v7 0/7] btrfs: add fscrypt support, PART 1 Daniel Vacek
@ 2025-11-18 16:00 ` Daniel Vacek
2025-11-18 16:00 ` [PATCH v7 2/6] btrfs: disable verity " Daniel Vacek
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Daniel Vacek @ 2025-11-18 16:00 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba
Cc: Daniel Vacek, linux-btrfs, linux-kernel, Omar Sandoval,
Sweet Tea Dorminy, Daniel Vacek
From: Omar Sandoval <osandov@osandov.com>
Initially, only normal data extents will be encrypted. This change
forbids various other bits:
- allows reflinking only if both inodes have the same encryption status
- disable inline data on encrypted inodes
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Daniel Vacek <neelx@suse.com>
--
v5 was 'Reviewed-by: Boris Burkov <boris@bur.io>' but the rebase changed
the code a bit so dropping.
https://lore.kernel.org/linux-btrfs/20240124195303.GC1789919@zen.localdomain/
Signed-off-by: Daniel Vacek <neelx.g@gmail.com>
---
fs/btrfs/inode.c | 4 ++++
fs/btrfs/reflink.c | 7 +++++++
2 files changed, 11 insertions(+)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index f71a5f7f55b9..8e13117eca16 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -592,6 +592,10 @@ static bool can_cow_file_range_inline(struct btrfs_inode *inode,
if (size < i_size_read(&inode->vfs_inode))
return false;
+ /* Encrypted file cannot be inlined. */
+ if (IS_ENCRYPTED(&inode->vfs_inode))
+ return false;
+
return true;
}
diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c
index 775a32a7953a..3c9c570d6493 100644
--- a/fs/btrfs/reflink.c
+++ b/fs/btrfs/reflink.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/blkdev.h>
+#include <linux/fscrypt.h>
#include <linux/iversion.h>
#include "ctree.h"
#include "fs.h"
@@ -789,6 +790,12 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
ASSERT(inode_in->vfs_inode.i_sb == inode_out->vfs_inode.i_sb);
}
+ /*
+ * Can only reflink encrypted files if both files are encrypted.
+ */
+ if (IS_ENCRYPTED(&inode_in->vfs_inode) != IS_ENCRYPTED(&inode_out->vfs_inode))
+ return -EINVAL;
+
/* Don't make the dst file partly checksummed */
if ((inode_in->flags & BTRFS_INODE_NODATASUM) !=
(inode_out->flags & BTRFS_INODE_NODATASUM)) {
--
2.51.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v7 2/6] btrfs: disable verity on encrypted inodes
2025-11-18 16:00 [PATCH v7 0/7] btrfs: add fscrypt support, PART 1 Daniel Vacek
2025-11-18 16:00 ` [PATCH v7 1/6] btrfs: disable various operations on encrypted inodes Daniel Vacek
@ 2025-11-18 16:00 ` Daniel Vacek
2025-11-18 16:00 ` [PATCH v7 3/6] btrfs: add orig_logical to btrfs_bio Daniel Vacek
` (4 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Daniel Vacek @ 2025-11-18 16:00 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba
Cc: Daniel Vacek, linux-btrfs, linux-kernel, Sweet Tea Dorminy,
Boris Burkov, Daniel Vacek
From: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Right now there isn't a way to encrypt things that aren't either
filenames in directories or data on blocks on disk with extent
encryption, so for now, disable verity usage with encryption on btrfs.
fscrypt with fsverity should be possible and it can be implemented
in the future.
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Daniel Vacek <neelx.g@gmail.com>
---
fs/btrfs/verity.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c
index 16f5580cba55..06dfcb461f53 100644
--- a/fs/btrfs/verity.c
+++ b/fs/btrfs/verity.c
@@ -578,6 +578,9 @@ static int btrfs_begin_enable_verity(struct file *filp)
btrfs_assert_inode_locked(inode);
+ if (IS_ENCRYPTED(&inode->vfs_inode))
+ return -EOPNOTSUPP;
+
if (test_bit(BTRFS_INODE_VERITY_IN_PROGRESS, &inode->runtime_flags))
return -EBUSY;
--
2.51.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v7 3/6] btrfs: add orig_logical to btrfs_bio
2025-11-18 16:00 [PATCH v7 0/7] btrfs: add fscrypt support, PART 1 Daniel Vacek
2025-11-18 16:00 ` [PATCH v7 1/6] btrfs: disable various operations on encrypted inodes Daniel Vacek
2025-11-18 16:00 ` [PATCH v7 2/6] btrfs: disable verity " Daniel Vacek
@ 2025-11-18 16:00 ` Daniel Vacek
2025-11-18 16:00 ` [PATCH v7 4/6] btrfs: don't rewrite ret from inode_permission Daniel Vacek
` (3 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Daniel Vacek @ 2025-11-18 16:00 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba
Cc: Daniel Vacek, linux-btrfs, linux-kernel, Daniel Vacek
From: Josef Bacik <josef@toxicpanda.com>
When checksumming the encrypted bio on writes we need to know which
logical address this checksum is for. At the point where we get the
encrypted bio the bi_sector is the physical location on the target disk,
so we need to save the original logical offset in the btrfs_bio. Then
we can use this when csum'ing the bio instead of the
bio->iter.bi_sector.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Daniel Vacek <neelx.g@gmail.com>
---
fs/btrfs/bio.c | 10 ++++++++++
fs/btrfs/bio.h | 2 ++
fs/btrfs/file-item.c | 2 +-
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c
index 1b38e3ee0a33..4a7bef895b97 100644
--- a/fs/btrfs/bio.c
+++ b/fs/btrfs/bio.c
@@ -94,6 +94,8 @@ static struct btrfs_bio *btrfs_split_bio(struct btrfs_fs_info *fs_info,
if (bbio_has_ordered_extent(bbio)) {
refcount_inc(&orig_bbio->ordered->refs);
bbio->ordered = orig_bbio->ordered;
+ bbio->orig_logical = orig_bbio->orig_logical;
+ orig_bbio->orig_logical += map_length;
}
bbio->csum_search_commit_root = orig_bbio->csum_search_commit_root;
atomic_inc(&orig_bbio->pending_ios);
@@ -765,6 +767,14 @@ static bool btrfs_submit_chunk(struct btrfs_bio *bbio, int mirror_num)
goto end_bbio;
}
+ /*
+ * For fscrypt writes we will get the encrypted bio after we've
+ * remapped our bio to the physical disk location, so we need to
+ * save the original bytenr so we know what we're checksumming.
+ */
+ if (bio_op(bio) == REQ_OP_WRITE && is_data_bbio(bbio))
+ bbio->orig_logical = logical;
+
map_length = min(map_length, length);
if (use_append)
map_length = btrfs_append_map_length(bbio, map_length);
diff --git a/fs/btrfs/bio.h b/fs/btrfs/bio.h
index 035145909b00..56279b7f3b2a 100644
--- a/fs/btrfs/bio.h
+++ b/fs/btrfs/bio.h
@@ -52,6 +52,7 @@ struct btrfs_bio {
* - pointer to the checksums for this bio
* - original physical address from the allocator
* (for zone append only)
+ * - original logical address, used for checksumming fscrypt bios.
*/
struct {
struct btrfs_ordered_extent *ordered;
@@ -60,6 +61,7 @@ struct btrfs_bio {
struct completion csum_done;
struct bvec_iter csum_saved_iter;
u64 orig_physical;
+ u64 orig_logical;
};
/* For metadata reads: parentness verification. */
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index b17632ea085f..14e5257f0f04 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -824,7 +824,7 @@ int btrfs_csum_one_bio(struct btrfs_bio *bbio, bool async)
if (!sums)
return -ENOMEM;
- sums->logical = bio->bi_iter.bi_sector << SECTOR_SHIFT;
+ sums->logical = bbio->orig_logical;
sums->len = bio->bi_iter.bi_size;
INIT_LIST_HEAD(&sums->list);
bbio->sums = sums;
--
2.51.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v7 4/6] btrfs: don't rewrite ret from inode_permission
2025-11-18 16:00 [PATCH v7 0/7] btrfs: add fscrypt support, PART 1 Daniel Vacek
` (2 preceding siblings ...)
2025-11-18 16:00 ` [PATCH v7 3/6] btrfs: add orig_logical to btrfs_bio Daniel Vacek
@ 2025-11-18 16:00 ` Daniel Vacek
2025-11-18 16:00 ` [PATCH v7 5/6] btrfs: move inode_to_path higher in backref.c Daniel Vacek
` (2 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: Daniel Vacek @ 2025-11-18 16:00 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba
Cc: Daniel Vacek, linux-btrfs, linux-kernel, Daniel Vacek
From: Josef Bacik <josef@toxicpanda.com>
In our user safe ino resolve ioctl we'll just turn any ret into -EACCES
from inode_permission. This is redundant, and could potentially be
wrong if we had an ENOMEM in the security layer or some such other
error, so simply return the actual return value.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Daniel Vacek <neelx.g@gmail.com>
---
fs/btrfs/ioctl.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 1920caf8d308..c2d992f5ce7d 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1910,10 +1910,8 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
ret = inode_permission(idmap, &temp_inode->vfs_inode,
MAY_READ | MAY_EXEC);
iput(&temp_inode->vfs_inode);
- if (ret) {
- ret = -EACCES;
+ if (ret)
goto out_put;
- }
if (key.offset == upper_limit)
break;
--
2.51.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v7 5/6] btrfs: move inode_to_path higher in backref.c
2025-11-18 16:00 [PATCH v7 0/7] btrfs: add fscrypt support, PART 1 Daniel Vacek
` (3 preceding siblings ...)
2025-11-18 16:00 ` [PATCH v7 4/6] btrfs: don't rewrite ret from inode_permission Daniel Vacek
@ 2025-11-18 16:00 ` Daniel Vacek
2025-11-18 16:00 ` [PATCH v7 6/6] btrfs: don't search back for dir inode item in INO_LOOKUP_USER Daniel Vacek
2025-11-18 16:10 ` [PATCH v7 0/7] btrfs: add fscrypt support, PART 1 Daniel Vacek
6 siblings, 0 replies; 9+ messages in thread
From: Daniel Vacek @ 2025-11-18 16:00 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba
Cc: Daniel Vacek, linux-btrfs, linux-kernel, Daniel Vacek
From: Josef Bacik <josef@toxicpanda.com>
We have a prototype and then the definition lower below, we don't need
to do this, simply move the function to where the prototype is.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Daniel Vacek <neelx.g@gmail.com>
---
fs/btrfs/backref.c | 68 ++++++++++++++++++++++------------------------
1 file changed, 32 insertions(+), 36 deletions(-)
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 78da47a3d00e..bd913e3c356f 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -2574,8 +2574,39 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
return iterate_extent_inodes(&walk_ctx, false, build_ino_list, ctx);
}
+/*
+ * returns 0 if the path could be dumped (probably truncated)
+ * returns <0 in case of an error
+ */
static int inode_to_path(u64 inum, u32 name_len, unsigned long name_off,
- struct extent_buffer *eb, struct inode_fs_paths *ipath);
+ struct extent_buffer *eb, struct inode_fs_paths *ipath)
+{
+ char *fspath;
+ char *fspath_min;
+ int i = ipath->fspath->elem_cnt;
+ const int s_ptr = sizeof(char *);
+ u32 bytes_left;
+
+ bytes_left = ipath->fspath->bytes_left > s_ptr ? ipath->fspath->bytes_left - s_ptr : 0;
+
+ fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr;
+ fspath = btrfs_ref_to_path(ipath->fs_root, ipath->btrfs_path, name_len,
+ name_off, eb, inum, fspath_min, bytes_left);
+ if (IS_ERR(fspath))
+ return PTR_ERR(fspath);
+
+ if (fspath > fspath_min) {
+ ipath->fspath->val[i] = (u64)(unsigned long)fspath;
+ ++ipath->fspath->elem_cnt;
+ ipath->fspath->bytes_left = fspath - fspath_min;
+ } else {
+ ++ipath->fspath->elem_missed;
+ ipath->fspath->bytes_missing += fspath_min - fspath;
+ ipath->fspath->bytes_left = 0;
+ }
+
+ return 0;
+}
static int iterate_inode_refs(u64 inum, struct inode_fs_paths *ipath)
{
@@ -2700,41 +2731,6 @@ static int iterate_inode_extrefs(u64 inum, struct inode_fs_paths *ipath)
return ret;
}
-/*
- * returns 0 if the path could be dumped (probably truncated)
- * returns <0 in case of an error
- */
-static int inode_to_path(u64 inum, u32 name_len, unsigned long name_off,
- struct extent_buffer *eb, struct inode_fs_paths *ipath)
-{
- char *fspath;
- char *fspath_min;
- int i = ipath->fspath->elem_cnt;
- const int s_ptr = sizeof(char *);
- u32 bytes_left;
-
- bytes_left = ipath->fspath->bytes_left > s_ptr ?
- ipath->fspath->bytes_left - s_ptr : 0;
-
- fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr;
- fspath = btrfs_ref_to_path(ipath->fs_root, ipath->btrfs_path, name_len,
- name_off, eb, inum, fspath_min, bytes_left);
- if (IS_ERR(fspath))
- return PTR_ERR(fspath);
-
- if (fspath > fspath_min) {
- ipath->fspath->val[i] = (u64)(unsigned long)fspath;
- ++ipath->fspath->elem_cnt;
- ipath->fspath->bytes_left = fspath - fspath_min;
- } else {
- ++ipath->fspath->elem_missed;
- ipath->fspath->bytes_missing += fspath_min - fspath;
- ipath->fspath->bytes_left = 0;
- }
-
- return 0;
-}
-
/*
* this dumps all file system paths to the inode into the ipath struct, provided
* is has been created large enough. each path is zero-terminated and accessed
--
2.51.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v7 6/6] btrfs: don't search back for dir inode item in INO_LOOKUP_USER
2025-11-18 16:00 [PATCH v7 0/7] btrfs: add fscrypt support, PART 1 Daniel Vacek
` (4 preceding siblings ...)
2025-11-18 16:00 ` [PATCH v7 5/6] btrfs: move inode_to_path higher in backref.c Daniel Vacek
@ 2025-11-18 16:00 ` Daniel Vacek
2025-11-18 16:10 ` [PATCH v7 0/7] btrfs: add fscrypt support, PART 1 Daniel Vacek
6 siblings, 0 replies; 9+ messages in thread
From: Daniel Vacek @ 2025-11-18 16:00 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba
Cc: Daniel Vacek, linux-btrfs, linux-kernel, Daniel Vacek
From: Josef Bacik <josef@toxicpanda.com>
We don't need to search back to the inode item, the directory inode
number is in key.offset, so simply use that. If we can't find the
directory we'll get an ENOENT at the iget.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Daniel Vacek <neelx.g@gmail.com>
---
fs/btrfs/ioctl.c | 23 +++--------------------
1 file changed, 3 insertions(+), 20 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index c2d992f5ce7d..69df5765acfa 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1822,7 +1822,7 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
struct btrfs_root_ref *rref;
struct btrfs_root *root = NULL;
struct btrfs_path *path;
- struct btrfs_key key, key2;
+ struct btrfs_key key;
struct extent_buffer *leaf;
char *ptr;
int slot;
@@ -1877,24 +1877,6 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
read_extent_buffer(leaf, ptr,
(unsigned long)(iref + 1), len);
- /* Check the read+exec permission of this directory */
- ret = btrfs_previous_item(root, path, dirid,
- BTRFS_INODE_ITEM_KEY);
- if (ret < 0) {
- goto out_put;
- } else if (ret > 0) {
- ret = -ENOENT;
- goto out_put;
- }
-
- leaf = path->nodes[0];
- slot = path->slots[0];
- btrfs_item_key_to_cpu(leaf, &key2, slot);
- if (key2.objectid != dirid) {
- ret = -ENOENT;
- goto out_put;
- }
-
/*
* We don't need the path anymore, so release it and
* avoid deadlocks and lockdep warnings in case
@@ -1902,11 +1884,12 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
* btree and lock the same leaf.
*/
btrfs_release_path(path);
- temp_inode = btrfs_iget(key2.objectid, root);
+ temp_inode = btrfs_iget(key.offset, root);
if (IS_ERR(temp_inode)) {
ret = PTR_ERR(temp_inode);
goto out_put;
}
+ /* Check the read+exec permission of this directory */
ret = inode_permission(idmap, &temp_inode->vfs_inode,
MAY_READ | MAY_EXEC);
iput(&temp_inode->vfs_inode);
--
2.51.0
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v7 0/7] btrfs: add fscrypt support, PART 1
2025-11-18 16:00 [PATCH v7 0/7] btrfs: add fscrypt support, PART 1 Daniel Vacek
` (5 preceding siblings ...)
2025-11-18 16:00 ` [PATCH v7 6/6] btrfs: don't search back for dir inode item in INO_LOOKUP_USER Daniel Vacek
@ 2025-11-18 16:10 ` Daniel Vacek
6 siblings, 0 replies; 9+ messages in thread
From: Daniel Vacek @ 2025-11-18 16:10 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba; +Cc: linux-btrfs, linux-kernel
Please, disregard this v7. I misconfigured my email. I'm sorry about the noise.
--nX
On Tue, 18 Nov 2025 at 17:01, Daniel Vacek <neelx@suse.com> wrote:
>
> This is a revive of former work [1] of Omar, Sweet Tea and Josef to bring
> native encryption support to btrfs.
>
> It will come in more parts. The first part this time is splitting the simple
> and isolated stuff out first to reduce the size of the final patchset.
>
> Changes:
> * v7 - Drop the checksum patch for now. It will make more sense later.
> - Drop the btrfs/330 fix. It seems no longer needed after the years.
> * v6 vs v5 [1] is mostly rebase to the latest for-next and cleaning up the
> conflicts.
>
> The remaining part needs further cleanup and a bit of redesign and it will
> follow later.
>
> [1] https://lore.kernel.org/linux-btrfs/cover.1706116485.git.josef@toxicpanda.com/
>
> Josef Bacik (4):
> btrfs: add orig_logical to btrfs_bio
> btrfs: don't rewrite ret from inode_permission
> btrfs: move inode_to_path higher in backref.c
> btrfs: don't search back for dir inode item in INO_LOOKUP_USER
>
> Omar Sandoval (1):
> btrfs: disable various operations on encrypted inodes
>
> Sweet Tea Dorminy (1):
> btrfs: disable verity on encrypted inodes
>
> fs/btrfs/backref.c | 68 +++++++++++++++++++++-----------------------
> fs/btrfs/bio.c | 10 +++++++
> fs/btrfs/bio.h | 2 ++
> fs/btrfs/file-item.c | 2 +-
> fs/btrfs/inode.c | 4 +++
> fs/btrfs/ioctl.c | 27 +++---------------
> fs/btrfs/reflink.c | 7 +++++
> fs/btrfs/verity.c | 3 ++
> 8 files changed, 63 insertions(+), 60 deletions(-)
>
> --
> 2.51.0
>
^ permalink raw reply [flat|nested] 9+ messages in thread