1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Interface between ext4 and JBD |
4 | */ |
5 | |
6 | #include "ext4_jbd2.h" |
7 | |
8 | #include <trace/events/ext4.h> |
9 | |
10 | int ext4_inode_journal_mode(struct inode *inode) |
11 | { |
12 | if (EXT4_JOURNAL(inode) == NULL) |
13 | return EXT4_INODE_WRITEBACK_DATA_MODE; /* writeback */ |
14 | /* We do not support data journalling with delayed allocation */ |
15 | if (!S_ISREG(inode->i_mode) || |
16 | ext4_test_inode_flag(inode, bit: EXT4_INODE_EA_INODE) || |
17 | test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || |
18 | (ext4_test_inode_flag(inode, bit: EXT4_INODE_JOURNAL_DATA) && |
19 | !test_opt(inode->i_sb, DELALLOC))) { |
20 | /* We do not support data journalling for encrypted data */ |
21 | if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode)) |
22 | return EXT4_INODE_ORDERED_DATA_MODE; /* ordered */ |
23 | return EXT4_INODE_JOURNAL_DATA_MODE; /* journal data */ |
24 | } |
25 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) |
26 | return EXT4_INODE_ORDERED_DATA_MODE; /* ordered */ |
27 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) |
28 | return EXT4_INODE_WRITEBACK_DATA_MODE; /* writeback */ |
29 | BUG(); |
30 | } |
31 | |
32 | /* Just increment the non-pointer handle value */ |
33 | static handle_t *ext4_get_nojournal(void) |
34 | { |
35 | handle_t *handle = current->journal_info; |
36 | unsigned long ref_cnt = (unsigned long)handle; |
37 | |
38 | BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT); |
39 | |
40 | ref_cnt++; |
41 | handle = (handle_t *)ref_cnt; |
42 | |
43 | current->journal_info = handle; |
44 | return handle; |
45 | } |
46 | |
47 | |
48 | /* Decrement the non-pointer handle value */ |
49 | static void ext4_put_nojournal(handle_t *handle) |
50 | { |
51 | unsigned long ref_cnt = (unsigned long)handle; |
52 | |
53 | BUG_ON(ref_cnt == 0); |
54 | |
55 | ref_cnt--; |
56 | handle = (handle_t *)ref_cnt; |
57 | |
58 | current->journal_info = handle; |
59 | } |
60 | |
61 | /* |
62 | * Wrappers for jbd2_journal_start/end. |
63 | */ |
64 | static int ext4_journal_check_start(struct super_block *sb) |
65 | { |
66 | journal_t *journal; |
67 | |
68 | might_sleep(); |
69 | |
70 | if (unlikely(ext4_forced_shutdown(sb))) |
71 | return -EIO; |
72 | |
73 | if (WARN_ON_ONCE(sb_rdonly(sb))) |
74 | return -EROFS; |
75 | |
76 | WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE); |
77 | journal = EXT4_SB(sb)->s_journal; |
78 | /* |
79 | * Special case here: if the journal has aborted behind our |
80 | * backs (eg. EIO in the commit thread), then we still need to |
81 | * take the FS itself readonly cleanly. |
82 | */ |
83 | if (journal && is_journal_aborted(journal)) { |
84 | ext4_abort(sb, -journal->j_errno, "Detected aborted journal" ); |
85 | return -EROFS; |
86 | } |
87 | return 0; |
88 | } |
89 | |
90 | handle_t *__ext4_journal_start_sb(struct inode *inode, |
91 | struct super_block *sb, unsigned int line, |
92 | int type, int blocks, int rsv_blocks, |
93 | int revoke_creds) |
94 | { |
95 | journal_t *journal; |
96 | int err; |
97 | if (inode) |
98 | trace_ext4_journal_start_inode(inode, blocks, rsv_blocks, |
99 | revoke_creds, type, |
100 | _RET_IP_); |
101 | else |
102 | trace_ext4_journal_start_sb(sb, blocks, rsv_blocks, |
103 | revoke_creds, type, |
104 | _RET_IP_); |
105 | err = ext4_journal_check_start(sb); |
106 | if (err < 0) |
107 | return ERR_PTR(error: err); |
108 | |
109 | journal = EXT4_SB(sb)->s_journal; |
110 | if (!journal || (EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY)) |
111 | return ext4_get_nojournal(); |
112 | return jbd2__journal_start(journal, blocks, rsv_blocks, revoke_records: revoke_creds, |
113 | GFP_NOFS, type, line_no: line); |
114 | } |
115 | |
116 | int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle) |
117 | { |
118 | struct super_block *sb; |
119 | int err; |
120 | int rc; |
121 | |
122 | if (!ext4_handle_valid(handle)) { |
123 | ext4_put_nojournal(handle); |
124 | return 0; |
125 | } |
126 | |
127 | err = handle->h_err; |
128 | if (!handle->h_transaction) { |
129 | rc = jbd2_journal_stop(handle); |
130 | return err ? err : rc; |
131 | } |
132 | |
133 | sb = handle->h_transaction->t_journal->j_private; |
134 | rc = jbd2_journal_stop(handle); |
135 | |
136 | if (!err) |
137 | err = rc; |
138 | if (err) |
139 | __ext4_std_error(sb, where, line, err); |
140 | return err; |
141 | } |
142 | |
143 | handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line, |
144 | int type) |
145 | { |
146 | struct super_block *sb; |
147 | int err; |
148 | |
149 | if (!ext4_handle_valid(handle)) |
150 | return ext4_get_nojournal(); |
151 | |
152 | sb = handle->h_journal->j_private; |
153 | trace_ext4_journal_start_reserved(sb, |
154 | blocks: jbd2_handle_buffer_credits(handle), _RET_IP_); |
155 | err = ext4_journal_check_start(sb); |
156 | if (err < 0) { |
157 | jbd2_journal_free_reserved(handle); |
158 | return ERR_PTR(error: err); |
159 | } |
160 | |
161 | err = jbd2_journal_start_reserved(handle, type, line_no: line); |
162 | if (err < 0) |
163 | return ERR_PTR(error: err); |
164 | return handle; |
165 | } |
166 | |
167 | int __ext4_journal_ensure_credits(handle_t *handle, int check_cred, |
168 | int extend_cred, int revoke_cred) |
169 | { |
170 | if (!ext4_handle_valid(handle)) |
171 | return 0; |
172 | if (is_handle_aborted(handle)) |
173 | return -EROFS; |
174 | if (jbd2_handle_buffer_credits(handle) >= check_cred && |
175 | handle->h_revoke_credits >= revoke_cred) |
176 | return 0; |
177 | extend_cred = max(0, extend_cred - jbd2_handle_buffer_credits(handle)); |
178 | revoke_cred = max(0, revoke_cred - handle->h_revoke_credits); |
179 | return ext4_journal_extend(handle, nblocks: extend_cred, revoke: revoke_cred); |
180 | } |
181 | |
182 | static void ext4_journal_abort_handle(const char *caller, unsigned int line, |
183 | const char *err_fn, |
184 | struct buffer_head *bh, |
185 | handle_t *handle, int err) |
186 | { |
187 | char nbuf[16]; |
188 | const char *errstr = ext4_decode_error(NULL, errno: err, nbuf); |
189 | |
190 | BUG_ON(!ext4_handle_valid(handle)); |
191 | |
192 | if (bh) |
193 | BUFFER_TRACE(bh, "abort" ); |
194 | |
195 | if (!handle->h_err) |
196 | handle->h_err = err; |
197 | |
198 | if (is_handle_aborted(handle)) |
199 | return; |
200 | |
201 | printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n" , |
202 | caller, line, errstr, err_fn); |
203 | |
204 | jbd2_journal_abort_handle(handle); |
205 | } |
206 | |
207 | static void ext4_check_bdev_write_error(struct super_block *sb) |
208 | { |
209 | struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; |
210 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
211 | int err; |
212 | |
213 | /* |
214 | * If the block device has write error flag, it may have failed to |
215 | * async write out metadata buffers in the background. In this case, |
216 | * we could read old data from disk and write it out again, which |
217 | * may lead to on-disk filesystem inconsistency. |
218 | */ |
219 | if (errseq_check(eseq: &mapping->wb_err, READ_ONCE(sbi->s_bdev_wb_err))) { |
220 | spin_lock(lock: &sbi->s_bdev_wb_lock); |
221 | err = errseq_check_and_advance(eseq: &mapping->wb_err, since: &sbi->s_bdev_wb_err); |
222 | spin_unlock(lock: &sbi->s_bdev_wb_lock); |
223 | if (err) |
224 | ext4_error_err(sb, -err, |
225 | "Error while async write back metadata" ); |
226 | } |
227 | } |
228 | |
229 | int __ext4_journal_get_write_access(const char *where, unsigned int line, |
230 | handle_t *handle, struct super_block *sb, |
231 | struct buffer_head *bh, |
232 | enum ext4_journal_trigger_type trigger_type) |
233 | { |
234 | int err; |
235 | |
236 | might_sleep(); |
237 | |
238 | ext4_check_bdev_write_error(sb); |
239 | |
240 | if (ext4_handle_valid(handle)) { |
241 | err = jbd2_journal_get_write_access(handle, bh); |
242 | if (err) { |
243 | ext4_journal_abort_handle(caller: where, line, err_fn: __func__, bh, |
244 | handle, err); |
245 | return err; |
246 | } |
247 | } |
248 | if (trigger_type == EXT4_JTR_NONE || !ext4_has_metadata_csum(sb)) |
249 | return 0; |
250 | BUG_ON(trigger_type >= EXT4_JOURNAL_TRIGGER_COUNT); |
251 | jbd2_journal_set_triggers(bh, |
252 | type: &EXT4_SB(sb)->s_journal_triggers[trigger_type].tr_triggers); |
253 | return 0; |
254 | } |
255 | |
256 | /* |
257 | * The ext4 forget function must perform a revoke if we are freeing data |
258 | * which has been journaled. Metadata (eg. indirect blocks) must be |
259 | * revoked in all cases. |
260 | * |
261 | * "bh" may be NULL: a metadata block may have been freed from memory |
262 | * but there may still be a record of it in the journal, and that record |
263 | * still needs to be revoked. |
264 | */ |
265 | int __ext4_forget(const char *where, unsigned int line, handle_t *handle, |
266 | int is_metadata, struct inode *inode, |
267 | struct buffer_head *bh, ext4_fsblk_t blocknr) |
268 | { |
269 | int err; |
270 | |
271 | might_sleep(); |
272 | |
273 | trace_ext4_forget(inode, is_metadata, block: blocknr); |
274 | BUFFER_TRACE(bh, "enter" ); |
275 | |
276 | ext4_debug("forgetting bh %p: is_metadata=%d, mode %o, data mode %x\n" , |
277 | bh, is_metadata, inode->i_mode, |
278 | test_opt(inode->i_sb, DATA_FLAGS)); |
279 | |
280 | /* In the no journal case, we can just do a bforget and return */ |
281 | if (!ext4_handle_valid(handle)) { |
282 | bforget(bh); |
283 | return 0; |
284 | } |
285 | |
286 | /* Never use the revoke function if we are doing full data |
287 | * journaling: there is no need to, and a V1 superblock won't |
288 | * support it. Otherwise, only skip the revoke on un-journaled |
289 | * data blocks. */ |
290 | |
291 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || |
292 | (!is_metadata && !ext4_should_journal_data(inode))) { |
293 | if (bh) { |
294 | BUFFER_TRACE(bh, "call jbd2_journal_forget" ); |
295 | err = jbd2_journal_forget(handle, bh); |
296 | if (err) |
297 | ext4_journal_abort_handle(caller: where, line, err_fn: __func__, |
298 | bh, handle, err); |
299 | return err; |
300 | } |
301 | return 0; |
302 | } |
303 | |
304 | /* |
305 | * data!=journal && (is_metadata || should_journal_data(inode)) |
306 | */ |
307 | BUFFER_TRACE(bh, "call jbd2_journal_revoke" ); |
308 | err = jbd2_journal_revoke(handle, blocknr, bh); |
309 | if (err) { |
310 | ext4_journal_abort_handle(caller: where, line, err_fn: __func__, |
311 | bh, handle, err); |
312 | __ext4_error(inode->i_sb, where, line, true, -err, 0, |
313 | "error %d when attempting revoke" , err); |
314 | } |
315 | BUFFER_TRACE(bh, "exit" ); |
316 | return err; |
317 | } |
318 | |
319 | int __ext4_journal_get_create_access(const char *where, unsigned int line, |
320 | handle_t *handle, struct super_block *sb, |
321 | struct buffer_head *bh, |
322 | enum ext4_journal_trigger_type trigger_type) |
323 | { |
324 | int err; |
325 | |
326 | if (!ext4_handle_valid(handle)) |
327 | return 0; |
328 | |
329 | err = jbd2_journal_get_create_access(handle, bh); |
330 | if (err) { |
331 | ext4_journal_abort_handle(caller: where, line, err_fn: __func__, bh, handle, |
332 | err); |
333 | return err; |
334 | } |
335 | if (trigger_type == EXT4_JTR_NONE || !ext4_has_metadata_csum(sb)) |
336 | return 0; |
337 | BUG_ON(trigger_type >= EXT4_JOURNAL_TRIGGER_COUNT); |
338 | jbd2_journal_set_triggers(bh, |
339 | type: &EXT4_SB(sb)->s_journal_triggers[trigger_type].tr_triggers); |
340 | return 0; |
341 | } |
342 | |
343 | int __ext4_handle_dirty_metadata(const char *where, unsigned int line, |
344 | handle_t *handle, struct inode *inode, |
345 | struct buffer_head *bh) |
346 | { |
347 | int err = 0; |
348 | |
349 | might_sleep(); |
350 | |
351 | set_buffer_meta(bh); |
352 | set_buffer_prio(bh); |
353 | set_buffer_uptodate(bh); |
354 | if (ext4_handle_valid(handle)) { |
355 | err = jbd2_journal_dirty_metadata(handle, bh); |
356 | /* Errors can only happen due to aborted journal or a nasty bug */ |
357 | if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) { |
358 | ext4_journal_abort_handle(caller: where, line, err_fn: __func__, bh, |
359 | handle, err); |
360 | if (inode == NULL) { |
361 | pr_err("EXT4: jbd2_journal_dirty_metadata " |
362 | "failed: handle type %u started at " |
363 | "line %u, credits %u/%u, errcode %d" , |
364 | handle->h_type, |
365 | handle->h_line_no, |
366 | handle->h_requested_credits, |
367 | jbd2_handle_buffer_credits(handle), err); |
368 | return err; |
369 | } |
370 | ext4_error_inode(inode, where, line, |
371 | bh->b_blocknr, |
372 | "journal_dirty_metadata failed: " |
373 | "handle type %u started at line %u, " |
374 | "credits %u/%u, errcode %d" , |
375 | handle->h_type, |
376 | handle->h_line_no, |
377 | handle->h_requested_credits, |
378 | jbd2_handle_buffer_credits(handle), |
379 | err); |
380 | } |
381 | } else { |
382 | if (inode) |
383 | mark_buffer_dirty_inode(bh, inode); |
384 | else |
385 | mark_buffer_dirty(bh); |
386 | if (inode && inode_needs_sync(inode)) { |
387 | sync_dirty_buffer(bh); |
388 | if (buffer_req(bh) && !buffer_uptodate(bh)) { |
389 | ext4_error_inode_err(inode, where, line, |
390 | bh->b_blocknr, EIO, |
391 | "IO error syncing itable block" ); |
392 | err = -EIO; |
393 | } |
394 | } |
395 | } |
396 | return err; |
397 | } |
398 | |