Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ext4: fix __ext4_new_inode() journal credits calculation

ea_inode feature allows creating extended attributes that are up to
64k in size. Update __ext4_new_inode() to pick increased credit limits.

To avoid overallocating too many journal credits, update
__ext4_xattr_set_credits() to make a distinction between xattr create
vs update. This helps __ext4_new_inode() because all attributes are
known to be new, so we can save credits that are normally needed to
delete old values.

Also, have fscrypt specify its maximum context size so that we don't
end up allocating credits for 64k size.

Signed-off-by: Tahsin Erdogan <tahsin@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>

authored by

Tahsin Erdogan and committed by
Theodore Ts'o
af65207c ad47f953

+89 -34
+1
fs/crypto/policy.c
··· 260 260 memcpy(ctx.master_key_descriptor, ci->ci_master_key, 261 261 FS_KEY_DESCRIPTOR_SIZE); 262 262 get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE); 263 + BUILD_BUG_ON(sizeof(ctx) != FSCRYPT_SET_CONTEXT_MAX_SIZE); 263 264 res = parent->i_sb->s_cop->set_context(child, &ctx, 264 265 sizeof(ctx), fs_data); 265 266 if (res)
+7 -6
fs/ext4/acl.c
··· 183 183 */ 184 184 static int 185 185 __ext4_set_acl(handle_t *handle, struct inode *inode, int type, 186 - struct posix_acl *acl) 186 + struct posix_acl *acl, int xattr_flags) 187 187 { 188 188 int name_index; 189 189 void *value = NULL; ··· 218 218 } 219 219 220 220 error = ext4_xattr_set_handle(handle, inode, name_index, "", 221 - value, size, 0); 221 + value, size, xattr_flags); 222 222 223 223 kfree(value); 224 224 if (!error) ··· 238 238 if (error) 239 239 return error; 240 240 retry: 241 - error = ext4_xattr_set_credits(inode, acl_size, &credits); 241 + error = ext4_xattr_set_credits(inode, acl_size, false /* is_create */, 242 + &credits); 242 243 if (error) 243 244 return error; 244 245 ··· 247 246 if (IS_ERR(handle)) 248 247 return PTR_ERR(handle); 249 248 250 - error = __ext4_set_acl(handle, inode, type, acl); 249 + error = __ext4_set_acl(handle, inode, type, acl, 0 /* xattr_flags */); 251 250 ext4_journal_stop(handle); 252 251 if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) 253 252 goto retry; ··· 272 271 273 272 if (default_acl) { 274 273 error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT, 275 - default_acl); 274 + default_acl, XATTR_CREATE); 276 275 posix_acl_release(default_acl); 277 276 } 278 277 if (acl) { 279 278 if (!error) 280 279 error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, 281 - acl); 280 + acl, XATTR_CREATE); 282 281 posix_acl_release(acl); 283 282 } 284 283 return error;
+45 -7
fs/ext4/ialloc.c
··· 766 766 if (!dir || !dir->i_nlink) 767 767 return ERR_PTR(-EPERM); 768 768 769 - if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb)))) 769 + sb = dir->i_sb; 770 + sbi = EXT4_SB(sb); 771 + 772 + if (unlikely(ext4_forced_shutdown(sbi))) 770 773 return ERR_PTR(-EIO); 771 774 772 - if ((ext4_encrypted_inode(dir) || 773 - DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) && 775 + if ((ext4_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) && 774 776 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) && 775 777 !(i_flags & EXT4_EA_INODE_FL)) { 776 778 err = fscrypt_get_encryption_info(dir); ··· 780 778 return ERR_PTR(err); 781 779 if (!fscrypt_has_encryption_key(dir)) 782 780 return ERR_PTR(-ENOKEY); 783 - if (!handle) 784 - nblocks += EXT4_DATA_TRANS_BLOCKS(dir->i_sb); 785 781 encrypt = 1; 786 782 } 787 783 788 - sb = dir->i_sb; 784 + if (!handle && sbi->s_journal && !(i_flags & EXT4_EA_INODE_FL)) { 785 + #ifdef CONFIG_EXT4_FS_POSIX_ACL 786 + struct posix_acl *p = get_acl(dir, ACL_TYPE_DEFAULT); 787 + 788 + if (p) { 789 + int acl_size = p->a_count * sizeof(ext4_acl_entry); 790 + 791 + nblocks += (S_ISDIR(mode) ? 2 : 1) * 792 + __ext4_xattr_set_credits(sb, NULL /* inode */, 793 + NULL /* block_bh */, acl_size, 794 + true /* is_create */); 795 + posix_acl_release(p); 796 + } 797 + #endif 798 + 799 + #ifdef CONFIG_SECURITY 800 + { 801 + int num_security_xattrs = 1; 802 + 803 + #ifdef CONFIG_INTEGRITY 804 + num_security_xattrs++; 805 + #endif 806 + /* 807 + * We assume that security xattrs are never 808 + * more than 1k. In practice they are under 809 + * 128 bytes. 810 + */ 811 + nblocks += num_security_xattrs * 812 + __ext4_xattr_set_credits(sb, NULL /* inode */, 813 + NULL /* block_bh */, 1024, 814 + true /* is_create */); 815 + } 816 + #endif 817 + if (encrypt) 818 + nblocks += __ext4_xattr_set_credits(sb, 819 + NULL /* inode */, NULL /* block_bh */, 820 + FSCRYPT_SET_CONTEXT_MAX_SIZE, 821 + true /* is_create */); 822 + } 823 + 789 824 ngroups = ext4_get_groups_count(sb); 790 825 trace_ext4_request_inode(dir, mode); 791 826 inode = new_inode(sb); 792 827 if (!inode) 793 828 return ERR_PTR(-ENOMEM); 794 829 ei = EXT4_I(inode); 795 - sbi = EXT4_SB(sb); 796 830 797 831 /* 798 832 * Initialize owners and quota early so that we don't have to account
+2 -1
fs/ext4/super.c
··· 1194 1194 if (res) 1195 1195 return res; 1196 1196 retry: 1197 - res = ext4_xattr_set_credits(inode, len, &credits); 1197 + res = ext4_xattr_set_credits(inode, len, false /* is_create */, 1198 + &credits); 1198 1199 if (res) 1199 1200 return res; 1200 1201
+27 -19
fs/ext4/xattr.c
··· 830 830 dquot_free_inode(inode); 831 831 } 832 832 833 - static int __ext4_xattr_set_credits(struct inode *inode, 834 - struct buffer_head *block_bh, 835 - size_t value_len) 833 + int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode, 834 + struct buffer_head *block_bh, size_t value_len, 835 + bool is_create) 836 836 { 837 - struct super_block *sb = inode->i_sb; 838 837 int credits; 839 838 int blocks; 840 839 ··· 859 860 * In case of inline data, we may push out the data to a block, 860 861 * so we need to reserve credits for this eventuality 861 862 */ 862 - if (ext4_has_inline_data(inode)) 863 + if (inode && ext4_has_inline_data(inode)) 863 864 credits += ext4_writepage_trans_blocks(inode) + 1; 864 865 865 866 /* We are done if ea_inode feature is not enabled. */ ··· 881 882 /* Blocks themselves. */ 882 883 credits += blocks; 883 884 884 - /* Dereference ea_inode holding old xattr value. 885 - * Old ea_inode, inode map, block bitmap, group descriptor. 886 - */ 887 - credits += 4; 885 + if (!is_create) { 886 + /* Dereference ea_inode holding old xattr value. 887 + * Old ea_inode, inode map, block bitmap, group descriptor. 888 + */ 889 + credits += 4; 888 890 889 - /* Data blocks for old ea_inode. */ 890 - blocks = XATTR_SIZE_MAX >> sb->s_blocksize_bits; 891 + /* Data blocks for old ea_inode. */ 892 + blocks = XATTR_SIZE_MAX >> sb->s_blocksize_bits; 891 893 892 - /* Indirection block or one level of extent tree for old ea_inode. */ 893 - blocks += 1; 894 + /* Indirection block or one level of extent tree for old 895 + * ea_inode. 896 + */ 897 + blocks += 1; 894 898 895 - /* Block bitmap and group descriptor updates for each block. */ 896 - credits += blocks * 2; 899 + /* Block bitmap and group descriptor updates for each block. */ 900 + credits += blocks * 2; 901 + } 897 902 898 903 /* We may need to clone the existing xattr block in which case we need 899 904 * to increment ref counts for existing ea_inodes referenced by it. ··· 2266 2263 goto cleanup; 2267 2264 } 2268 2265 2269 - credits = __ext4_xattr_set_credits(inode, bh, value_len); 2266 + credits = __ext4_xattr_set_credits(inode->i_sb, inode, bh, 2267 + value_len, 2268 + flags & XATTR_CREATE); 2270 2269 brelse(bh); 2271 2270 2272 2271 if (!ext4_handle_has_enough_credits(handle, credits)) { ··· 2375 2370 return error; 2376 2371 } 2377 2372 2378 - int ext4_xattr_set_credits(struct inode *inode, size_t value_len, int *credits) 2373 + int ext4_xattr_set_credits(struct inode *inode, size_t value_len, 2374 + bool is_create, int *credits) 2379 2375 { 2380 2376 struct buffer_head *bh; 2381 2377 int err; ··· 2392 2386 if (IS_ERR(bh)) { 2393 2387 err = PTR_ERR(bh); 2394 2388 } else { 2395 - *credits = __ext4_xattr_set_credits(inode, bh, value_len); 2389 + *credits = __ext4_xattr_set_credits(inode->i_sb, inode, bh, 2390 + value_len, is_create); 2396 2391 brelse(bh); 2397 2392 err = 0; 2398 2393 } ··· 2424 2417 return error; 2425 2418 2426 2419 retry: 2427 - error = ext4_xattr_set_credits(inode, value_len, &credits); 2420 + error = ext4_xattr_set_credits(inode, value_len, flags & XATTR_CREATE, 2421 + &credits); 2428 2422 if (error) 2429 2423 return error; 2430 2424
+4 -1
fs/ext4/xattr.h
··· 153 153 extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int); 154 154 extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int); 155 155 extern int ext4_xattr_set_credits(struct inode *inode, size_t value_len, 156 - int *credits); 156 + bool is_create, int *credits); 157 + extern int __ext4_xattr_set_credits(struct super_block *sb, struct inode *inode, 158 + struct buffer_head *block_bh, size_t value_len, 159 + bool is_create); 157 160 158 161 extern int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, 159 162 struct ext4_xattr_inode_array **array,
+3
include/linux/fscrypt_common.h
··· 83 83 unsigned (*max_namelen)(struct inode *); 84 84 }; 85 85 86 + /* Maximum value for the third parameter of fscrypt_operations.set_context(). */ 87 + #define FSCRYPT_SET_CONTEXT_MAX_SIZE 28 88 + 86 89 static inline bool fscrypt_dummy_context_enabled(struct inode *inode) 87 90 { 88 91 if (inode->i_sb->s_cop->dummy_context &&