Add fix to add-get_inode_usage-callback-to-transfer-multi-inode-charges
[ext4-patch-queue.git] / fix-ext4_new_inode-journal-credits-calculation
blob9b6c9e9b58947bb434190df74d8d88caf5414c44
1 ext4: fix __ext4_new_inode() journal credits calculation
3 From: Tahsin Erdogan <tahsin@google.com>
5 ea_inode feature allows creating extended attributes that are up to
6 64k in size. Update __ext4_new_inode() to pick increased credit limits.
8 To avoid overallocating too many journal credits, update
9 __ext4_xattr_set_credits() to make a distinction between xattr create
10 vs update. This helps __ext4_new_inode() because all attributes are
11 known to be new, so we can save credits that are normally needed to
12 delete old values.
14 Also, have fscrypt specify its maximum context size so that we don't
15 end up allocating credits for 64k size.
17 Signed-off-by: Tahsin Erdogan <tahsin@google.com>
18 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
19 ---
20  fs/crypto/policy.c             |  1 +
21  fs/ext4/acl.c                  | 13 ++++++------
22  fs/ext4/ialloc.c               | 26 +++++++++++++++++-------
23  fs/ext4/super.c                |  3 ++-
24  fs/ext4/xattr.c                | 46 +++++++++++++++++++++++++-----------------
25  fs/ext4/xattr.h                |  5 ++++-
26  include/linux/fscrypt_common.h |  3 +++
27  7 files changed, 63 insertions(+), 34 deletions(-)
29 diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
30 index 210976e7a269..94becf5a1519 100644
31 --- a/fs/crypto/policy.c
32 +++ b/fs/crypto/policy.c
33 @@ -260,6 +260,7 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child,
34         memcpy(ctx.master_key_descriptor, ci->ci_master_key,
35                FS_KEY_DESCRIPTOR_SIZE);
36         get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
37 +       BUILD_BUG_ON(sizeof(ctx) != FSCRYPT_SET_CONTEXT_MAX_SIZE);
38         res = parent->i_sb->s_cop->set_context(child, &ctx,
39                                                 sizeof(ctx), fs_data);
40         if (res)
41 diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
42 index 8db03e5c78bc..09441ae07a5b 100644
43 --- a/fs/ext4/acl.c
44 +++ b/fs/ext4/acl.c
45 @@ -183,7 +183,7 @@ ext4_get_acl(struct inode *inode, int type)
46   */
47  static int
48  __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
49 -            struct posix_acl *acl)
50 +            struct posix_acl *acl, int xattr_flags)
51  {
52         int name_index;
53         void *value = NULL;
54 @@ -218,7 +218,7 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
55         }
57         error = ext4_xattr_set_handle(handle, inode, name_index, "",
58 -                                     value, size, 0);
59 +                                     value, size, xattr_flags);
61         kfree(value);
62         if (!error)
63 @@ -238,7 +238,8 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type)
64         if (error)
65                 return error;
66  retry:
67 -       error = ext4_xattr_set_credits(inode, acl_size, &credits);
68 +       error = ext4_xattr_set_credits(inode, acl_size, false /* is_create */,
69 +                                      &credits);
70         if (error)
71                 return error;
73 @@ -246,7 +247,7 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type)
74         if (IS_ERR(handle))
75                 return PTR_ERR(handle);
77 -       error = __ext4_set_acl(handle, inode, type, acl);
78 +       error = __ext4_set_acl(handle, inode, type, acl, 0 /* xattr_flags */);
79         ext4_journal_stop(handle);
80         if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
81                 goto retry;
82 @@ -271,13 +272,13 @@ ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
84         if (default_acl) {
85                 error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT,
86 -                                      default_acl);
87 +                                      default_acl, XATTR_CREATE);
88                 posix_acl_release(default_acl);
89         }
90         if (acl) {
91                 if (!error)
92                         error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS,
93 -                                              acl);
94 +                                              acl, XATTR_CREATE);
95                 posix_acl_release(acl);
96         }
97         return error;
98 diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
99 index 0c79e3efcaf7..21a2538afcc2 100644
100 --- a/fs/ext4/ialloc.c
101 +++ b/fs/ext4/ialloc.c
102 @@ -766,11 +766,13 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
103         if (!dir || !dir->i_nlink)
104                 return ERR_PTR(-EPERM);
106 -       if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb))))
107 +       sb = dir->i_sb;
108 +       sbi = EXT4_SB(sb);
110 +       if (unlikely(ext4_forced_shutdown(sbi)))
111                 return ERR_PTR(-EIO);
113 -       if ((ext4_encrypted_inode(dir) ||
114 -            DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) &&
115 +       if ((ext4_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) &&
116             (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) &&
117             !(i_flags & EXT4_EA_INODE_FL)) {
118                 err = fscrypt_get_encryption_info(dir);
119 @@ -778,19 +780,29 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
120                         return ERR_PTR(err);
121                 if (!fscrypt_has_encryption_key(dir))
122                         return ERR_PTR(-ENOKEY);
123 -               if (!handle)
124 -                       nblocks += EXT4_DATA_TRANS_BLOCKS(dir->i_sb);
125                 encrypt = 1;
126         }
128 -       sb = dir->i_sb;
129 +       if (!handle && sbi->s_journal && !(i_flags & EXT4_EA_INODE_FL)) {
130 +               /*
131 +                * 2 ea entries for ext4_init_acl(), 2 for ext4_init_security().
132 +                */
133 +               nblocks += 4 * __ext4_xattr_set_credits(sb, NULL /* inode */,
134 +                                       NULL /* block_bh */, XATTR_SIZE_MAX,
135 +                                       true /* is_create */);
136 +               if (encrypt)
137 +                       nblocks += __ext4_xattr_set_credits(sb,
138 +                                       NULL /* inode */, NULL /* block_bh */,
139 +                                       FSCRYPT_SET_CONTEXT_MAX_SIZE,
140 +                                       true /* is_create */);
141 +       }
143         ngroups = ext4_get_groups_count(sb);
144         trace_ext4_request_inode(dir, mode);
145         inode = new_inode(sb);
146         if (!inode)
147                 return ERR_PTR(-ENOMEM);
148         ei = EXT4_I(inode);
149 -       sbi = EXT4_SB(sb);
151         /*
152          * Initialize owners and quota early so that we don't have to account
153 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
154 index 56c971807df5..f666042a3d58 100644
155 --- a/fs/ext4/super.c
156 +++ b/fs/ext4/super.c
157 @@ -1194,7 +1194,8 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
158         if (res)
159                 return res;
160  retry:
161 -       res = ext4_xattr_set_credits(inode, len, &credits);
162 +       res = ext4_xattr_set_credits(inode, len, false /* is_create */,
163 +                                    &credits);
164         if (res)
165                 return res;
167 diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
168 index 624aad69991d..1f617ffb775a 100644
169 --- a/fs/ext4/xattr.c
170 +++ b/fs/ext4/xattr.c
171 @@ -829,11 +829,10 @@ static void ext4_xattr_inode_free_quota(struct inode *inode, size_t len)
172         dquot_free_inode(inode);
175 -static int __ext4_xattr_set_credits(struct inode *inode,
176 -                                   struct buffer_head *block_bh,
177 -                                   size_t value_len)
178 +int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode,
179 +                            struct buffer_head *block_bh, size_t value_len,
180 +                            bool is_create)
182 -       struct super_block *sb = inode->i_sb;
183         int credits;
184         int blocks;
186 @@ -859,7 +858,7 @@ static int __ext4_xattr_set_credits(struct inode *inode,
187          * In case of inline data, we may push out the data to a block,
188          * so we need to reserve credits for this eventuality
189          */
190 -       if (ext4_has_inline_data(inode))
191 +       if (inode && ext4_has_inline_data(inode))
192                 credits += ext4_writepage_trans_blocks(inode) + 1;
194         /* We are done if ea_inode feature is not enabled. */
195 @@ -881,19 +880,23 @@ static int __ext4_xattr_set_credits(struct inode *inode,
196         /* Blocks themselves. */
197         credits += blocks;
199 -       /* Dereference ea_inode holding old xattr value.
200 -        * Old ea_inode, inode map, block bitmap, group descriptor.
201 -        */
202 -       credits += 4;
203 +       if (!is_create) {
204 +               /* Dereference ea_inode holding old xattr value.
205 +                * Old ea_inode, inode map, block bitmap, group descriptor.
206 +                */
207 +               credits += 4;
209 -       /* Data blocks for old ea_inode. */
210 -       blocks = XATTR_SIZE_MAX >> sb->s_blocksize_bits;
211 +               /* Data blocks for old ea_inode. */
212 +               blocks = XATTR_SIZE_MAX >> sb->s_blocksize_bits;
214 -       /* Indirection block or one level of extent tree for old ea_inode. */
215 -       blocks += 1;
216 +               /* Indirection block or one level of extent tree for old
217 +                * ea_inode.
218 +                */
219 +               blocks += 1;
221 -       /* Block bitmap and group descriptor updates for each block. */
222 -       credits += blocks * 2;
223 +               /* Block bitmap and group descriptor updates for each block. */
224 +               credits += blocks * 2;
225 +       }
227         /* We may need to clone the existing xattr block in which case we need
228          * to increment ref counts for existing ea_inodes referenced by it.
229 @@ -2262,7 +2265,9 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
230                         goto cleanup;
231                 }
233 -               credits = __ext4_xattr_set_credits(inode, bh, value_len);
234 +               credits = __ext4_xattr_set_credits(inode->i_sb, inode, bh,
235 +                                                  value_len,
236 +                                                  flags & XATTR_CREATE);
237                 brelse(bh);
239                 if (!ext4_handle_has_enough_credits(handle, credits)) {
240 @@ -2369,7 +2374,8 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
241         return error;
244 -int ext4_xattr_set_credits(struct inode *inode, size_t value_len, int *credits)
245 +int ext4_xattr_set_credits(struct inode *inode, size_t value_len,
246 +                          bool is_create, int *credits)
248         struct buffer_head *bh;
249         int err;
250 @@ -2385,7 +2391,8 @@ int ext4_xattr_set_credits(struct inode *inode, size_t value_len, int *credits)
251         if (IS_ERR(bh)) {
252                 err = PTR_ERR(bh);
253         } else {
254 -               *credits = __ext4_xattr_set_credits(inode, bh, value_len);
255 +               *credits = __ext4_xattr_set_credits(inode->i_sb, inode, bh,
256 +                                                   value_len, is_create);
257                 brelse(bh);
258                 err = 0;
259         }
260 @@ -2416,7 +2423,8 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name,
261                 return error;
263  retry:
264 -       error = ext4_xattr_set_credits(inode, value_len, &credits);
265 +       error = ext4_xattr_set_credits(inode, value_len, flags & XATTR_CREATE,
266 +                                      &credits);
267         if (error)
268                 return error;
270 diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
271 index 26119a67c8c3..0d2dde1fa87a 100644
272 --- a/fs/ext4/xattr.h
273 +++ b/fs/ext4/xattr.h
274 @@ -153,7 +153,10 @@ extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t);
275  extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
276  extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
277  extern int ext4_xattr_set_credits(struct inode *inode, size_t value_len,
278 -                                 int *credits);
279 +                                 bool is_create, int *credits);
280 +extern int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode,
281 +                               struct buffer_head *block_bh, size_t value_len,
282 +                               bool is_create);
284  extern int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
285                                    struct ext4_xattr_inode_array **array,
286 diff --git a/include/linux/fscrypt_common.h b/include/linux/fscrypt_common.h
287 index 0a30c106c1e5..82beaf70e7e2 100644
288 --- a/include/linux/fscrypt_common.h
289 +++ b/include/linux/fscrypt_common.h
290 @@ -83,6 +83,9 @@ struct fscrypt_operations {
291         unsigned (*max_namelen)(struct inode *);
292  };
294 +/* Maximum value for the third parameter of fscrypt_operations.set_context(). */
295 +#define FSCRYPT_SET_CONTEXT_MAX_SIZE   28
297  static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
299         if (inode->i_sb->s_cop->dummy_context &&
300 -- 
301 2.13.2.725.g09c95d1e9-goog