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

ext4: fix the number of credits needed for acl ops with inline data

Operations which modify extended attributes may need extra journal
credits if inline data is used, since there is a chance that some
extended attributes may need to get pushed to an external attribute
block.

Changes to reflect this was made in xattr.c, but they were missed in
fs/ext4/acl.c. To fix this, abstract the calculation of the number of
credits needed for xattr operations to an inline function defined in
ext4_jbd2.h, and use it in acl.c and xattr.c.

Also move the function declarations used in inline.c from xattr.h
(where they are non-obviously hidden, and caused problems since
ext4_jbd2.h needs to use the function ext4_has_inline_data), and move
them to ext4.h.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Tao Ma <boyu.mt@taobao.com>
Reviewed-by: Jan Kara <jack@suse.cz>

+86 -78
+2 -2
fs/ext4/acl.c
··· 325 325 return error; 326 326 retry: 327 327 handle = ext4_journal_start(inode, EXT4_HT_XATTR, 328 - EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); 328 + ext4_jbd2_credits_xattr(inode)); 329 329 if (IS_ERR(handle)) { 330 330 error = PTR_ERR(handle); 331 331 ext4_std_error(inode->i_sb, error); ··· 423 423 424 424 retry: 425 425 handle = ext4_journal_start(inode, EXT4_HT_XATTR, 426 - EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); 426 + ext4_jbd2_credits_xattr(inode)); 427 427 if (IS_ERR(handle)) { 428 428 error = PTR_ERR(handle); 429 429 goto release_and_out;
+69
fs/ext4/ext4.h
··· 2456 2456 extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin); 2457 2457 extern void ext4_unwritten_wait(struct inode *inode); 2458 2458 2459 + /* inline.c */ 2460 + extern int ext4_has_inline_data(struct inode *inode); 2461 + extern int ext4_get_inline_size(struct inode *inode); 2462 + extern int ext4_get_max_inline_size(struct inode *inode); 2463 + extern int ext4_find_inline_data_nolock(struct inode *inode); 2464 + extern void ext4_write_inline_data(struct inode *inode, 2465 + struct ext4_iloc *iloc, 2466 + void *buffer, loff_t pos, 2467 + unsigned int len); 2468 + extern int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, 2469 + unsigned int len); 2470 + extern int ext4_init_inline_data(handle_t *handle, struct inode *inode, 2471 + unsigned int len); 2472 + extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode); 2473 + 2474 + extern int ext4_readpage_inline(struct inode *inode, struct page *page); 2475 + extern int ext4_try_to_write_inline_data(struct address_space *mapping, 2476 + struct inode *inode, 2477 + loff_t pos, unsigned len, 2478 + unsigned flags, 2479 + struct page **pagep); 2480 + extern int ext4_write_inline_data_end(struct inode *inode, 2481 + loff_t pos, unsigned len, 2482 + unsigned copied, 2483 + struct page *page); 2484 + extern struct buffer_head * 2485 + ext4_journalled_write_inline_data(struct inode *inode, 2486 + unsigned len, 2487 + struct page *page); 2488 + extern int ext4_da_write_inline_data_begin(struct address_space *mapping, 2489 + struct inode *inode, 2490 + loff_t pos, unsigned len, 2491 + unsigned flags, 2492 + struct page **pagep, 2493 + void **fsdata); 2494 + extern int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, 2495 + unsigned len, unsigned copied, 2496 + struct page *page); 2497 + extern int ext4_try_add_inline_entry(handle_t *handle, struct dentry *dentry, 2498 + struct inode *inode); 2499 + extern int ext4_try_create_inline_dir(handle_t *handle, 2500 + struct inode *parent, 2501 + struct inode *inode); 2502 + extern int ext4_read_inline_dir(struct file *filp, 2503 + void *dirent, filldir_t filldir, 2504 + int *has_inline_data); 2505 + extern struct buffer_head *ext4_find_inline_entry(struct inode *dir, 2506 + const struct qstr *d_name, 2507 + struct ext4_dir_entry_2 **res_dir, 2508 + int *has_inline_data); 2509 + extern int ext4_delete_inline_entry(handle_t *handle, 2510 + struct inode *dir, 2511 + struct ext4_dir_entry_2 *de_del, 2512 + struct buffer_head *bh, 2513 + int *has_inline_data); 2514 + extern int empty_inline_dir(struct inode *dir, int *has_inline_data); 2515 + extern struct buffer_head *ext4_get_first_inline_block(struct inode *inode, 2516 + struct ext4_dir_entry_2 **parent_de, 2517 + int *retval); 2518 + extern int ext4_inline_data_fiemap(struct inode *inode, 2519 + struct fiemap_extent_info *fieinfo, 2520 + int *has_inline); 2521 + extern int ext4_try_to_evict_inline_data(handle_t *handle, 2522 + struct inode *inode, 2523 + int needed); 2524 + extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline); 2525 + 2526 + extern int ext4_convert_inline_data(struct inode *inode); 2527 + 2459 2528 /* namei.c */ 2460 2529 extern const struct inode_operations ext4_dir_inode_operations; 2461 2530 extern const struct inode_operations ext4_special_inode_operations;
+14
fs/ext4/ext4_jbd2.h
··· 104 104 #define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb)) 105 105 #define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb)) 106 106 107 + static inline int ext4_jbd2_credits_xattr(struct inode *inode) 108 + { 109 + int credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb); 110 + 111 + /* 112 + * In case of inline data, we may push out the data to a block, 113 + * so we need to reserve credits for this eventuality 114 + */ 115 + if (ext4_has_inline_data(inode)) 116 + credits += ext4_writepage_trans_blocks(inode) + 1; 117 + return credits; 118 + } 119 + 120 + 107 121 /* 108 122 * Ext4 handle operation types -- for logging purposes 109 123 */
+1 -8
fs/ext4/xattr.c
··· 1165 1165 { 1166 1166 handle_t *handle; 1167 1167 int error, retries = 0; 1168 - int credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb); 1168 + int credits = ext4_jbd2_credits_xattr(inode); 1169 1169 1170 1170 retry: 1171 - /* 1172 - * In case of inline data, we may push out the data to a block, 1173 - * So reserve the journal space first. 1174 - */ 1175 - if (ext4_has_inline_data(inode)) 1176 - credits += ext4_writepage_trans_blocks(inode) + 1; 1177 - 1178 1171 handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits); 1179 1172 if (IS_ERR(handle)) { 1180 1173 error = PTR_ERR(handle);
-68
fs/ext4/xattr.h
··· 125 125 struct ext4_xattr_info *i, 126 126 struct ext4_xattr_ibody_find *is); 127 127 128 - extern int ext4_has_inline_data(struct inode *inode); 129 - extern int ext4_get_inline_size(struct inode *inode); 130 - extern int ext4_get_max_inline_size(struct inode *inode); 131 - extern int ext4_find_inline_data_nolock(struct inode *inode); 132 - extern void ext4_write_inline_data(struct inode *inode, 133 - struct ext4_iloc *iloc, 134 - void *buffer, loff_t pos, 135 - unsigned int len); 136 - extern int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, 137 - unsigned int len); 138 - extern int ext4_init_inline_data(handle_t *handle, struct inode *inode, 139 - unsigned int len); 140 - extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode); 141 - 142 - extern int ext4_readpage_inline(struct inode *inode, struct page *page); 143 - extern int ext4_try_to_write_inline_data(struct address_space *mapping, 144 - struct inode *inode, 145 - loff_t pos, unsigned len, 146 - unsigned flags, 147 - struct page **pagep); 148 - extern int ext4_write_inline_data_end(struct inode *inode, 149 - loff_t pos, unsigned len, 150 - unsigned copied, 151 - struct page *page); 152 - extern struct buffer_head * 153 - ext4_journalled_write_inline_data(struct inode *inode, 154 - unsigned len, 155 - struct page *page); 156 - extern int ext4_da_write_inline_data_begin(struct address_space *mapping, 157 - struct inode *inode, 158 - loff_t pos, unsigned len, 159 - unsigned flags, 160 - struct page **pagep, 161 - void **fsdata); 162 - extern int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, 163 - unsigned len, unsigned copied, 164 - struct page *page); 165 - extern int ext4_try_add_inline_entry(handle_t *handle, struct dentry *dentry, 166 - struct inode *inode); 167 - extern int ext4_try_create_inline_dir(handle_t *handle, 168 - struct inode *parent, 169 - struct inode *inode); 170 - extern int ext4_read_inline_dir(struct file *filp, 171 - void *dirent, filldir_t filldir, 172 - int *has_inline_data); 173 - extern struct buffer_head *ext4_find_inline_entry(struct inode *dir, 174 - const struct qstr *d_name, 175 - struct ext4_dir_entry_2 **res_dir, 176 - int *has_inline_data); 177 - extern int ext4_delete_inline_entry(handle_t *handle, 178 - struct inode *dir, 179 - struct ext4_dir_entry_2 *de_del, 180 - struct buffer_head *bh, 181 - int *has_inline_data); 182 - extern int empty_inline_dir(struct inode *dir, int *has_inline_data); 183 - extern struct buffer_head *ext4_get_first_inline_block(struct inode *inode, 184 - struct ext4_dir_entry_2 **parent_de, 185 - int *retval); 186 - extern int ext4_inline_data_fiemap(struct inode *inode, 187 - struct fiemap_extent_info *fieinfo, 188 - int *has_inline); 189 - extern int ext4_try_to_evict_inline_data(handle_t *handle, 190 - struct inode *inode, 191 - int needed); 192 - extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline); 193 - 194 - extern int ext4_convert_inline_data(struct inode *inode); 195 - 196 128 #ifdef CONFIG_EXT4_FS_SECURITY 197 129 extern int ext4_init_security(handle_t *handle, struct inode *inode, 198 130 struct inode *dir, const struct qstr *qstr);