| From 73b92a2a5e97d17cc4d5c4fe9d724d3273fb6fd2 Mon Sep 17 00:00:00 2001 |
| From: Sergey Karamov <skaramov@google.com> |
| Date: Sat, 10 Dec 2016 17:54:58 -0500 |
| Subject: ext4: do not perform data journaling when data is encrypted |
| |
| From: Sergey Karamov <skaramov@google.com> |
| |
| commit 73b92a2a5e97d17cc4d5c4fe9d724d3273fb6fd2 upstream. |
| |
| Currently data journalling is incompatible with encryption: enabling both |
| at the same time has never been supported by design, and would result in |
| unpredictable behavior. However, users are not precluded from turning on |
| both features simultaneously. This change programmatically replaces data |
| journaling for encrypted regular files with ordered data journaling mode. |
| |
| Background: |
| Journaling encrypted data has not been supported because it operates on |
| buffer heads of the page in the page cache. Namely, when the commit |
| happens, which could be up to five seconds after caching, the commit |
| thread uses the buffer heads attached to the page to copy the contents of |
| the page to the journal. With encryption, it would have been required to |
| keep the bounce buffer with ciphertext for up to the aforementioned five |
| seconds, since the page cache can only hold plaintext and could not be |
| used for journaling. Alternatively, it would be required to setup the |
| journal to initiate a callback at the commit time to perform deferred |
| encryption - in this case, not only would the data have to be written |
| twice, but it would also have to be encrypted twice. This level of |
| complexity was not justified for a mode that in practice is very rarely |
| used because of the overhead from the data journalling. |
| |
| Solution: |
| If data=journaled has been set as a mount option for a filesystem, or if |
| journaling is enabled on a regular file, do not perform journaling if the |
| file is also encrypted, instead fall back to the data=ordered mode for the |
| file. |
| |
| Rationale: |
| The intent is to allow seamless and proper filesystem operation when |
| journaling and encryption have both been enabled, and have these two |
| conflicting features gracefully resolved by the filesystem. |
| |
| Fixes: 4461471107b7 |
| Signed-off-by: Sergey Karamov <skaramov@google.com> |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/ext4/ext4_jbd2.h | 14 ++++++++------ |
| fs/ext4/super.c | 5 +++++ |
| 2 files changed, 13 insertions(+), 6 deletions(-) |
| |
| --- a/fs/ext4/ext4_jbd2.h |
| +++ b/fs/ext4/ext4_jbd2.h |
| @@ -414,17 +414,19 @@ static inline int ext4_inode_journal_mod |
| return EXT4_INODE_WRITEBACK_DATA_MODE; /* writeback */ |
| /* We do not support data journalling with delayed allocation */ |
| if (!S_ISREG(inode->i_mode) || |
| - test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) |
| - return EXT4_INODE_JOURNAL_DATA_MODE; /* journal data */ |
| - if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) && |
| - !test_opt(inode->i_sb, DELALLOC)) |
| + test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || |
| + (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) && |
| + !test_opt(inode->i_sb, DELALLOC))) { |
| + /* We do not support data journalling for encrypted data */ |
| + if (S_ISREG(inode->i_mode) && ext4_encrypted_inode(inode)) |
| + return EXT4_INODE_ORDERED_DATA_MODE; /* ordered */ |
| return EXT4_INODE_JOURNAL_DATA_MODE; /* journal data */ |
| + } |
| if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) |
| return EXT4_INODE_ORDERED_DATA_MODE; /* ordered */ |
| if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) |
| return EXT4_INODE_WRITEBACK_DATA_MODE; /* writeback */ |
| - else |
| - BUG(); |
| + BUG(); |
| } |
| |
| static inline int ext4_should_journal_data(struct inode *inode) |
| --- a/fs/ext4/super.c |
| +++ b/fs/ext4/super.c |
| @@ -3469,6 +3469,11 @@ static int ext4_fill_super(struct super_ |
| "both data=journal and dax"); |
| goto failed_mount; |
| } |
| + if (ext4_has_feature_encrypt(sb)) { |
| + ext4_msg(sb, KERN_WARNING, |
| + "encrypted files will use data=ordered " |
| + "instead of data journaling mode"); |
| + } |
| if (test_opt(sb, DELALLOC)) |
| clear_opt(sb, DELALLOC); |
| } else { |