LCOV - code coverage report
Current view: top level - fs/ext4 - ext4_jbd2.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 94 172 54.7 %
Date: 2021-04-22 12:43:58 Functions: 11 14 78.6 %

          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       17251 : int ext4_inode_journal_mode(struct inode *inode)
      11             : {
      12       17251 :         if (EXT4_JOURNAL(inode) == NULL)
      13             :                 return EXT4_INODE_WRITEBACK_DATA_MODE;  /* writeback */
      14             :         /* We do not support data journalling with delayed allocation */
      15       17249 :         if (!S_ISREG(inode->i_mode) ||
      16       16153 :             ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE) ||
      17       16153 :             test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
      18       16153 :             (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        1096 :                 if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode))
      22             :                         return EXT4_INODE_ORDERED_DATA_MODE;  /* ordered */
      23        1096 :                 return EXT4_INODE_JOURNAL_DATA_MODE;    /* journal data */
      24             :         }
      25       16153 :         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        8919 : static int ext4_journal_check_start(struct super_block *sb)
      65             : {
      66        8919 :         journal_t *journal;
      67             : 
      68        8919 :         might_sleep();
      69             : 
      70        8919 :         if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
      71             :                 return -EIO;
      72             : 
      73        8919 :         if (sb_rdonly(sb))
      74             :                 return -EROFS;
      75        8919 :         WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
      76        8919 :         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        8919 :         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        8849 : handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
      90             :                                   int type, int blocks, int rsv_blocks,
      91             :                                   int revoke_creds)
      92             : {
      93        8849 :         journal_t *journal;
      94        8849 :         int err;
      95             : 
      96        8849 :         trace_ext4_journal_start(sb, blocks, rsv_blocks, revoke_creds,
      97        8849 :                                  _RET_IP_);
      98        8849 :         err = ext4_journal_check_start(sb);
      99        8849 :         if (err < 0)
     100           0 :                 return ERR_PTR(err);
     101             : 
     102        8849 :         journal = EXT4_SB(sb)->s_journal;
     103        8849 :         if (!journal || (EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY))
     104           0 :                 return ext4_get_nojournal();
     105        8849 :         return jbd2__journal_start(journal, blocks, rsv_blocks, revoke_creds,
     106             :                                    GFP_NOFS, type, line);
     107             : }
     108             : 
     109        8919 : int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
     110             : {
     111        8919 :         struct super_block *sb;
     112        8919 :         int err;
     113        8919 :         int rc;
     114             : 
     115        8919 :         if (!ext4_handle_valid(handle)) {
     116           0 :                 ext4_put_nojournal(handle);
     117           0 :                 return 0;
     118             :         }
     119             : 
     120        8919 :         err = handle->h_err;
     121        8919 :         if (!handle->h_transaction) {
     122           0 :                 rc = jbd2_journal_stop(handle);
     123           0 :                 return err ? err : rc;
     124             :         }
     125             : 
     126        8919 :         sb = handle->h_transaction->t_journal->j_private;
     127        8919 :         rc = jbd2_journal_stop(handle);
     128             : 
     129        8919 :         if (!err)
     130        8919 :                 err = rc;
     131        8919 :         if (err)
     132           0 :                 __ext4_std_error(sb, where, line, err);
     133             :         return err;
     134             : }
     135             : 
     136          70 : handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
     137             :                                         int type)
     138             : {
     139          70 :         struct super_block *sb;
     140          70 :         int err;
     141             : 
     142          70 :         if (!ext4_handle_valid(handle))
     143           0 :                 return ext4_get_nojournal();
     144             : 
     145          70 :         sb = handle->h_journal->j_private;
     146          70 :         trace_ext4_journal_start_reserved(sb,
     147          70 :                                 jbd2_handle_buffer_credits(handle), _RET_IP_);
     148          70 :         err = ext4_journal_check_start(sb);
     149          70 :         if (err < 0) {
     150           0 :                 jbd2_journal_free_reserved(handle);
     151           0 :                 return ERR_PTR(err);
     152             :         }
     153             : 
     154          70 :         err = jbd2_journal_start_reserved(handle, type, line);
     155          70 :         if (err < 0)
     156           0 :                 return ERR_PTR(err);
     157             :         return handle;
     158             : }
     159             : 
     160         393 : int __ext4_journal_ensure_credits(handle_t *handle, int check_cred,
     161             :                                   int extend_cred, int revoke_cred)
     162             : {
     163         393 :         if (!ext4_handle_valid(handle))
     164             :                 return 0;
     165         393 :         if (jbd2_handle_buffer_credits(handle) >= check_cred &&
     166         393 :             handle->h_revoke_credits >= revoke_cred)
     167             :                 return 0;
     168           0 :         extend_cred = max(0, extend_cred - jbd2_handle_buffer_credits(handle));
     169           0 :         revoke_cred = max(0, revoke_cred - handle->h_revoke_credits);
     170           0 :         return ext4_journal_extend(handle, extend_cred, revoke_cred);
     171             : }
     172             : 
     173           0 : static void ext4_journal_abort_handle(const char *caller, unsigned int line,
     174             :                                       const char *err_fn,
     175             :                                       struct buffer_head *bh,
     176             :                                       handle_t *handle, int err)
     177             : {
     178           0 :         char nbuf[16];
     179           0 :         const char *errstr = ext4_decode_error(NULL, err, nbuf);
     180             : 
     181           0 :         BUG_ON(!ext4_handle_valid(handle));
     182             : 
     183           0 :         if (bh)
     184           0 :                 BUFFER_TRACE(bh, "abort");
     185             : 
     186           0 :         if (!handle->h_err)
     187           0 :                 handle->h_err = err;
     188             : 
     189           0 :         if (is_handle_aborted(handle))
     190           0 :                 return;
     191             : 
     192           0 :         printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
     193             :                caller, line, errstr, err_fn);
     194             : 
     195           0 :         jbd2_journal_abort_handle(handle);
     196             : }
     197             : 
     198       14537 : static void ext4_check_bdev_write_error(struct super_block *sb)
     199             : {
     200       14537 :         struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
     201       14537 :         struct ext4_sb_info *sbi = EXT4_SB(sb);
     202       14537 :         int err;
     203             : 
     204             :         /*
     205             :          * If the block device has write error flag, it may have failed to
     206             :          * async write out metadata buffers in the background. In this case,
     207             :          * we could read old data from disk and write it out again, which
     208             :          * may lead to on-disk filesystem inconsistency.
     209             :          */
     210       14537 :         if (errseq_check(&mapping->wb_err, READ_ONCE(sbi->s_bdev_wb_err))) {
     211           0 :                 spin_lock(&sbi->s_bdev_wb_lock);
     212           0 :                 err = errseq_check_and_advance(&mapping->wb_err, &sbi->s_bdev_wb_err);
     213           0 :                 spin_unlock(&sbi->s_bdev_wb_lock);
     214           0 :                 if (err)
     215           0 :                         ext4_error_err(sb, -err,
     216             :                                        "Error while async write back metadata");
     217             :         }
     218       14537 : }
     219             : 
     220       14537 : int __ext4_journal_get_write_access(const char *where, unsigned int line,
     221             :                                     handle_t *handle, struct buffer_head *bh)
     222             : {
     223       14537 :         int err = 0;
     224             : 
     225       14537 :         might_sleep();
     226             : 
     227       14537 :         if (bh->b_bdev->bd_super)
     228       14537 :                 ext4_check_bdev_write_error(bh->b_bdev->bd_super);
     229             : 
     230       14537 :         if (ext4_handle_valid(handle)) {
     231       14537 :                 err = jbd2_journal_get_write_access(handle, bh);
     232       14537 :                 if (err)
     233           0 :                         ext4_journal_abort_handle(where, line, __func__, bh,
     234             :                                                   handle, err);
     235             :         }
     236       14537 :         return err;
     237             : }
     238             : 
     239             : /*
     240             :  * The ext4 forget function must perform a revoke if we are freeing data
     241             :  * which has been journaled.  Metadata (eg. indirect blocks) must be
     242             :  * revoked in all cases.
     243             :  *
     244             :  * "bh" may be NULL: a metadata block may have been freed from memory
     245             :  * but there may still be a record of it in the journal, and that record
     246             :  * still needs to be revoked.
     247             :  *
     248             :  * If the handle isn't valid we're not journaling, but we still need to
     249             :  * call into ext4_journal_revoke() to put the buffer head.
     250             :  */
     251          77 : int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
     252             :                   int is_metadata, struct inode *inode,
     253             :                   struct buffer_head *bh, ext4_fsblk_t blocknr)
     254             : {
     255          77 :         int err;
     256             : 
     257          77 :         might_sleep();
     258             : 
     259          77 :         trace_ext4_forget(inode, is_metadata, blocknr);
     260          77 :         BUFFER_TRACE(bh, "enter");
     261             : 
     262             :         jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, "
     263             :                   "data mode %x\n",
     264             :                   bh, is_metadata, inode->i_mode,
     265          77 :                   test_opt(inode->i_sb, DATA_FLAGS));
     266             : 
     267             :         /* In the no journal case, we can just do a bforget and return */
     268          77 :         if (!ext4_handle_valid(handle)) {
     269           0 :                 bforget(bh);
     270           0 :                 return 0;
     271             :         }
     272             : 
     273             :         /* Never use the revoke function if we are doing full data
     274             :          * journaling: there is no need to, and a V1 superblock won't
     275             :          * support it.  Otherwise, only skip the revoke on un-journaled
     276             :          * data blocks. */
     277             : 
     278          77 :         if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
     279           0 :             (!is_metadata && !ext4_should_journal_data(inode))) {
     280           0 :                 if (bh) {
     281           0 :                         BUFFER_TRACE(bh, "call jbd2_journal_forget");
     282           0 :                         err = jbd2_journal_forget(handle, bh);
     283           0 :                         if (err)
     284           0 :                                 ext4_journal_abort_handle(where, line, __func__,
     285             :                                                           bh, handle, err);
     286           0 :                         return err;
     287             :                 }
     288             :                 return 0;
     289             :         }
     290             : 
     291             :         /*
     292             :          * data!=journal && (is_metadata || should_journal_data(inode))
     293             :          */
     294          77 :         BUFFER_TRACE(bh, "call jbd2_journal_revoke");
     295          77 :         err = jbd2_journal_revoke(handle, blocknr, bh);
     296          77 :         if (err) {
     297           0 :                 ext4_journal_abort_handle(where, line, __func__,
     298             :                                           bh, handle, err);
     299           0 :                 __ext4_error(inode->i_sb, where, line, true, -err, 0,
     300             :                              "error %d when attempting revoke", err);
     301             :         }
     302             :         BUFFER_TRACE(bh, "exit");
     303             :         return err;
     304             : }
     305             : 
     306         175 : int __ext4_journal_get_create_access(const char *where, unsigned int line,
     307             :                                 handle_t *handle, struct buffer_head *bh)
     308             : {
     309         175 :         int err = 0;
     310             : 
     311         175 :         if (ext4_handle_valid(handle)) {
     312         175 :                 err = jbd2_journal_get_create_access(handle, bh);
     313         175 :                 if (err)
     314           0 :                         ext4_journal_abort_handle(where, line, __func__,
     315             :                                                   bh, handle, err);
     316             :         }
     317         175 :         return err;
     318             : }
     319             : 
     320       14708 : int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
     321             :                                  handle_t *handle, struct inode *inode,
     322             :                                  struct buffer_head *bh)
     323             : {
     324       14708 :         int err = 0;
     325             : 
     326       14708 :         might_sleep();
     327             : 
     328       14708 :         set_buffer_meta(bh);
     329       14708 :         set_buffer_prio(bh);
     330       14708 :         if (ext4_handle_valid(handle)) {
     331       14708 :                 err = jbd2_journal_dirty_metadata(handle, bh);
     332             :                 /* Errors can only happen due to aborted journal or a nasty bug */
     333       29416 :                 if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
     334           0 :                         ext4_journal_abort_handle(where, line, __func__, bh,
     335             :                                                   handle, err);
     336           0 :                         if (inode == NULL) {
     337           0 :                                 pr_err("EXT4: jbd2_journal_dirty_metadata "
     338             :                                        "failed: handle type %u started at "
     339             :                                        "line %u, credits %u/%u, errcode %d",
     340             :                                        handle->h_type,
     341             :                                        handle->h_line_no,
     342             :                                        handle->h_requested_credits,
     343             :                                        jbd2_handle_buffer_credits(handle), err);
     344           0 :                                 return err;
     345             :                         }
     346           0 :                         ext4_error_inode(inode, where, line,
     347             :                                          bh->b_blocknr,
     348             :                                          "journal_dirty_metadata failed: "
     349             :                                          "handle type %u started at line %u, "
     350             :                                          "credits %u/%u, errcode %d",
     351             :                                          handle->h_type,
     352             :                                          handle->h_line_no,
     353             :                                          handle->h_requested_credits,
     354             :                                          jbd2_handle_buffer_credits(handle),
     355             :                                          err);
     356             :                 }
     357             :         } else {
     358           0 :                 set_buffer_uptodate(bh);
     359           0 :                 if (inode)
     360           0 :                         mark_buffer_dirty_inode(bh, inode);
     361             :                 else
     362           0 :                         mark_buffer_dirty(bh);
     363           0 :                 if (inode && inode_needs_sync(inode)) {
     364           0 :                         sync_dirty_buffer(bh);
     365           0 :                         if (buffer_req(bh) && !buffer_uptodate(bh)) {
     366           0 :                                 ext4_error_inode_err(inode, where, line,
     367             :                                                      bh->b_blocknr, EIO,
     368             :                                         "IO error syncing itable block");
     369           0 :                                 err = -EIO;
     370             :                         }
     371             :                 }
     372             :         }
     373             :         return err;
     374             : }

Generated by: LCOV version 1.14