1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 28984d137SAndrew Morton /* 38984d137SAndrew Morton * Interface between ext4 and JBD 48984d137SAndrew Morton */ 58984d137SAndrew Morton 63dcf5451SChristoph Hellwig #include "ext4_jbd2.h" 78984d137SAndrew Morton 8d6797d14STheodore Ts'o #include <trace/events/ext4.h> 9d6797d14STheodore Ts'o 1046797ad7SEric Biggers int ext4_inode_journal_mode(struct inode *inode) 1146797ad7SEric Biggers { 1246797ad7SEric Biggers if (EXT4_JOURNAL(inode) == NULL) 1346797ad7SEric Biggers return EXT4_INODE_WRITEBACK_DATA_MODE; /* writeback */ 1446797ad7SEric Biggers /* We do not support data journalling with delayed allocation */ 1546797ad7SEric Biggers if (!S_ISREG(inode->i_mode) || 1646797ad7SEric Biggers ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE) || 1746797ad7SEric Biggers test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || 1846797ad7SEric Biggers (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) && 1946797ad7SEric Biggers !test_opt(inode->i_sb, DELALLOC))) { 2046797ad7SEric Biggers /* We do not support data journalling for encrypted data */ 2146797ad7SEric Biggers if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode)) 2246797ad7SEric Biggers return EXT4_INODE_ORDERED_DATA_MODE; /* ordered */ 2346797ad7SEric Biggers return EXT4_INODE_JOURNAL_DATA_MODE; /* journal data */ 2446797ad7SEric Biggers } 2546797ad7SEric Biggers if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) 2646797ad7SEric Biggers return EXT4_INODE_ORDERED_DATA_MODE; /* ordered */ 2746797ad7SEric Biggers if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) 2846797ad7SEric Biggers return EXT4_INODE_WRITEBACK_DATA_MODE; /* writeback */ 2946797ad7SEric Biggers BUG(); 3046797ad7SEric Biggers } 3146797ad7SEric Biggers 32722887ddSTheodore Ts'o /* Just increment the non-pointer handle value */ 33722887ddSTheodore Ts'o static handle_t *ext4_get_nojournal(void) 34722887ddSTheodore Ts'o { 35722887ddSTheodore Ts'o handle_t *handle = current->journal_info; 36722887ddSTheodore Ts'o unsigned long ref_cnt = (unsigned long)handle; 37722887ddSTheodore Ts'o 38722887ddSTheodore Ts'o BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT); 39722887ddSTheodore Ts'o 40722887ddSTheodore Ts'o ref_cnt++; 41722887ddSTheodore Ts'o handle = (handle_t *)ref_cnt; 42722887ddSTheodore Ts'o 43722887ddSTheodore Ts'o current->journal_info = handle; 44722887ddSTheodore Ts'o return handle; 45722887ddSTheodore Ts'o } 46722887ddSTheodore Ts'o 47722887ddSTheodore Ts'o 48722887ddSTheodore Ts'o /* Decrement the non-pointer handle value */ 49722887ddSTheodore Ts'o static void ext4_put_nojournal(handle_t *handle) 50722887ddSTheodore Ts'o { 51722887ddSTheodore Ts'o unsigned long ref_cnt = (unsigned long)handle; 52722887ddSTheodore Ts'o 53722887ddSTheodore Ts'o BUG_ON(ref_cnt == 0); 54722887ddSTheodore Ts'o 55722887ddSTheodore Ts'o ref_cnt--; 56722887ddSTheodore Ts'o handle = (handle_t *)ref_cnt; 57722887ddSTheodore Ts'o 58722887ddSTheodore Ts'o current->journal_info = handle; 59722887ddSTheodore Ts'o } 60722887ddSTheodore Ts'o 61722887ddSTheodore Ts'o /* 62722887ddSTheodore Ts'o * Wrappers for jbd2_journal_start/end. 63722887ddSTheodore Ts'o */ 645fe2fe89SJan Kara static int ext4_journal_check_start(struct super_block *sb) 65722887ddSTheodore Ts'o { 66722887ddSTheodore Ts'o journal_t *journal; 67722887ddSTheodore Ts'o 68b10a44c3STheodore Ts'o might_sleep(); 690db1ff22STheodore Ts'o 700db1ff22STheodore Ts'o if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) 710db1ff22STheodore Ts'o return -EIO; 720db1ff22STheodore Ts'o 73bc98a42cSDavid Howells if (sb_rdonly(sb)) 745fe2fe89SJan Kara return -EROFS; 75722887ddSTheodore Ts'o WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE); 76722887ddSTheodore Ts'o journal = EXT4_SB(sb)->s_journal; 77722887ddSTheodore Ts'o /* 78722887ddSTheodore Ts'o * Special case here: if the journal has aborted behind our 79722887ddSTheodore Ts'o * backs (eg. EIO in the commit thread), then we still need to 80722887ddSTheodore Ts'o * take the FS itself readonly cleanly. 81722887ddSTheodore Ts'o */ 825fe2fe89SJan Kara if (journal && is_journal_aborted(journal)) { 8354d3adbcSTheodore Ts'o ext4_abort(sb, -journal->j_errno, "Detected aborted journal"); 845fe2fe89SJan Kara return -EROFS; 85722887ddSTheodore Ts'o } 865fe2fe89SJan Kara return 0; 875fe2fe89SJan Kara } 885fe2fe89SJan Kara 895fe2fe89SJan Kara handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line, 9083448bdfSJan Kara int type, int blocks, int rsv_blocks, 9183448bdfSJan Kara int revoke_creds) 925fe2fe89SJan Kara { 935fe2fe89SJan Kara journal_t *journal; 945fe2fe89SJan Kara int err; 955fe2fe89SJan Kara 9683448bdfSJan Kara trace_ext4_journal_start(sb, blocks, rsv_blocks, revoke_creds, 9783448bdfSJan Kara _RET_IP_); 985fe2fe89SJan Kara err = ext4_journal_check_start(sb); 995fe2fe89SJan Kara if (err < 0) 1005fe2fe89SJan Kara return ERR_PTR(err); 1015fe2fe89SJan Kara 1025fe2fe89SJan Kara journal = EXT4_SB(sb)->s_journal; 1038016e29fSHarshad Shirwadkar if (!journal || (EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY)) 1045fe2fe89SJan Kara return ext4_get_nojournal(); 10583448bdfSJan Kara return jbd2__journal_start(journal, blocks, rsv_blocks, revoke_creds, 10683448bdfSJan Kara GFP_NOFS, type, line); 107722887ddSTheodore Ts'o } 108722887ddSTheodore Ts'o 109722887ddSTheodore Ts'o int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle) 110722887ddSTheodore Ts'o { 111722887ddSTheodore Ts'o struct super_block *sb; 112722887ddSTheodore Ts'o int err; 113722887ddSTheodore Ts'o int rc; 114722887ddSTheodore Ts'o 115722887ddSTheodore Ts'o if (!ext4_handle_valid(handle)) { 116722887ddSTheodore Ts'o ext4_put_nojournal(handle); 117722887ddSTheodore Ts'o return 0; 118722887ddSTheodore Ts'o } 1199d506594SLukas Czerner 1206934da92SLukas Czerner err = handle->h_err; 1219d506594SLukas Czerner if (!handle->h_transaction) { 1226934da92SLukas Czerner rc = jbd2_journal_stop(handle); 1236934da92SLukas Czerner return err ? err : rc; 1249d506594SLukas Czerner } 1259d506594SLukas Czerner 126722887ddSTheodore Ts'o sb = handle->h_transaction->t_journal->j_private; 127722887ddSTheodore Ts'o rc = jbd2_journal_stop(handle); 128722887ddSTheodore Ts'o 129722887ddSTheodore Ts'o if (!err) 130722887ddSTheodore Ts'o err = rc; 131722887ddSTheodore Ts'o if (err) 132722887ddSTheodore Ts'o __ext4_std_error(sb, where, line, err); 133722887ddSTheodore Ts'o return err; 134722887ddSTheodore Ts'o } 135722887ddSTheodore Ts'o 1365fe2fe89SJan Kara handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line, 1375fe2fe89SJan Kara int type) 1385fe2fe89SJan Kara { 1395fe2fe89SJan Kara struct super_block *sb; 1405fe2fe89SJan Kara int err; 1415fe2fe89SJan Kara 1425fe2fe89SJan Kara if (!ext4_handle_valid(handle)) 1435fe2fe89SJan Kara return ext4_get_nojournal(); 1445fe2fe89SJan Kara 1455fe2fe89SJan Kara sb = handle->h_journal->j_private; 146a9a8344eSJan Kara trace_ext4_journal_start_reserved(sb, 147a9a8344eSJan Kara jbd2_handle_buffer_credits(handle), _RET_IP_); 1485fe2fe89SJan Kara err = ext4_journal_check_start(sb); 1495fe2fe89SJan Kara if (err < 0) { 1505fe2fe89SJan Kara jbd2_journal_free_reserved(handle); 1515fe2fe89SJan Kara return ERR_PTR(err); 1525fe2fe89SJan Kara } 1535fe2fe89SJan Kara 1545fe2fe89SJan Kara err = jbd2_journal_start_reserved(handle, type, line); 1555fe2fe89SJan Kara if (err < 0) 1565fe2fe89SJan Kara return ERR_PTR(err); 1575fe2fe89SJan Kara return handle; 1585fe2fe89SJan Kara } 1595fe2fe89SJan Kara 160a4130367SJan Kara int __ext4_journal_ensure_credits(handle_t *handle, int check_cred, 16183448bdfSJan Kara int extend_cred, int revoke_cred) 162a4130367SJan Kara { 163a4130367SJan Kara if (!ext4_handle_valid(handle)) 164a4130367SJan Kara return 0; 16583448bdfSJan Kara if (jbd2_handle_buffer_credits(handle) >= check_cred && 16683448bdfSJan Kara handle->h_revoke_credits >= revoke_cred) 167a4130367SJan Kara return 0; 16883448bdfSJan Kara extend_cred = max(0, extend_cred - jbd2_handle_buffer_credits(handle)); 16983448bdfSJan Kara revoke_cred = max(0, revoke_cred - handle->h_revoke_credits); 17083448bdfSJan Kara return ext4_journal_extend(handle, extend_cred, revoke_cred); 171a4130367SJan Kara } 172a4130367SJan Kara 173c197855eSStephen Hemminger static void ext4_journal_abort_handle(const char *caller, unsigned int line, 174c197855eSStephen Hemminger const char *err_fn, 175c197855eSStephen Hemminger struct buffer_head *bh, 176722887ddSTheodore Ts'o handle_t *handle, int err) 177722887ddSTheodore Ts'o { 178722887ddSTheodore Ts'o char nbuf[16]; 179722887ddSTheodore Ts'o const char *errstr = ext4_decode_error(NULL, err, nbuf); 180722887ddSTheodore Ts'o 181722887ddSTheodore Ts'o BUG_ON(!ext4_handle_valid(handle)); 182722887ddSTheodore Ts'o 183722887ddSTheodore Ts'o if (bh) 184722887ddSTheodore Ts'o BUFFER_TRACE(bh, "abort"); 185722887ddSTheodore Ts'o 186722887ddSTheodore Ts'o if (!handle->h_err) 187722887ddSTheodore Ts'o handle->h_err = err; 188722887ddSTheodore Ts'o 189722887ddSTheodore Ts'o if (is_handle_aborted(handle)) 190722887ddSTheodore Ts'o return; 191722887ddSTheodore Ts'o 192722887ddSTheodore Ts'o printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n", 193722887ddSTheodore Ts'o caller, line, errstr, err_fn); 194722887ddSTheodore Ts'o 195722887ddSTheodore Ts'o jbd2_journal_abort_handle(handle); 196722887ddSTheodore Ts'o } 197722887ddSTheodore Ts'o 198bc71726cSzhangyi (F) static void ext4_check_bdev_write_error(struct super_block *sb) 199bc71726cSzhangyi (F) { 200bc71726cSzhangyi (F) struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; 201bc71726cSzhangyi (F) struct ext4_sb_info *sbi = EXT4_SB(sb); 202bc71726cSzhangyi (F) int err; 203bc71726cSzhangyi (F) 204bc71726cSzhangyi (F) /* 205bc71726cSzhangyi (F) * If the block device has write error flag, it may have failed to 206bc71726cSzhangyi (F) * async write out metadata buffers in the background. In this case, 207bc71726cSzhangyi (F) * we could read old data from disk and write it out again, which 208bc71726cSzhangyi (F) * may lead to on-disk filesystem inconsistency. 209bc71726cSzhangyi (F) */ 210bc71726cSzhangyi (F) if (errseq_check(&mapping->wb_err, READ_ONCE(sbi->s_bdev_wb_err))) { 211bc71726cSzhangyi (F) spin_lock(&sbi->s_bdev_wb_lock); 212bc71726cSzhangyi (F) err = errseq_check_and_advance(&mapping->wb_err, &sbi->s_bdev_wb_err); 213bc71726cSzhangyi (F) spin_unlock(&sbi->s_bdev_wb_lock); 214bc71726cSzhangyi (F) if (err) 215bc71726cSzhangyi (F) ext4_error_err(sb, -err, 216bc71726cSzhangyi (F) "Error while async write back metadata"); 217bc71726cSzhangyi (F) } 218bc71726cSzhangyi (F) } 219bc71726cSzhangyi (F) 22090c7201bSTheodore Ts'o int __ext4_journal_get_write_access(const char *where, unsigned int line, 22190c7201bSTheodore Ts'o handle_t *handle, struct buffer_head *bh) 2228984d137SAndrew Morton { 2230390131bSFrank Mayhar int err = 0; 2240390131bSFrank Mayhar 225b10a44c3STheodore Ts'o might_sleep(); 226b10a44c3STheodore Ts'o 227bc71726cSzhangyi (F) if (bh->b_bdev->bd_super) 228bc71726cSzhangyi (F) ext4_check_bdev_write_error(bh->b_bdev->bd_super); 229bc71726cSzhangyi (F) 2300390131bSFrank Mayhar if (ext4_handle_valid(handle)) { 2310390131bSFrank Mayhar err = jbd2_journal_get_write_access(handle, bh); 2328984d137SAndrew Morton if (err) 23390c7201bSTheodore Ts'o ext4_journal_abort_handle(where, line, __func__, bh, 2340390131bSFrank Mayhar handle, err); 2350390131bSFrank Mayhar } 2368984d137SAndrew Morton return err; 2378984d137SAndrew Morton } 2388984d137SAndrew Morton 239d6797d14STheodore Ts'o /* 240d6797d14STheodore Ts'o * The ext4 forget function must perform a revoke if we are freeing data 241d6797d14STheodore Ts'o * which has been journaled. Metadata (eg. indirect blocks) must be 242d6797d14STheodore Ts'o * revoked in all cases. 243d6797d14STheodore Ts'o * 244d6797d14STheodore Ts'o * "bh" may be NULL: a metadata block may have been freed from memory 245d6797d14STheodore Ts'o * but there may still be a record of it in the journal, and that record 246d6797d14STheodore Ts'o * still needs to be revoked. 247d6797d14STheodore Ts'o * 248d6797d14STheodore Ts'o * If the handle isn't valid we're not journaling, but we still need to 249d6797d14STheodore Ts'o * call into ext4_journal_revoke() to put the buffer head. 250d6797d14STheodore Ts'o */ 25190c7201bSTheodore Ts'o int __ext4_forget(const char *where, unsigned int line, handle_t *handle, 25290c7201bSTheodore Ts'o int is_metadata, struct inode *inode, 25390c7201bSTheodore Ts'o struct buffer_head *bh, ext4_fsblk_t blocknr) 254d6797d14STheodore Ts'o { 255d6797d14STheodore Ts'o int err; 256d6797d14STheodore Ts'o 257d6797d14STheodore Ts'o might_sleep(); 258d6797d14STheodore Ts'o 259d6797d14STheodore Ts'o trace_ext4_forget(inode, is_metadata, blocknr); 260d6797d14STheodore Ts'o BUFFER_TRACE(bh, "enter"); 261d6797d14STheodore Ts'o 262d6797d14STheodore Ts'o jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " 263d6797d14STheodore Ts'o "data mode %x\n", 264d6797d14STheodore Ts'o bh, is_metadata, inode->i_mode, 265d6797d14STheodore Ts'o test_opt(inode->i_sb, DATA_FLAGS)); 266d6797d14STheodore Ts'o 267e4684b3fSTheodore Ts'o /* In the no journal case, we can just do a bforget and return */ 268e4684b3fSTheodore Ts'o if (!ext4_handle_valid(handle)) { 269e4684b3fSTheodore Ts'o bforget(bh); 270e4684b3fSTheodore Ts'o return 0; 271e4684b3fSTheodore Ts'o } 272e4684b3fSTheodore Ts'o 273d6797d14STheodore Ts'o /* Never use the revoke function if we are doing full data 274d6797d14STheodore Ts'o * journaling: there is no need to, and a V1 superblock won't 275d6797d14STheodore Ts'o * support it. Otherwise, only skip the revoke on un-journaled 276d6797d14STheodore Ts'o * data blocks. */ 277d6797d14STheodore Ts'o 278d6797d14STheodore Ts'o if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || 279d6797d14STheodore Ts'o (!is_metadata && !ext4_should_journal_data(inode))) { 280d6797d14STheodore Ts'o if (bh) { 281d6797d14STheodore Ts'o BUFFER_TRACE(bh, "call jbd2_journal_forget"); 282b7e57e7cSTheodore Ts'o err = jbd2_journal_forget(handle, bh); 283b7e57e7cSTheodore Ts'o if (err) 28490c7201bSTheodore Ts'o ext4_journal_abort_handle(where, line, __func__, 28590c7201bSTheodore Ts'o bh, handle, err); 286b7e57e7cSTheodore Ts'o return err; 287d6797d14STheodore Ts'o } 288d6797d14STheodore Ts'o return 0; 289d6797d14STheodore Ts'o } 290d6797d14STheodore Ts'o 291d6797d14STheodore Ts'o /* 292d6797d14STheodore Ts'o * data!=journal && (is_metadata || should_journal_data(inode)) 293d6797d14STheodore Ts'o */ 294e4684b3fSTheodore Ts'o BUFFER_TRACE(bh, "call jbd2_journal_revoke"); 295e4684b3fSTheodore Ts'o err = jbd2_journal_revoke(handle, blocknr, bh); 296e4684b3fSTheodore Ts'o if (err) { 29790c7201bSTheodore Ts'o ext4_journal_abort_handle(where, line, __func__, 29890c7201bSTheodore Ts'o bh, handle, err); 29954d3adbcSTheodore Ts'o __ext4_abort(inode->i_sb, where, line, -err, 300d6797d14STheodore Ts'o "error %d when attempting revoke", err); 301e4684b3fSTheodore Ts'o } 302d6797d14STheodore Ts'o BUFFER_TRACE(bh, "exit"); 303d6797d14STheodore Ts'o return err; 304d6797d14STheodore Ts'o } 305d6797d14STheodore Ts'o 30690c7201bSTheodore Ts'o int __ext4_journal_get_create_access(const char *where, unsigned int line, 3078984d137SAndrew Morton handle_t *handle, struct buffer_head *bh) 3088984d137SAndrew Morton { 3090390131bSFrank Mayhar int err = 0; 3100390131bSFrank Mayhar 3110390131bSFrank Mayhar if (ext4_handle_valid(handle)) { 3120390131bSFrank Mayhar err = jbd2_journal_get_create_access(handle, bh); 3138984d137SAndrew Morton if (err) 31490c7201bSTheodore Ts'o ext4_journal_abort_handle(where, line, __func__, 31590c7201bSTheodore Ts'o bh, handle, err); 3160390131bSFrank Mayhar } 3178984d137SAndrew Morton return err; 3188984d137SAndrew Morton } 3198984d137SAndrew Morton 32090c7201bSTheodore Ts'o int __ext4_handle_dirty_metadata(const char *where, unsigned int line, 32190c7201bSTheodore Ts'o handle_t *handle, struct inode *inode, 32290c7201bSTheodore Ts'o struct buffer_head *bh) 3238984d137SAndrew Morton { 3240390131bSFrank Mayhar int err = 0; 3250390131bSFrank Mayhar 326b10a44c3STheodore Ts'o might_sleep(); 327b10a44c3STheodore Ts'o 32813fca323STheodore Ts'o set_buffer_meta(bh); 32913fca323STheodore Ts'o set_buffer_prio(bh); 3300390131bSFrank Mayhar if (ext4_handle_valid(handle)) { 3310390131bSFrank Mayhar err = jbd2_journal_dirty_metadata(handle, bh); 332c5d31192SDmitry Monakhov /* Errors can only happen due to aborted journal or a nasty bug */ 333c5d31192SDmitry Monakhov if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) { 33491aa11faSJan Kara ext4_journal_abort_handle(where, line, __func__, bh, 33591aa11faSJan Kara handle, err); 33666a4cb18STheodore Ts'o if (inode == NULL) { 33766a4cb18STheodore Ts'o pr_err("EXT4: jbd2_journal_dirty_metadata " 33866a4cb18STheodore Ts'o "failed: handle type %u started at " 33966a4cb18STheodore Ts'o "line %u, credits %u/%u, errcode %d", 34066a4cb18STheodore Ts'o handle->h_type, 34166a4cb18STheodore Ts'o handle->h_line_no, 34266a4cb18STheodore Ts'o handle->h_requested_credits, 343a9a8344eSJan Kara jbd2_handle_buffer_credits(handle), err); 34466a4cb18STheodore Ts'o return err; 34566a4cb18STheodore Ts'o } 346ae1495b1STheodore Ts'o ext4_error_inode(inode, where, line, 347ae1495b1STheodore Ts'o bh->b_blocknr, 348ae1495b1STheodore Ts'o "journal_dirty_metadata failed: " 349ae1495b1STheodore Ts'o "handle type %u started at line %u, " 350ae1495b1STheodore Ts'o "credits %u/%u, errcode %d", 351ae1495b1STheodore Ts'o handle->h_type, 352ae1495b1STheodore Ts'o handle->h_line_no, 353ae1495b1STheodore Ts'o handle->h_requested_credits, 354a9a8344eSJan Kara jbd2_handle_buffer_credits(handle), 355a9a8344eSJan Kara err); 3569ea7a0dfSTheodore Ts'o } 3570390131bSFrank Mayhar } else { 358f2eeca09SHarshad Shirwadkar set_buffer_uptodate(bh); 35973b50c1cSCurt Wohlgemuth if (inode) 360fe188c0eSTheodore Ts'o mark_buffer_dirty_inode(bh, inode); 361fe188c0eSTheodore Ts'o else 3620390131bSFrank Mayhar mark_buffer_dirty(bh); 3630390131bSFrank Mayhar if (inode && inode_needs_sync(inode)) { 3640390131bSFrank Mayhar sync_dirty_buffer(bh); 3650390131bSFrank Mayhar if (buffer_req(bh) && !buffer_uptodate(bh)) { 36654d3adbcSTheodore Ts'o ext4_error_inode_err(inode, where, line, 36754d3adbcSTheodore Ts'o bh->b_blocknr, EIO, 368c398eda0STheodore Ts'o "IO error syncing itable block"); 3690390131bSFrank Mayhar err = -EIO; 3700390131bSFrank Mayhar } 3710390131bSFrank Mayhar } 3720390131bSFrank Mayhar } 3738984d137SAndrew Morton return err; 3748984d137SAndrew Morton } 375a0375156STheodore Ts'o 37690c7201bSTheodore Ts'o int __ext4_handle_dirty_super(const char *where, unsigned int line, 377b50924c2SArtem Bityutskiy handle_t *handle, struct super_block *sb) 378a0375156STheodore Ts'o { 379a0375156STheodore Ts'o struct buffer_head *bh = EXT4_SB(sb)->s_sbh; 380a0375156STheodore Ts'o int err = 0; 381a0375156STheodore Ts'o 38206db49e6STheodore Ts'o ext4_superblock_csum_set(sb); 383a0375156STheodore Ts'o if (ext4_handle_valid(handle)) { 384a0375156STheodore Ts'o err = jbd2_journal_dirty_metadata(handle, bh); 385a0375156STheodore Ts'o if (err) 38690c7201bSTheodore Ts'o ext4_journal_abort_handle(where, line, __func__, 38790c7201bSTheodore Ts'o bh, handle, err); 38806db49e6STheodore Ts'o } else 389a9c47317SDarrick J. Wong mark_buffer_dirty(bh); 390a0375156STheodore Ts'o return err; 391a0375156STheodore Ts'o } 392