Clean up whitespace and fixed a bug in the context inheritance error path
[ext4-patch-queue.git] / enable-filename-encryption
blob587428181dc2ffe4ead03085b76bb32017436e0b
1 ext4 crypto: enable filename encryption
3 From: Michael Halcrow <mhalcrow@google.com>
5 Signed-off-by: Uday Savagaonkar <savagaon@google.com>
6 Signed-off-by: Ildar Muslukhov <ildarm@google.com>
7 Signed-off-by: Michael Halcrow <mhalcrow@google.com>
8 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
9 ---
10  fs/ext4/dir.c    | 64 +++++++++++++++++++++++++++++++++++++++++++++++++---------------
11  fs/ext4/ialloc.c | 21 +++++++++++++++++++--
12  2 files changed, 68 insertions(+), 17 deletions(-)
14 diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
15 index f67f955..2b6e0c8 100644
16 --- a/fs/ext4/dir.c
17 +++ b/fs/ext4/dir.c
18 @@ -110,7 +110,10 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
19         int err;
20         struct inode *inode = file_inode(file);
21         struct super_block *sb = inode->i_sb;
22 +       struct buffer_head *bh = NULL;
23         int dir_has_error = 0;
24 +       struct ext4_fname_crypto_ctx *enc_ctx = NULL;
25 +       struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
27         if (is_dx_dir(inode)) {
28                 err = ext4_dx_readdir(file, ctx);
29 @@ -127,17 +130,28 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
31         if (ext4_has_inline_data(inode)) {
32                 int has_inline_data = 1;
33 -               int ret = ext4_read_inline_dir(file, ctx,
34 +               err = ext4_read_inline_dir(file, ctx,
35                                            &has_inline_data);
36                 if (has_inline_data)
37 -                       return ret;
38 +                       return err;
39 +       }
41 +       enc_ctx = ext4_get_fname_crypto_ctx(inode, EXT4_NAME_LEN);
42 +       if (IS_ERR(enc_ctx))
43 +               return PTR_ERR(enc_ctx);
44 +       if (enc_ctx) {
45 +               err = ext4_fname_crypto_alloc_buffer(enc_ctx, EXT4_NAME_LEN,
46 +                                                    &fname_crypto_str);
47 +               if (err < 0) {
48 +                       ext4_put_fname_crypto_ctx(&enc_ctx);
49 +                       return err;
50 +               }
51         }
53         offset = ctx->pos & (sb->s_blocksize - 1);
55         while (ctx->pos < inode->i_size) {
56                 struct ext4_map_blocks map;
57 -               struct buffer_head *bh = NULL;
59                 map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
60                 map.m_len = 1;
61 @@ -180,6 +194,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
62                                         (unsigned long long)ctx->pos);
63                         ctx->pos += sb->s_blocksize - offset;
64                         brelse(bh);
65 +                       bh = NULL;
66                         continue;
67                 }
68                 set_buffer_verified(bh);
69 @@ -226,25 +241,44 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
70                         offset += ext4_rec_len_from_disk(de->rec_len,
71                                         sb->s_blocksize);
72                         if (le32_to_cpu(de->inode)) {
73 -                               if (!dir_emit(ctx, de->name,
74 -                                               de->name_len,
75 -                                               le32_to_cpu(de->inode),
76 -                                               get_dtype(sb, de->file_type))) {
77 -                                       brelse(bh);
78 -                                       return 0;
79 +                               if (enc_ctx == NULL) {
80 +                                       /* Directory is not encrypted */
81 +                                       if (!dir_emit(ctx, de->name,
82 +                                           de->name_len,
83 +                                           le32_to_cpu(de->inode),
84 +                                           get_dtype(sb, de->file_type)))
85 +                                               goto done;
86 +                               } else {
87 +                                       /* Directory is encrypted */
88 +                                       err = ext4_fname_disk_to_usr(enc_ctx,
89 +                                                       de, &fname_crypto_str);
90 +                                       if (err < 0)
91 +                                               goto errout;
92 +                                       if (!dir_emit(ctx,
93 +                                           fname_crypto_str.name, err,
94 +                                           le32_to_cpu(de->inode),
95 +                                           get_dtype(sb, de->file_type)))
96 +                                               goto done;
97                                 }
98                         }
99                         ctx->pos += ext4_rec_len_from_disk(de->rec_len,
100                                                 sb->s_blocksize);
101                 }
102 -               offset = 0;
103 +               if ((ctx->pos < inode->i_size) && !dir_relax(inode))
104 +                       goto done;
105                 brelse(bh);
106 -               if (ctx->pos < inode->i_size) {
107 -                       if (!dir_relax(inode))
108 -                               return 0;
109 -               }
110 +               bh = NULL;
111 +               offset = 0;
112         }
113 -       return 0;
114 +done:
115 +       err = 0;
116 +errout:
117 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
118 +       ext4_put_fname_crypto_ctx(&enc_ctx);
119 +       ext4_fname_crypto_free_buffer(&fname_crypto_str);
120 +#endif
121 +       brelse(bh);
122 +       return err;
125  static inline int is_32bit_api(void)
126 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
127 index e554ca3..8f37c9e 100644
128 --- a/fs/ext4/ialloc.c
129 +++ b/fs/ext4/ialloc.c
130 @@ -1034,11 +1034,28 @@ got:
131         ext4_set_inode_state(inode, EXT4_STATE_NEW);
133         ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
135 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
136 +       if ((sbi->s_file_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID) &&
137 +           (sbi->s_dir_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID)) {
138 +               ei->i_inline_off = 0;
139 +               if (EXT4_HAS_INCOMPAT_FEATURE(sb,
140 +                       EXT4_FEATURE_INCOMPAT_INLINE_DATA))
141 +                       ext4_set_inode_state(inode,
142 +                       EXT4_STATE_MAY_INLINE_DATA);
143 +       } else {
144 +               /* Inline data and encryption are incompatible
145 +                * We turn off inline data since encryption is enabled */
146 +               ei->i_inline_off = 1;
147 +               if (EXT4_HAS_INCOMPAT_FEATURE(sb,
148 +                       EXT4_FEATURE_INCOMPAT_INLINE_DATA))
149 +                       ext4_clear_inode_state(inode,
150 +                       EXT4_STATE_MAY_INLINE_DATA);
151 +       }
152 +#else
153         ei->i_inline_off = 0;
154         if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_INLINE_DATA))
155                 ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
157 +#endif
158         ret = inode;
159         err = dquot_alloc_inode(inode);
160         if (err)