diff options
author | Theodore Ts'o <tytso@mit.edu> | 2013-02-09 15:23:03 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-02-09 15:23:03 -0500 |
commit | 95eaefbdececae5e781d76d03fe7472a857c8c7a (patch) | |
tree | abe337e1490ded4166cf4d26f97cd1fe856a84ab /fs/ext4 | |
parent | 64044abf05d0842a7fed30e102fa411a744c7d9f (diff) |
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>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/acl.c | 4 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 69 | ||||
-rw-r--r-- | fs/ext4/ext4_jbd2.h | 14 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 9 | ||||
-rw-r--r-- | fs/ext4/xattr.h | 68 |
5 files changed, 86 insertions, 78 deletions
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 406cf8bb12d5..39a54a0e9fe4 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c | |||
@@ -325,7 +325,7 @@ ext4_acl_chmod(struct inode *inode) | |||
325 | return error; | 325 | return error; |
326 | retry: | 326 | retry: |
327 | handle = ext4_journal_start(inode, EXT4_HT_XATTR, | 327 | handle = ext4_journal_start(inode, EXT4_HT_XATTR, |
328 | EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); | 328 | ext4_jbd2_credits_xattr(inode)); |
329 | if (IS_ERR(handle)) { | 329 | if (IS_ERR(handle)) { |
330 | error = PTR_ERR(handle); | 330 | error = PTR_ERR(handle); |
331 | ext4_std_error(inode->i_sb, error); | 331 | ext4_std_error(inode->i_sb, error); |
@@ -423,7 +423,7 @@ ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value, | |||
423 | 423 | ||
424 | retry: | 424 | retry: |
425 | handle = ext4_journal_start(inode, EXT4_HT_XATTR, | 425 | handle = ext4_journal_start(inode, EXT4_HT_XATTR, |
426 | EXT4_DATA_TRANS_BLOCKS(inode->i_sb)); | 426 | ext4_jbd2_credits_xattr(inode)); |
427 | if (IS_ERR(handle)) { | 427 | if (IS_ERR(handle)) { |
428 | error = PTR_ERR(handle); | 428 | error = PTR_ERR(handle); |
429 | goto release_and_out; | 429 | goto release_and_out; |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index a5ae87c51401..61ecf059f70c 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -2456,6 +2456,75 @@ extern const struct file_operations ext4_file_operations; | |||
2456 | extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin); | 2456 | extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin); |
2457 | extern void ext4_unwritten_wait(struct inode *inode); | 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 | /* namei.c */ | 2528 | /* namei.c */ |
2460 | extern const struct inode_operations ext4_dir_inode_operations; | 2529 | extern const struct inode_operations ext4_dir_inode_operations; |
2461 | extern const struct inode_operations ext4_special_inode_operations; | 2530 | extern const struct inode_operations ext4_special_inode_operations; |
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index c1fc2dca14ae..4c216b1bf20c 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
@@ -104,6 +104,20 @@ | |||
104 | #define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb)) | 104 | #define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb)) |
105 | #define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb)) | 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 | * Ext4 handle operation types -- for logging purposes | 122 | * Ext4 handle operation types -- for logging purposes |
109 | */ | 123 | */ |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 2efc5600b03b..cc31da027596 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -1165,16 +1165,9 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name, | |||
1165 | { | 1165 | { |
1166 | handle_t *handle; | 1166 | handle_t *handle; |
1167 | int error, retries = 0; | 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 | retry: | 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 | handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits); | 1171 | handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits); |
1179 | if (IS_ERR(handle)) { | 1172 | if (IS_ERR(handle)) { |
1180 | error = PTR_ERR(handle); | 1173 | error = PTR_ERR(handle); |
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index 69eda787a96a..aa25deb5c6cd 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h | |||
@@ -125,74 +125,6 @@ extern int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, | |||
125 | struct ext4_xattr_info *i, | 125 | struct ext4_xattr_info *i, |
126 | struct ext4_xattr_ibody_find *is); | 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 | #ifdef CONFIG_EXT4_FS_SECURITY | 128 | #ifdef CONFIG_EXT4_FS_SECURITY |
197 | extern int ext4_init_security(handle_t *handle, struct inode *inode, | 129 | extern int ext4_init_security(handle_t *handle, struct inode *inode, |
198 | struct inode *dir, const struct qstr *qstr); | 130 | struct inode *dir, const struct qstr *qstr); |