LCOV - code coverage report
Current view: top level - fs/ext4 - ext4_jbd2.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 0 186 0.0 %
Date: 2023-07-31 20:08:27 Functions: 0 14 0.0 %

          Line data    Source code
       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           0 : int ext4_inode_journal_mode(struct inode *inode)
      11             : {
      12           0 :         if (EXT4_JOURNAL(inode) == NULL)
      13             :                 return EXT4_INODE_WRITEBACK_DATA_MODE;  /* writeback */
      14             :         /* We do not support data journalling with delayed allocation */
      15           0 :         if (!S_ISREG(inode->i_mode) ||
      16           0 :             ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE) ||
      17           0 :             test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
      18           0 :             (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) &&
      19           0 :             !test_opt(inode->i_sb, DELALLOC))) {
      20             :                 /* We do not support data journalling for encrypted data */
      21           0 :                 if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode))
      22             :                         return EXT4_INODE_ORDERED_DATA_MODE;  /* ordered */
      23           0 :                 return EXT4_INODE_JOURNAL_DATA_MODE;    /* journal data */
      24             :         }
      25           0 :         if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
      26             :                 return EXT4_INODE_ORDERED_DATA_MODE;    /* ordered */
      27           0 :         if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
      28             :                 return EXT4_INODE_WRITEBACK_DATA_MODE;  /* writeback */
      29           0 :         BUG();
      30             : }
      31             : 
      32             : /* Just increment the non-pointer handle value */
      33           0 : static handle_t *ext4_get_nojournal(void)
      34             : {
      35           0 :         handle_t *handle = current->journal_info;
      36           0 :         unsigned long ref_cnt = (unsigned long)handle;
      37             : 
      38           0 :         BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT);
      39             : 
      40           0 :         ref_cnt++;
      41           0 :         handle = (handle_t *)ref_cnt;
      42             : 
      43           0 :         current->journal_info = handle;
      44           0 :         return handle;
      45             : }
      46             : 
      47             : 
      48             : /* Decrement the non-pointer handle value */
      49           0 : static void ext4_put_nojournal(handle_t *handle)
      50             : {
      51           0 :         unsigned long ref_cnt = (unsigned long)handle;
      52             : 
      53           0 :         BUG_ON(ref_cnt == 0);
      54             : 
      55           0 :         ref_cnt--;
      56           0 :         handle = (handle_t *)ref_cnt;
      57             : 
      58           0 :         current->journal_info = handle;
      59           0 : }
      60             : 
      61             : /*
      62             :  * Wrappers for jbd2_journal_start/end.
      63             :  */
      64           0 : static int ext4_journal_check_start(struct super_block *sb)
      65             : {
      66           0 :         journal_t *journal;
      67             : 
      68           0 :         might_sleep();
      69             : 
      70           0 :         if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
      71             :                 return -EIO;
      72             : 
      73           0 :         if (sb_rdonly(sb))
      74             :                 return -EROFS;
      75           0 :         WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
      76           0 :         journal = EXT4_SB(sb)->s_journal;
      77             :         /*
      78             :          * Special case here: if the journal has aborted behind our
      79             :          * backs (eg. EIO in the commit thread), then we still need to
      80             :          * take the FS itself readonly cleanly.
      81             :          */
      82           0 :         if (journal && is_journal_aborted(journal)) {
      83           0 :                 ext4_abort(sb, -journal->j_errno, "Detected aborted journal");
      84           0 :                 return -EROFS;
      85             :         }
      86             :         return 0;
      87             : }
      88             : 
      89           0 : handle_t *__ext4_journal_start_sb(struct inode *inode,
      90             :                                   struct super_block *sb, unsigned int line,
      91             :                                   int type, int blocks, int rsv_blocks,
      92             :                                   int revoke_creds)
      93             : {
      94           0 :         journal_t *journal;
      95           0 :         int err;
      96           0 :         if (inode)
      97           0 :                 trace_ext4_journal_start_inode(inode, blocks, rsv_blocks,
      98             :                                         revoke_creds, type,
      99           0 :                                         _RET_IP_);
     100             :         else
     101           0 :                 trace_ext4_journal_start_sb(sb, blocks, rsv_blocks,
     102             :                                         revoke_creds, type,
     103           0 :                                         _RET_IP_);
     104           0 :         err = ext4_journal_check_start(sb);
     105           0 :         if (err < 0)
     106           0 :                 return ERR_PTR(err);
     107             : 
     108           0 :         journal = EXT4_SB(sb)->s_journal;
     109           0 :         if (!journal || (EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY))
     110           0 :                 return ext4_get_nojournal();
     111           0 :         return jbd2__journal_start(journal, blocks, rsv_blocks, revoke_creds,
     112             :                                    GFP_NOFS, type, line);
     113             : }
     114             : 
     115           0 : int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
     116             : {
     117           0 :         struct super_block *sb;
     118           0 :         int err;
     119           0 :         int rc;
     120             : 
     121           0 :         if (!ext4_handle_valid(handle)) {
     122           0 :                 ext4_put_nojournal(handle);
     123           0 :                 return 0;
     124             :         }
     125             : 
     126           0 :         err = handle->h_err;
     127           0 :         if (!handle->h_transaction) {
     128           0 :                 rc = jbd2_journal_stop(handle);
     129           0 :                 return err ? err : rc;
     130             :         }
     131             : 
     132           0 :         sb = handle->h_transaction->t_journal->j_private;
     133           0 :         rc = jbd2_journal_stop(handle);
     134             : 
     135           0 :         if (!err)
     136           0 :                 err = rc;
     137           0 :         if (err)
     138           0 :                 __ext4_std_error(sb, where, line, err);
     139             :         return err;
     140             : }
     141             : 
     142           0 : handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
     143             :                                         int type)
     144             : {
     145           0 :         struct super_block *sb;
     146           0 :         int err;
     147             : 
     148           0 :         if (!ext4_handle_valid(handle))
     149           0 :                 return ext4_get_nojournal();
     150             : 
     151           0 :         sb = handle->h_journal->j_private;
     152           0 :         trace_ext4_journal_start_reserved(sb,
     153           0 :                                 jbd2_handle_buffer_credits(handle), _RET_IP_);
     154           0 :         err = ext4_journal_check_start(sb);
     155           0 :         if (err < 0) {
     156           0 :                 jbd2_journal_free_reserved(handle);
     157           0 :                 return ERR_PTR(err);
     158             :         }
     159             : 
     160           0 :         err = jbd2_journal_start_reserved(handle, type, line);
     161           0 :         if (err < 0)
     162           0 :                 return ERR_PTR(err);
     163             :         return handle;
     164             : }
     165             : 
     166           0 : int __ext4_journal_ensure_credits(handle_t *handle, int check_cred,
     167             :                                   int extend_cred, int revoke_cred)
     168             : {
     169           0 :         if (!ext4_handle_valid(handle))
     170             :                 return 0;
     171           0 :         if (is_handle_aborted(handle))
     172             :                 return -EROFS;
     173           0 :         if (jbd2_handle_buffer_credits(handle) >= check_cred &&
     174           0 :             handle->h_revoke_credits >= revoke_cred)
     175             :                 return 0;
     176           0 :         extend_cred = max(0, extend_cred - jbd2_handle_buffer_credits(handle));
     177           0 :         revoke_cred = max(0, revoke_cred - handle->h_revoke_credits);
     178           0 :         return ext4_journal_extend(handle, extend_cred, revoke_cred);
     179             : }
     180             : 
     181           0 : static void ext4_journal_abort_handle(const char *caller, unsigned int line,
     182             :                                       const char *err_fn,
     183             :                                       struct buffer_head *bh,
     184             :                                       handle_t *handle, int err)
     185             : {
     186           0 :         char nbuf[16];
     187           0 :         const char *errstr = ext4_decode_error(NULL, err, nbuf);
     188             : 
     189           0 :         BUG_ON(!ext4_handle_valid(handle));
     190             : 
     191           0 :         if (bh)
     192           0 :                 BUFFER_TRACE(bh, "abort");
     193             : 
     194           0 :         if (!handle->h_err)
     195           0 :                 handle->h_err = err;
     196             : 
     197           0 :         if (is_handle_aborted(handle))
     198           0 :                 return;
     199             : 
     200           0 :         printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
     201             :                caller, line, errstr, err_fn);
     202             : 
     203           0 :         jbd2_journal_abort_handle(handle);
     204             : }
     205             : 
     206           0 : static void ext4_check_bdev_write_error(struct super_block *sb)
     207             : {
     208           0 :         struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
     209           0 :         struct ext4_sb_info *sbi = EXT4_SB(sb);
     210           0 :         int err;
     211             : 
     212             :         /*
     213             :          * If the block device has write error flag, it may have failed to
     214             :          * async write out metadata buffers in the background. In this case,
     215             :          * we could read old data from disk and write it out again, which
     216             :          * may lead to on-disk filesystem inconsistency.
     217             :          */
     218           0 :         if (errseq_check(&mapping->wb_err, READ_ONCE(sbi->s_bdev_wb_err))) {
     219           0 :                 spin_lock(&sbi->s_bdev_wb_lock);
     220           0 :                 err = errseq_check_and_advance(&mapping->wb_err, &sbi->s_bdev_wb_err);
     221           0 :                 spin_unlock(&sbi->s_bdev_wb_lock);
     222           0 :                 if (err)
     223           0 :                         ext4_error_err(sb, -err,
     224             :                                        "Error while async write back metadata");
     225             :         }
     226           0 : }
     227             : 
     228           0 : int __ext4_journal_get_write_access(const char *where, unsigned int line,
     229             :                                     handle_t *handle, struct super_block *sb,
     230             :                                     struct buffer_head *bh,
     231             :                                     enum ext4_journal_trigger_type trigger_type)
     232             : {
     233           0 :         int err;
     234             : 
     235           0 :         might_sleep();
     236             : 
     237           0 :         if (bh->b_bdev->bd_super)
     238           0 :                 ext4_check_bdev_write_error(bh->b_bdev->bd_super);
     239             : 
     240           0 :         if (ext4_handle_valid(handle)) {
     241           0 :                 err = jbd2_journal_get_write_access(handle, bh);
     242           0 :                 if (err) {
     243           0 :                         ext4_journal_abort_handle(where, line, __func__, bh,
     244             :                                                   handle, err);
     245           0 :                         return err;
     246             :                 }
     247             :         }
     248           0 :         if (trigger_type == EXT4_JTR_NONE || !ext4_has_metadata_csum(sb))
     249           0 :                 return 0;
     250           0 :         BUG_ON(trigger_type >= EXT4_JOURNAL_TRIGGER_COUNT);
     251           0 :         jbd2_journal_set_triggers(bh,
     252             :                 &EXT4_SB(sb)->s_journal_triggers[trigger_type].tr_triggers);
     253           0 :         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           0 : 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           0 :         int err;
     270             : 
     271           0 :         might_sleep();
     272             : 
     273           0 :         trace_ext4_forget(inode, is_metadata, blocknr);
     274           0 :         BUFFER_TRACE(bh, "enter");
     275             : 
     276           0 :         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           0 :         if (!ext4_handle_valid(handle)) {
     282           0 :                 bforget(bh);
     283           0 :                 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           0 :         if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
     292           0 :             (!is_metadata && !ext4_should_journal_data(inode))) {
     293           0 :                 if (bh) {
     294           0 :                         BUFFER_TRACE(bh, "call jbd2_journal_forget");
     295           0 :                         err = jbd2_journal_forget(handle, bh);
     296           0 :                         if (err)
     297           0 :                                 ext4_journal_abort_handle(where, line, __func__,
     298             :                                                           bh, handle, err);
     299           0 :                         return err;
     300             :                 }
     301             :                 return 0;
     302             :         }
     303             : 
     304             :         /*
     305             :          * data!=journal && (is_metadata || should_journal_data(inode))
     306             :          */
     307           0 :         BUFFER_TRACE(bh, "call jbd2_journal_revoke");
     308           0 :         err = jbd2_journal_revoke(handle, blocknr, bh);
     309           0 :         if (err) {
     310           0 :                 ext4_journal_abort_handle(where, line, __func__,
     311             :                                           bh, handle, err);
     312           0 :                 __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           0 : 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           0 :         int err;
     325             : 
     326           0 :         if (!ext4_handle_valid(handle))
     327             :                 return 0;
     328             : 
     329           0 :         err = jbd2_journal_get_create_access(handle, bh);
     330           0 :         if (err) {
     331           0 :                 ext4_journal_abort_handle(where, line, __func__, bh, handle,
     332             :                                           err);
     333           0 :                 return err;
     334             :         }
     335           0 :         if (trigger_type == EXT4_JTR_NONE || !ext4_has_metadata_csum(sb))
     336           0 :                 return 0;
     337           0 :         BUG_ON(trigger_type >= EXT4_JOURNAL_TRIGGER_COUNT);
     338           0 :         jbd2_journal_set_triggers(bh,
     339             :                 &EXT4_SB(sb)->s_journal_triggers[trigger_type].tr_triggers);
     340           0 :         return 0;
     341             : }
     342             : 
     343           0 : 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           0 :         int err = 0;
     348             : 
     349           0 :         might_sleep();
     350             : 
     351           0 :         set_buffer_meta(bh);
     352           0 :         set_buffer_prio(bh);
     353           0 :         set_buffer_uptodate(bh);
     354           0 :         if (ext4_handle_valid(handle)) {
     355           0 :                 err = jbd2_journal_dirty_metadata(handle, bh);
     356             :                 /* Errors can only happen due to aborted journal or a nasty bug */
     357           0 :                 if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
     358           0 :                         ext4_journal_abort_handle(where, line, __func__, bh,
     359             :                                                   handle, err);
     360           0 :                         if (inode == NULL) {
     361           0 :                                 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           0 :                                 return err;
     369             :                         }
     370           0 :                         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           0 :                 if (inode)
     383           0 :                         mark_buffer_dirty_inode(bh, inode);
     384             :                 else
     385           0 :                         mark_buffer_dirty(bh);
     386           0 :                 if (inode && inode_needs_sync(inode)) {
     387           0 :                         sync_dirty_buffer(bh);
     388           0 :                         if (buffer_req(bh) && !buffer_uptodate(bh)) {
     389           0 :                                 ext4_error_inode_err(inode, where, line,
     390             :                                                      bh->b_blocknr, EIO,
     391             :                                         "IO error syncing itable block");
     392           0 :                                 err = -EIO;
     393             :                         }
     394             :                 }
     395             :         }
     396             :         return err;
     397             : }

Generated by: LCOV version 1.14