add patch fix-ocfs2-corrupt-when-updating-journal-superblock-fails
[ext4-patch-queue.git] / stop-allocating-pages
blob646c39f9c97dffe7c48bdee964a46cdc1cf2a207
1 ext4 crypto: don't allocate a page when encrypting/decrypting file names
3 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
4 ---
5  fs/ext4/crypto_fname.c | 72 ++++++++++++++++++++----------------------------------------------------
6  fs/ext4/dir.c          |  3 +++
7  fs/ext4/ext4_crypto.h  |  2 --
8  fs/ext4/namei.c        |  4 ++++
9  fs/ext4/symlink.c      |  1 +
10  5 files changed, 28 insertions(+), 54 deletions(-)
12 diff --git a/fs/ext4/crypto_fname.c b/fs/ext4/crypto_fname.c
13 index ad5e328..23d7f1d 100644
14 --- a/fs/ext4/crypto_fname.c
15 +++ b/fs/ext4/crypto_fname.c
16 @@ -65,9 +65,9 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
17         struct crypto_ablkcipher *tfm = ctx->ctfm;
18         int res = 0;
19         char iv[EXT4_CRYPTO_BLOCK_SIZE];
20 -       struct scatterlist sg[1];
21 +       struct scatterlist src_sg, dst_sg;
22         int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);
23 -       char *workbuf;
24 +       char *workbuf, buf[32], *alloc_buf = NULL;
26         if (iname->len <= 0 || iname->len > ctx->lim)
27                 return -EIO;
28 @@ -78,20 +78,27 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
29         ciphertext_len = (ciphertext_len > ctx->lim)
30                         ? ctx->lim : ciphertext_len;
32 +       if (ciphertext_len <= sizeof(buf)) {
33 +               workbuf = buf;
34 +       } else {
35 +               alloc_buf = kmalloc(ciphertext_len, GFP_NOFS);
36 +               if (!alloc_buf)
37 +                       return -ENOMEM;
38 +               workbuf = alloc_buf;
39 +       }
41         /* Allocate request */
42         req = ablkcipher_request_alloc(tfm, GFP_NOFS);
43         if (!req) {
44                 printk_ratelimited(
45                     KERN_ERR "%s: crypto_request_alloc() failed\n", __func__);
46 +               kfree(alloc_buf);
47                 return -ENOMEM;
48         }
49         ablkcipher_request_set_callback(req,
50                 CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
51                 ext4_dir_crypt_complete, &ecr);
53 -       /* Map the workpage */
54 -       workbuf = kmap(ctx->workpage);
56         /* Copy the input */
57         memcpy(workbuf, iname->name, iname->len);
58         if (iname->len < ciphertext_len)
59 @@ -101,21 +108,16 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
60         memset(iv, 0, EXT4_CRYPTO_BLOCK_SIZE);
62         /* Create encryption request */
63 -       sg_init_table(sg, 1);
64 -       sg_set_page(sg, ctx->workpage, PAGE_SIZE, 0);
65 -       ablkcipher_request_set_crypt(req, sg, sg, ciphertext_len, iv);
66 +       sg_init_one(&src_sg, workbuf, ciphertext_len);
67 +       sg_init_one(&dst_sg, oname->name, ciphertext_len);
68 +       ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv);
69         res = crypto_ablkcipher_encrypt(req);
70         if (res == -EINPROGRESS || res == -EBUSY) {
71                 BUG_ON(req->base.data != &ecr);
72                 wait_for_completion(&ecr.completion);
73                 res = ecr.res;
74         }
75 -       if (res >= 0) {
76 -               /* Copy the result to output */
77 -               memcpy(oname->name, workbuf, ciphertext_len);
78 -               res = ciphertext_len;
79 -       }
80 -       kunmap(ctx->workpage);
81 +       kfree(alloc_buf);
82         ablkcipher_request_free(req);
83         if (res < 0) {
84                 printk_ratelimited(
85 @@ -139,11 +141,10 @@ static int ext4_fname_decrypt(struct ext4_fname_crypto_ctx *ctx,
86         struct ext4_str tmp_in[2], tmp_out[1];
87         struct ablkcipher_request *req = NULL;
88         DECLARE_EXT4_COMPLETION_RESULT(ecr);
89 -       struct scatterlist sg[1];
90 +       struct scatterlist src_sg, dst_sg;
91         struct crypto_ablkcipher *tfm = ctx->ctfm;
92         int res = 0;
93         char iv[EXT4_CRYPTO_BLOCK_SIZE];
94 -       char *workbuf;
96         if (iname->len <= 0 || iname->len > ctx->lim)
97                 return -EIO;
98 @@ -163,31 +164,19 @@ static int ext4_fname_decrypt(struct ext4_fname_crypto_ctx *ctx,
99                 CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
100                 ext4_dir_crypt_complete, &ecr);
102 -       /* Map the workpage */
103 -       workbuf = kmap(ctx->workpage);
105 -       /* Copy the input */
106 -       memcpy(workbuf, iname->name, iname->len);
108         /* Initialize IV */
109         memset(iv, 0, EXT4_CRYPTO_BLOCK_SIZE);
111         /* Create encryption request */
112 -       sg_init_table(sg, 1);
113 -       sg_set_page(sg, ctx->workpage, PAGE_SIZE, 0);
114 -       ablkcipher_request_set_crypt(req, sg, sg, iname->len, iv);
115 +       sg_init_one(&src_sg, iname->name, iname->len);
116 +       sg_init_one(&dst_sg, oname->name, oname->len);
117 +       ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
118         res = crypto_ablkcipher_decrypt(req);
119         if (res == -EINPROGRESS || res == -EBUSY) {
120                 BUG_ON(req->base.data != &ecr);
121                 wait_for_completion(&ecr.completion);
122                 res = ecr.res;
123         }
124 -       if (res >= 0) {
125 -               /* Copy the result to output */
126 -               memcpy(oname->name, workbuf, iname->len);
127 -               res = iname->len;
128 -       }
129 -       kunmap(ctx->workpage);
130         ablkcipher_request_free(req);
131         if (res < 0) {
132                 printk_ratelimited(
133 @@ -267,8 +256,6 @@ void ext4_free_fname_crypto_ctx(struct ext4_fname_crypto_ctx *ctx)
134                 crypto_free_ablkcipher(ctx->ctfm);
135         if (ctx->htfm && !IS_ERR(ctx->htfm))
136                 crypto_free_hash(ctx->htfm);
137 -       if (ctx->workpage && !IS_ERR(ctx->workpage))
138 -               __free_page(ctx->workpage);
139         kfree(ctx);
142 @@ -322,7 +309,6 @@ struct ext4_fname_crypto_ctx *ext4_alloc_fname_crypto_ctx(
143         ctx->ctfm_key_is_ready = 0;
144         ctx->ctfm = NULL;
145         ctx->htfm = NULL;
146 -       ctx->workpage = NULL;
147         return ctx;
150 @@ -390,24 +376,6 @@ struct ext4_fname_crypto_ctx *ext4_get_fname_crypto_ctx(
151                         ext4_put_fname_crypto_ctx(&ctx);
152                         return ERR_PTR(-ENOMEM);
153                 }
154 -               if (ctx->workpage == NULL)
155 -                       ctx->workpage = alloc_page(GFP_NOFS);
156 -               if (IS_ERR(ctx->workpage)) {
157 -                       res = PTR_ERR(ctx->workpage);
158 -                       printk(
159 -                           KERN_DEBUG "%s: error (%d) allocating work page\n",
160 -                           __func__, res);
161 -                       ctx->workpage = NULL;
162 -                       ext4_put_fname_crypto_ctx(&ctx);
163 -                       return ERR_PTR(res);
164 -               }
165 -               if (ctx->workpage == NULL) {
166 -                       printk(
167 -                           KERN_DEBUG "%s: could not allocate work page\n",
168 -                           __func__);
169 -                       ext4_put_fname_crypto_ctx(&ctx);
170 -                       return ERR_PTR(-ENOMEM);
171 -               }
172                 ctx->lim = max_ciphertext_len;
173                 crypto_ablkcipher_clear_flags(ctx->ctfm, ~0);
174                 crypto_tfm_set_flags(crypto_ablkcipher_tfm(ctx->ctfm),
175 diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
176 index 5665d82..d799d5d 100644
177 --- a/fs/ext4/dir.c
178 +++ b/fs/ext4/dir.c
179 @@ -247,9 +247,12 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
180                                             get_dtype(sb, de->file_type)))
181                                                 goto done;
182                                 } else {
183 +                                       int save_len = fname_crypto_str.len;
185                                         /* Directory is encrypted */
186                                         err = ext4_fname_disk_to_usr(enc_ctx,
187                                                 NULL, de, &fname_crypto_str);
188 +                                       fname_crypto_str.len = save_len;
189                                         if (err < 0)
190                                                 goto errout;
191                                         if (!dir_emit(ctx,
192 diff --git a/fs/ext4/ext4_crypto.h b/fs/ext4/ext4_crypto.h
193 index d75159c..552424a 100644
194 --- a/fs/ext4/ext4_crypto.h
195 +++ b/fs/ext4/ext4_crypto.h
196 @@ -123,10 +123,8 @@ struct ext4_str {
198  struct ext4_fname_crypto_ctx {
199         u32 lim;
200 -       char tmp_buf[EXT4_CRYPTO_BLOCK_SIZE];
201         struct crypto_ablkcipher *ctfm;
202         struct crypto_hash *htfm;
203 -       struct page *workpage;
204         struct ext4_encryption_key key;
205         unsigned flags : 8;
206         unsigned has_valid_key : 1;
207 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
208 index 752d4af..bf66e56 100644
209 --- a/fs/ext4/namei.c
210 +++ b/fs/ext4/namei.c
211 @@ -998,6 +998,8 @@ static int htree_dirblock_to_tree(struct file *dir_file,
212                                    hinfo->hash, hinfo->minor_hash, de,
213                                    &tmp_str);
214                 } else {
215 +                       int save_len = fname_crypto_str.len;
217                         /* Directory is encrypted */
218                         err = ext4_fname_disk_to_usr(ctx, hinfo, de,
219                                                      &fname_crypto_str);
220 @@ -1008,6 +1010,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
221                         err = ext4_htree_store_dirent(dir_file,
222                                    hinfo->hash, hinfo->minor_hash, de,
223                                         &fname_crypto_str);
224 +                       fname_crypto_str.len = save_len;
225                 }
226                 if (err != 0) {
227                         count = err;
228 @@ -3132,6 +3135,7 @@ static int ext4_symlink(struct inode *dir,
229                 istr.name = (const unsigned char *) symname;
230                 istr.len = len;
231                 ostr.name = sd->encrypted_path;
232 +               ostr.len = disk_link.len;
233                 err = ext4_fname_usr_to_disk(ctx, &istr, &ostr);
234                 ext4_put_fname_crypto_ctx(&ctx);
235                 if (err < 0)
236 diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
237 index ce2ed28..3428c51 100644
238 --- a/fs/ext4/symlink.c
239 +++ b/fs/ext4/symlink.c
240 @@ -74,6 +74,7 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
241                 goto errout;
242         }
243         pstr.name = paddr;
244 +       pstr.len = plen;
245         res = _ext4_fname_disk_to_usr(ctx, NULL, &cstr, &pstr);
246         if (res < 0)
247                 goto errout;