add patch avoid-infinite-loop-when-destroying-aborted-journal
[ext4-patch-queue.git] / use-transaction-when-adding-crypto-policy
blob071fd96e6beb7a0cac8262911f9c01020e62703c
1 ext4 crypto: use a jbd2 transaction when adding a crypto policy
3 Start a jbd2 transaction, and mark the inode dirty on the inode under
4 that transaction after setting the encrypt flag.  Otherwise if the
5 directory isn't modified after setting the crypto policy, the
6 encrypted flag might not survive the inode getting pushed out from
7 memory, or the the file system getting unmounted and remounted.
9 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
10 ---
11  fs/ext4/crypto_policy.c | 17 +++++++++++++++--
12  1 file changed, 15 insertions(+), 2 deletions(-)
14 diff --git a/fs/ext4/crypto_policy.c b/fs/ext4/crypto_policy.c
15 index 02c4e5d..a640ec2 100644
16 --- a/fs/ext4/crypto_policy.c
17 +++ b/fs/ext4/crypto_policy.c
18 @@ -12,6 +12,7 @@
19  #include <linux/string.h>
20  #include <linux/types.h>
22 +#include "ext4_jbd2.h"
23  #include "ext4.h"
24  #include "xattr.h"
26 @@ -49,7 +50,8 @@ static int ext4_create_encryption_context_from_policy(
27         struct inode *inode, const struct ext4_encryption_policy *policy)
28  {
29         struct ext4_encryption_context ctx;
30 -       int res = 0;
31 +       handle_t *handle;
32 +       int res, res2;
34         res = ext4_convert_inline_data(inode);
35         if (res)
36 @@ -78,11 +80,22 @@ static int ext4_create_encryption_context_from_policy(
37         BUILD_BUG_ON(sizeof(ctx.nonce) != EXT4_KEY_DERIVATION_NONCE_SIZE);
38         get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
40 +       handle = ext4_journal_start(inode, EXT4_HT_MISC,
41 +                                   ext4_jbd2_credits_xattr(inode));
42 +       if (IS_ERR(handle))
43 +               return PTR_ERR(handle);
44         res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
45                              EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
46                              sizeof(ctx), 0);
47 -       if (!res)
48 +       if (!res) {
49                 ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
50 +               res = ext4_mark_inode_dirty(handle, inode);
51 +               if (res)
52 +                       EXT4_ERROR_INODE(inode, "Failed to mark inode dirty");
53 +       }
54 +       res2 = ext4_journal_stop(handle);
55 +       if (!res)
56 +               res = res2;
57         return res;
58  }