18984d137SAndrew Morton /* 28984d137SAndrew Morton * Interface between ext4 and JBD 38984d137SAndrew Morton */ 48984d137SAndrew Morton 53dcf5451SChristoph Hellwig #include "ext4_jbd2.h" 68984d137SAndrew Morton 7d6797d14STheodore Ts'o #include <trace/events/ext4.h> 8d6797d14STheodore Ts'o 9722887ddSTheodore Ts'o /* Just increment the non-pointer handle value */ 10722887ddSTheodore Ts'o static handle_t *ext4_get_nojournal(void) 11722887ddSTheodore Ts'o { 12722887ddSTheodore Ts'o handle_t *handle = current->journal_info; 13722887ddSTheodore Ts'o unsigned long ref_cnt = (unsigned long)handle; 14722887ddSTheodore Ts'o 15722887ddSTheodore Ts'o BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT); 16722887ddSTheodore Ts'o 17722887ddSTheodore Ts'o ref_cnt++; 18722887ddSTheodore Ts'o handle = (handle_t *)ref_cnt; 19722887ddSTheodore Ts'o 20722887ddSTheodore Ts'o current->journal_info = handle; 21722887ddSTheodore Ts'o return handle; 22722887ddSTheodore Ts'o } 23722887ddSTheodore Ts'o 24722887ddSTheodore Ts'o 25722887ddSTheodore Ts'o /* Decrement the non-pointer handle value */ 26722887ddSTheodore Ts'o static void ext4_put_nojournal(handle_t *handle) 27722887ddSTheodore Ts'o { 28722887ddSTheodore Ts'o unsigned long ref_cnt = (unsigned long)handle; 29722887ddSTheodore Ts'o 30722887ddSTheodore Ts'o BUG_ON(ref_cnt == 0); 31722887ddSTheodore Ts'o 32722887ddSTheodore Ts'o ref_cnt--; 33722887ddSTheodore Ts'o handle = (handle_t *)ref_cnt; 34722887ddSTheodore Ts'o 35722887ddSTheodore Ts'o current->journal_info = handle; 36722887ddSTheodore Ts'o } 37722887ddSTheodore Ts'o 38722887ddSTheodore Ts'o /* 39722887ddSTheodore Ts'o * Wrappers for jbd2_journal_start/end. 40722887ddSTheodore Ts'o */ 415fe2fe89SJan Kara static int ext4_journal_check_start(struct super_block *sb) 42722887ddSTheodore Ts'o { 43722887ddSTheodore Ts'o journal_t *journal; 44722887ddSTheodore Ts'o 45b10a44c3STheodore Ts'o might_sleep(); 46722887ddSTheodore Ts'o if (sb->s_flags & MS_RDONLY) 475fe2fe89SJan Kara return -EROFS; 48722887ddSTheodore Ts'o WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE); 49722887ddSTheodore Ts'o journal = EXT4_SB(sb)->s_journal; 50722887ddSTheodore Ts'o /* 51722887ddSTheodore Ts'o * Special case here: if the journal has aborted behind our 52722887ddSTheodore Ts'o * backs (eg. EIO in the commit thread), then we still need to 53722887ddSTheodore Ts'o * take the FS itself readonly cleanly. 54722887ddSTheodore Ts'o */ 555fe2fe89SJan Kara if (journal && is_journal_aborted(journal)) { 56722887ddSTheodore Ts'o ext4_abort(sb, "Detected aborted journal"); 575fe2fe89SJan Kara return -EROFS; 58722887ddSTheodore Ts'o } 595fe2fe89SJan Kara return 0; 605fe2fe89SJan Kara } 615fe2fe89SJan Kara 625fe2fe89SJan Kara handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line, 635fe2fe89SJan Kara int type, int blocks, int rsv_blocks) 645fe2fe89SJan Kara { 655fe2fe89SJan Kara journal_t *journal; 665fe2fe89SJan Kara int err; 675fe2fe89SJan Kara 685fe2fe89SJan Kara trace_ext4_journal_start(sb, blocks, rsv_blocks, _RET_IP_); 695fe2fe89SJan Kara err = ext4_journal_check_start(sb); 705fe2fe89SJan Kara if (err < 0) 715fe2fe89SJan Kara return ERR_PTR(err); 725fe2fe89SJan Kara 735fe2fe89SJan Kara journal = EXT4_SB(sb)->s_journal; 745fe2fe89SJan Kara if (!journal) 755fe2fe89SJan Kara return ext4_get_nojournal(); 765fe2fe89SJan Kara return jbd2__journal_start(journal, blocks, rsv_blocks, GFP_NOFS, 775fe2fe89SJan Kara type, line); 78722887ddSTheodore Ts'o } 79722887ddSTheodore Ts'o 80722887ddSTheodore Ts'o int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle) 81722887ddSTheodore Ts'o { 82722887ddSTheodore Ts'o struct super_block *sb; 83722887ddSTheodore Ts'o int err; 84722887ddSTheodore Ts'o int rc; 85722887ddSTheodore Ts'o 86722887ddSTheodore Ts'o if (!ext4_handle_valid(handle)) { 87722887ddSTheodore Ts'o ext4_put_nojournal(handle); 88722887ddSTheodore Ts'o return 0; 89722887ddSTheodore Ts'o } 90722887ddSTheodore Ts'o sb = handle->h_transaction->t_journal->j_private; 91722887ddSTheodore Ts'o err = handle->h_err; 92722887ddSTheodore Ts'o rc = jbd2_journal_stop(handle); 93722887ddSTheodore Ts'o 94722887ddSTheodore Ts'o if (!err) 95722887ddSTheodore Ts'o err = rc; 96722887ddSTheodore Ts'o if (err) 97722887ddSTheodore Ts'o __ext4_std_error(sb, where, line, err); 98722887ddSTheodore Ts'o return err; 99722887ddSTheodore Ts'o } 100722887ddSTheodore Ts'o 1015fe2fe89SJan Kara handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line, 1025fe2fe89SJan Kara int type) 1035fe2fe89SJan Kara { 1045fe2fe89SJan Kara struct super_block *sb; 1055fe2fe89SJan Kara int err; 1065fe2fe89SJan Kara 1075fe2fe89SJan Kara if (!ext4_handle_valid(handle)) 1085fe2fe89SJan Kara return ext4_get_nojournal(); 1095fe2fe89SJan Kara 1105fe2fe89SJan Kara sb = handle->h_journal->j_private; 1115fe2fe89SJan Kara trace_ext4_journal_start_reserved(sb, handle->h_buffer_credits, 1125fe2fe89SJan Kara _RET_IP_); 1135fe2fe89SJan Kara err = ext4_journal_check_start(sb); 1145fe2fe89SJan Kara if (err < 0) { 1155fe2fe89SJan Kara jbd2_journal_free_reserved(handle); 1165fe2fe89SJan Kara return ERR_PTR(err); 1175fe2fe89SJan Kara } 1185fe2fe89SJan Kara 1195fe2fe89SJan Kara err = jbd2_journal_start_reserved(handle, type, line); 1205fe2fe89SJan Kara if (err < 0) 1215fe2fe89SJan Kara return ERR_PTR(err); 1225fe2fe89SJan Kara return handle; 1235fe2fe89SJan Kara } 1245fe2fe89SJan Kara 125722887ddSTheodore Ts'o void ext4_journal_abort_handle(const char *caller, unsigned int line, 126722887ddSTheodore Ts'o const char *err_fn, struct buffer_head *bh, 127722887ddSTheodore Ts'o handle_t *handle, int err) 128722887ddSTheodore Ts'o { 129722887ddSTheodore Ts'o char nbuf[16]; 130722887ddSTheodore Ts'o const char *errstr = ext4_decode_error(NULL, err, nbuf); 131722887ddSTheodore Ts'o 132722887ddSTheodore Ts'o BUG_ON(!ext4_handle_valid(handle)); 133722887ddSTheodore Ts'o 134722887ddSTheodore Ts'o if (bh) 135722887ddSTheodore Ts'o BUFFER_TRACE(bh, "abort"); 136722887ddSTheodore Ts'o 137722887ddSTheodore Ts'o if (!handle->h_err) 138722887ddSTheodore Ts'o handle->h_err = err; 139722887ddSTheodore Ts'o 140722887ddSTheodore Ts'o if (is_handle_aborted(handle)) 141722887ddSTheodore Ts'o return; 142722887ddSTheodore Ts'o 143722887ddSTheodore Ts'o printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n", 144722887ddSTheodore Ts'o caller, line, errstr, err_fn); 145722887ddSTheodore Ts'o 146722887ddSTheodore Ts'o jbd2_journal_abort_handle(handle); 147722887ddSTheodore Ts'o } 148722887ddSTheodore Ts'o 14990c7201bSTheodore Ts'o int __ext4_journal_get_write_access(const char *where, unsigned int line, 15090c7201bSTheodore Ts'o handle_t *handle, struct buffer_head *bh) 1518984d137SAndrew Morton { 1520390131bSFrank Mayhar int err = 0; 1530390131bSFrank Mayhar 154b10a44c3STheodore Ts'o might_sleep(); 155b10a44c3STheodore Ts'o 1560390131bSFrank Mayhar if (ext4_handle_valid(handle)) { 1570390131bSFrank Mayhar err = jbd2_journal_get_write_access(handle, bh); 1588984d137SAndrew Morton if (err) 15990c7201bSTheodore Ts'o ext4_journal_abort_handle(where, line, __func__, bh, 1600390131bSFrank Mayhar handle, err); 1610390131bSFrank Mayhar } 1628984d137SAndrew Morton return err; 1638984d137SAndrew Morton } 1648984d137SAndrew Morton 165d6797d14STheodore Ts'o /* 166d6797d14STheodore Ts'o * The ext4 forget function must perform a revoke if we are freeing data 167d6797d14STheodore Ts'o * which has been journaled. Metadata (eg. indirect blocks) must be 168d6797d14STheodore Ts'o * revoked in all cases. 169d6797d14STheodore Ts'o * 170d6797d14STheodore Ts'o * "bh" may be NULL: a metadata block may have been freed from memory 171d6797d14STheodore Ts'o * but there may still be a record of it in the journal, and that record 172d6797d14STheodore Ts'o * still needs to be revoked. 173d6797d14STheodore Ts'o * 174d6797d14STheodore Ts'o * If the handle isn't valid we're not journaling, but we still need to 175d6797d14STheodore Ts'o * call into ext4_journal_revoke() to put the buffer head. 176d6797d14STheodore Ts'o */ 17790c7201bSTheodore Ts'o int __ext4_forget(const char *where, unsigned int line, handle_t *handle, 17890c7201bSTheodore Ts'o int is_metadata, struct inode *inode, 17990c7201bSTheodore Ts'o struct buffer_head *bh, ext4_fsblk_t blocknr) 180d6797d14STheodore Ts'o { 181d6797d14STheodore Ts'o int err; 182d6797d14STheodore Ts'o 183d6797d14STheodore Ts'o might_sleep(); 184d6797d14STheodore Ts'o 185d6797d14STheodore Ts'o trace_ext4_forget(inode, is_metadata, blocknr); 186d6797d14STheodore Ts'o BUFFER_TRACE(bh, "enter"); 187d6797d14STheodore Ts'o 188d6797d14STheodore Ts'o jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " 189d6797d14STheodore Ts'o "data mode %x\n", 190d6797d14STheodore Ts'o bh, is_metadata, inode->i_mode, 191d6797d14STheodore Ts'o test_opt(inode->i_sb, DATA_FLAGS)); 192d6797d14STheodore Ts'o 193e4684b3fSTheodore Ts'o /* In the no journal case, we can just do a bforget and return */ 194e4684b3fSTheodore Ts'o if (!ext4_handle_valid(handle)) { 195e4684b3fSTheodore Ts'o bforget(bh); 196e4684b3fSTheodore Ts'o return 0; 197e4684b3fSTheodore Ts'o } 198e4684b3fSTheodore Ts'o 199d6797d14STheodore Ts'o /* Never use the revoke function if we are doing full data 200d6797d14STheodore Ts'o * journaling: there is no need to, and a V1 superblock won't 201d6797d14STheodore Ts'o * support it. Otherwise, only skip the revoke on un-journaled 202d6797d14STheodore Ts'o * data blocks. */ 203d6797d14STheodore Ts'o 204d6797d14STheodore Ts'o if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || 205d6797d14STheodore Ts'o (!is_metadata && !ext4_should_journal_data(inode))) { 206d6797d14STheodore Ts'o if (bh) { 207d6797d14STheodore Ts'o BUFFER_TRACE(bh, "call jbd2_journal_forget"); 208b7e57e7cSTheodore Ts'o err = jbd2_journal_forget(handle, bh); 209b7e57e7cSTheodore Ts'o if (err) 21090c7201bSTheodore Ts'o ext4_journal_abort_handle(where, line, __func__, 21190c7201bSTheodore Ts'o bh, handle, err); 212b7e57e7cSTheodore Ts'o return err; 213d6797d14STheodore Ts'o } 214d6797d14STheodore Ts'o return 0; 215d6797d14STheodore Ts'o } 216d6797d14STheodore Ts'o 217d6797d14STheodore Ts'o /* 218d6797d14STheodore Ts'o * data!=journal && (is_metadata || should_journal_data(inode)) 219d6797d14STheodore Ts'o */ 220e4684b3fSTheodore Ts'o BUFFER_TRACE(bh, "call jbd2_journal_revoke"); 221e4684b3fSTheodore Ts'o err = jbd2_journal_revoke(handle, blocknr, bh); 222e4684b3fSTheodore Ts'o if (err) { 22390c7201bSTheodore Ts'o ext4_journal_abort_handle(where, line, __func__, 22490c7201bSTheodore Ts'o bh, handle, err); 225c398eda0STheodore Ts'o __ext4_abort(inode->i_sb, where, line, 226d6797d14STheodore Ts'o "error %d when attempting revoke", err); 227e4684b3fSTheodore Ts'o } 228d6797d14STheodore Ts'o BUFFER_TRACE(bh, "exit"); 229d6797d14STheodore Ts'o return err; 230d6797d14STheodore Ts'o } 231d6797d14STheodore Ts'o 23290c7201bSTheodore Ts'o int __ext4_journal_get_create_access(const char *where, unsigned int line, 2338984d137SAndrew Morton handle_t *handle, struct buffer_head *bh) 2348984d137SAndrew Morton { 2350390131bSFrank Mayhar int err = 0; 2360390131bSFrank Mayhar 2370390131bSFrank Mayhar if (ext4_handle_valid(handle)) { 2380390131bSFrank Mayhar err = jbd2_journal_get_create_access(handle, bh); 2398984d137SAndrew Morton if (err) 24090c7201bSTheodore Ts'o ext4_journal_abort_handle(where, line, __func__, 24190c7201bSTheodore Ts'o bh, handle, err); 2420390131bSFrank Mayhar } 2438984d137SAndrew Morton return err; 2448984d137SAndrew Morton } 2458984d137SAndrew Morton 24690c7201bSTheodore Ts'o int __ext4_handle_dirty_metadata(const char *where, unsigned int line, 24790c7201bSTheodore Ts'o handle_t *handle, struct inode *inode, 24890c7201bSTheodore Ts'o struct buffer_head *bh) 2498984d137SAndrew Morton { 2500390131bSFrank Mayhar int err = 0; 2510390131bSFrank Mayhar 252b10a44c3STheodore Ts'o might_sleep(); 253b10a44c3STheodore Ts'o 25413fca323STheodore Ts'o set_buffer_meta(bh); 25513fca323STheodore Ts'o set_buffer_prio(bh); 2560390131bSFrank Mayhar if (ext4_handle_valid(handle)) { 2570390131bSFrank Mayhar err = jbd2_journal_dirty_metadata(handle, bh); 2589ea7a0dfSTheodore Ts'o if (err) { 2599ea7a0dfSTheodore Ts'o /* Errors can only happen if there is a bug */ 2609ea7a0dfSTheodore Ts'o handle->h_err = err; 2619ea7a0dfSTheodore Ts'o __ext4_journal_stop(where, line, handle); 2629ea7a0dfSTheodore Ts'o } 2630390131bSFrank Mayhar } else { 26473b50c1cSCurt Wohlgemuth if (inode) 265fe188c0eSTheodore Ts'o mark_buffer_dirty_inode(bh, inode); 266fe188c0eSTheodore Ts'o else 2670390131bSFrank Mayhar mark_buffer_dirty(bh); 2680390131bSFrank Mayhar if (inode && inode_needs_sync(inode)) { 2690390131bSFrank Mayhar sync_dirty_buffer(bh); 2700390131bSFrank Mayhar if (buffer_req(bh) && !buffer_uptodate(bh)) { 2711c13d5c0STheodore Ts'o struct ext4_super_block *es; 2721c13d5c0STheodore Ts'o 2731c13d5c0STheodore Ts'o es = EXT4_SB(inode->i_sb)->s_es; 2741c13d5c0STheodore Ts'o es->s_last_error_block = 2751c13d5c0STheodore Ts'o cpu_to_le64(bh->b_blocknr); 276c398eda0STheodore Ts'o ext4_error_inode(inode, where, line, 277c398eda0STheodore Ts'o bh->b_blocknr, 278c398eda0STheodore Ts'o "IO error syncing itable block"); 2790390131bSFrank Mayhar err = -EIO; 2800390131bSFrank Mayhar } 2810390131bSFrank Mayhar } 2820390131bSFrank Mayhar } 2838984d137SAndrew Morton return err; 2848984d137SAndrew Morton } 285a0375156STheodore Ts'o 28690c7201bSTheodore Ts'o int __ext4_handle_dirty_super(const char *where, unsigned int line, 287b50924c2SArtem Bityutskiy handle_t *handle, struct super_block *sb) 288a0375156STheodore Ts'o { 289a0375156STheodore Ts'o struct buffer_head *bh = EXT4_SB(sb)->s_sbh; 290a0375156STheodore Ts'o int err = 0; 291a0375156STheodore Ts'o 29206db49e6STheodore Ts'o ext4_superblock_csum_set(sb); 293a0375156STheodore Ts'o if (ext4_handle_valid(handle)) { 294a0375156STheodore Ts'o err = jbd2_journal_dirty_metadata(handle, bh); 295a0375156STheodore Ts'o if (err) 29690c7201bSTheodore Ts'o ext4_journal_abort_handle(where, line, __func__, 29790c7201bSTheodore Ts'o bh, handle, err); 29806db49e6STheodore Ts'o } else 299a9c47317SDarrick J. Wong mark_buffer_dirty(bh); 300a0375156STheodore Ts'o return err; 301a0375156STheodore Ts'o } 302