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