LCOV - code coverage report
Current view: top level - fs/ext4 - ext4_jbd2.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 55 127 43.3 %
Date: 2020-09-30 20:25:01 Functions: 8 12 66.7 %
Branches: 30 88 34.1 %

           Branch data     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                 :            : /* Just increment the non-pointer handle value */
      11                 :          0 : static handle_t *ext4_get_nojournal(void)
      12                 :            : {
      13                 :          0 :         handle_t *handle = current->journal_info;
      14                 :          0 :         unsigned long ref_cnt = (unsigned long)handle;
      15                 :            : 
      16         [ #  # ]:          0 :         BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT);
      17                 :            : 
      18                 :          0 :         ref_cnt++;
      19                 :          0 :         handle = (handle_t *)ref_cnt;
      20                 :            : 
      21                 :          0 :         current->journal_info = handle;
      22                 :          0 :         return handle;
      23                 :            : }
      24                 :            : 
      25                 :            : 
      26                 :            : /* Decrement the non-pointer handle value */
      27                 :          0 : static void ext4_put_nojournal(handle_t *handle)
      28                 :            : {
      29                 :          0 :         unsigned long ref_cnt = (unsigned long)handle;
      30                 :            : 
      31         [ #  # ]:          0 :         BUG_ON(ref_cnt == 0);
      32                 :            : 
      33                 :          0 :         ref_cnt--;
      34                 :          0 :         handle = (handle_t *)ref_cnt;
      35                 :            : 
      36                 :          0 :         current->journal_info = handle;
      37                 :          0 : }
      38                 :            : 
      39                 :            : /*
      40                 :            :  * Wrappers for jbd2_journal_start/end.
      41                 :            :  */
      42                 :    2781178 : static int ext4_journal_check_start(struct super_block *sb)
      43                 :            : {
      44                 :            :         journal_t *journal;
      45                 :            : 
      46                 :    2781178 :         might_sleep();
      47                 :            : 
      48         [ +  + ]:    2781178 :         if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
      49                 :            :                 return -EIO;
      50                 :            : 
      51         [ +  + ]:    2781184 :         if (sb_rdonly(sb))
      52                 :            :                 return -EROFS;
      53         [ -  + ]:    2781182 :         WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
      54                 :    2781180 :         journal = EXT4_SB(sb)->s_journal;
      55                 :            :         /*
      56                 :            :          * Special case here: if the journal has aborted behind our
      57                 :            :          * backs (eg. EIO in the commit thread), then we still need to
      58                 :            :          * take the FS itself readonly cleanly.
      59                 :            :          */
      60   [ +  -  -  + ]:    5562360 :         if (journal && is_journal_aborted(journal)) {
      61                 :          0 :                 ext4_abort(sb, "Detected aborted journal");
      62                 :          0 :                 return -EROFS;
      63                 :            :         }
      64                 :            :         return 0;
      65                 :            : }
      66                 :            : 
      67                 :    2781166 : handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
      68                 :            :                                   int type, int blocks, int rsv_blocks)
      69                 :            : {
      70                 :            :         journal_t *journal;
      71                 :            :         int err;
      72                 :            : 
      73                 :    2781166 :         trace_ext4_journal_start(sb, blocks, rsv_blocks, _RET_IP_);
      74                 :    2781176 :         err = ext4_journal_check_start(sb);
      75         [ -  + ]:    2781170 :         if (err < 0)
      76                 :          0 :                 return ERR_PTR(err);
      77                 :            : 
      78                 :    2781170 :         journal = EXT4_SB(sb)->s_journal;
      79         [ -  + ]:    2781170 :         if (!journal)
      80                 :          0 :                 return ext4_get_nojournal();
      81                 :    2781170 :         return jbd2__journal_start(journal, blocks, rsv_blocks, GFP_NOFS,
      82                 :            :                                    type, line);
      83                 :            : }
      84                 :            : 
      85                 :    2781162 : int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
      86                 :            : {
      87                 :            :         struct super_block *sb;
      88                 :            :         int err;
      89                 :            :         int rc;
      90                 :            : 
      91         [ -  + ]:    2781162 :         if (!ext4_handle_valid(handle)) {
      92                 :          0 :                 ext4_put_nojournal(handle);
      93                 :          0 :                 return 0;
      94                 :            :         }
      95                 :            : 
      96                 :    2781162 :         err = handle->h_err;
      97         [ -  + ]:    2781162 :         if (!handle->h_transaction) {
      98                 :          0 :                 rc = jbd2_journal_stop(handle);
      99         [ #  # ]:          0 :                 return err ? err : rc;
     100                 :            :         }
     101                 :            : 
     102                 :    2781162 :         sb = handle->h_transaction->t_journal->j_private;
     103                 :    2781162 :         rc = jbd2_journal_stop(handle);
     104                 :            : 
     105         [ +  + ]:    2781186 :         if (!err)
     106                 :            :                 err = rc;
     107         [ -  + ]:    2781186 :         if (err)
     108                 :          0 :                 __ext4_std_error(sb, where, line, err);
     109                 :    2781184 :         return err;
     110                 :            : }
     111                 :            : 
     112                 :          0 : handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
     113                 :            :                                         int type)
     114                 :            : {
     115                 :            :         struct super_block *sb;
     116                 :            :         int err;
     117                 :            : 
     118         [ #  # ]:          0 :         if (!ext4_handle_valid(handle))
     119                 :          0 :                 return ext4_get_nojournal();
     120                 :            : 
     121                 :          0 :         sb = handle->h_journal->j_private;
     122                 :          0 :         trace_ext4_journal_start_reserved(sb, handle->h_buffer_credits,
     123                 :          0 :                                           _RET_IP_);
     124                 :          0 :         err = ext4_journal_check_start(sb);
     125         [ #  # ]:          0 :         if (err < 0) {
     126                 :          0 :                 jbd2_journal_free_reserved(handle);
     127                 :          0 :                 return ERR_PTR(err);
     128                 :            :         }
     129                 :            : 
     130                 :          0 :         err = jbd2_journal_start_reserved(handle, type, line);
     131         [ #  # ]:          0 :         if (err < 0)
     132                 :          0 :                 return ERR_PTR(err);
     133                 :            :         return handle;
     134                 :            : }
     135                 :            : 
     136                 :          0 : static void ext4_journal_abort_handle(const char *caller, unsigned int line,
     137                 :            :                                       const char *err_fn,
     138                 :            :                                       struct buffer_head *bh,
     139                 :            :                                       handle_t *handle, int err)
     140                 :            : {
     141                 :            :         char nbuf[16];
     142                 :          0 :         const char *errstr = ext4_decode_error(NULL, err, nbuf);
     143                 :            : 
     144         [ #  # ]:          0 :         BUG_ON(!ext4_handle_valid(handle));
     145                 :            : 
     146                 :            :         if (bh)
     147                 :            :                 BUFFER_TRACE(bh, "abort");
     148                 :            : 
     149         [ #  # ]:          0 :         if (!handle->h_err)
     150                 :          0 :                 handle->h_err = err;
     151                 :            : 
     152         [ #  # ]:          0 :         if (is_handle_aborted(handle))
     153                 :          0 :                 return;
     154                 :            : 
     155                 :          0 :         printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
     156                 :            :                caller, line, errstr, err_fn);
     157                 :            : 
     158                 :            :         jbd2_journal_abort_handle(handle);
     159                 :            : }
     160                 :            : 
     161                 :    4317210 : int __ext4_journal_get_write_access(const char *where, unsigned int line,
     162                 :            :                                     handle_t *handle, struct buffer_head *bh)
     163                 :            : {
     164                 :            :         int err = 0;
     165                 :            : 
     166                 :    4317210 :         might_sleep();
     167                 :            : 
     168         [ +  + ]:    4317210 :         if (ext4_handle_valid(handle)) {
     169                 :    4317202 :                 err = jbd2_journal_get_write_access(handle, bh);
     170         [ -  + ]:    4317200 :                 if (err)
     171                 :          0 :                         ext4_journal_abort_handle(where, line, __func__, bh,
     172                 :            :                                                   handle, err);
     173                 :            :         }
     174                 :    4317208 :         return err;
     175                 :            : }
     176                 :            : 
     177                 :            : /*
     178                 :            :  * The ext4 forget function must perform a revoke if we are freeing data
     179                 :            :  * which has been journaled.  Metadata (eg. indirect blocks) must be
     180                 :            :  * revoked in all cases.
     181                 :            :  *
     182                 :            :  * "bh" may be NULL: a metadata block may have been freed from memory
     183                 :            :  * but there may still be a record of it in the journal, and that record
     184                 :            :  * still needs to be revoked.
     185                 :            :  *
     186                 :            :  * If the handle isn't valid we're not journaling, but we still need to
     187                 :            :  * call into ext4_journal_revoke() to put the buffer head.
     188                 :            :  */
     189                 :       3260 : int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
     190                 :            :                   int is_metadata, struct inode *inode,
     191                 :            :                   struct buffer_head *bh, ext4_fsblk_t blocknr)
     192                 :            : {
     193                 :            :         int err;
     194                 :            : 
     195                 :       3260 :         might_sleep();
     196                 :            : 
     197                 :       3260 :         trace_ext4_forget(inode, is_metadata, blocknr);
     198                 :            :         BUFFER_TRACE(bh, "enter");
     199                 :            : 
     200                 :            :         jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, "
     201                 :            :                   "data mode %x\n",
     202                 :            :                   bh, is_metadata, inode->i_mode,
     203                 :            :                   test_opt(inode->i_sb, DATA_FLAGS));
     204                 :            : 
     205                 :            :         /* In the no journal case, we can just do a bforget and return */
     206         [ -  + ]:       3260 :         if (!ext4_handle_valid(handle)) {
     207                 :            :                 bforget(bh);
     208                 :            :                 return 0;
     209                 :            :         }
     210                 :            : 
     211                 :            :         /* Never use the revoke function if we are doing full data
     212                 :            :          * journaling: there is no need to, and a V1 superblock won't
     213                 :            :          * support it.  Otherwise, only skip the revoke on un-journaled
     214                 :            :          * data blocks. */
     215                 :            : 
     216   [ +  -  -  + ]:       6520 :         if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
     217         [ #  # ]:          0 :             (!is_metadata && !ext4_should_journal_data(inode))) {
     218         [ #  # ]:          0 :                 if (bh) {
     219                 :            :                         BUFFER_TRACE(bh, "call jbd2_journal_forget");
     220                 :          0 :                         err = jbd2_journal_forget(handle, bh);
     221         [ #  # ]:          0 :                         if (err)
     222                 :          0 :                                 ext4_journal_abort_handle(where, line, __func__,
     223                 :            :                                                           bh, handle, err);
     224                 :          0 :                         return err;
     225                 :            :                 }
     226                 :            :                 return 0;
     227                 :            :         }
     228                 :            : 
     229                 :            :         /*
     230                 :            :          * data!=journal && (is_metadata || should_journal_data(inode))
     231                 :            :          */
     232                 :            :         BUFFER_TRACE(bh, "call jbd2_journal_revoke");
     233                 :       3260 :         err = jbd2_journal_revoke(handle, blocknr, bh);
     234         [ -  + ]:       3260 :         if (err) {
     235                 :          0 :                 ext4_journal_abort_handle(where, line, __func__,
     236                 :            :                                           bh, handle, err);
     237                 :          0 :                 __ext4_abort(inode->i_sb, where, line,
     238                 :            :                            "error %d when attempting revoke", err);
     239                 :            :         }
     240                 :            :         BUFFER_TRACE(bh, "exit");
     241                 :       3260 :         return err;
     242                 :            : }
     243                 :            : 
     244                 :      84920 : int __ext4_journal_get_create_access(const char *where, unsigned int line,
     245                 :            :                                 handle_t *handle, struct buffer_head *bh)
     246                 :            : {
     247                 :            :         int err = 0;
     248                 :            : 
     249         [ +  - ]:      84920 :         if (ext4_handle_valid(handle)) {
     250                 :      84920 :                 err = jbd2_journal_get_create_access(handle, bh);
     251         [ -  + ]:      84920 :                 if (err)
     252                 :          0 :                         ext4_journal_abort_handle(where, line, __func__,
     253                 :            :                                                   bh, handle, err);
     254                 :            :         }
     255                 :      84920 :         return err;
     256                 :            : }
     257                 :            : 
     258                 :    4384434 : int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
     259                 :            :                                  handle_t *handle, struct inode *inode,
     260                 :            :                                  struct buffer_head *bh)
     261                 :            : {
     262                 :            :         int err = 0;
     263                 :            : 
     264                 :    4384434 :         might_sleep();
     265                 :            : 
     266                 :            :         set_buffer_meta(bh);
     267                 :            :         set_buffer_prio(bh);
     268         [ +  - ]:    4384410 :         if (ext4_handle_valid(handle)) {
     269                 :    4384410 :                 err = jbd2_journal_dirty_metadata(handle, bh);
     270                 :            :                 /* Errors can only happen due to aborted journal or a nasty bug */
     271   [ +  +  -  +  :    4384420 :                 if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
             #  #  -  + ]
     272                 :          0 :                         ext4_journal_abort_handle(where, line, __func__, bh,
     273                 :            :                                                   handle, err);
     274         [ #  # ]:          0 :                         if (inode == NULL) {
     275                 :          0 :                                 pr_err("EXT4: jbd2_journal_dirty_metadata "
     276                 :            :                                        "failed: handle type %u started at "
     277                 :            :                                        "line %u, credits %u/%u, errcode %d",
     278                 :            :                                        handle->h_type,
     279                 :            :                                        handle->h_line_no,
     280                 :            :                                        handle->h_requested_credits,
     281                 :            :                                        handle->h_buffer_credits, err);
     282                 :          0 :                                 return err;
     283                 :            :                         }
     284                 :          0 :                         ext4_error_inode(inode, where, line,
     285                 :            :                                          bh->b_blocknr,
     286                 :            :                                          "journal_dirty_metadata failed: "
     287                 :            :                                          "handle type %u started at line %u, "
     288                 :            :                                          "credits %u/%u, errcode %d",
     289                 :            :                                          handle->h_type,
     290                 :            :                                          handle->h_line_no,
     291                 :            :                                          handle->h_requested_credits,
     292                 :            :                                          handle->h_buffer_credits, err);
     293                 :            :                 }
     294                 :            :         } else {
     295         [ #  # ]:          0 :                 if (inode)
     296                 :          0 :                         mark_buffer_dirty_inode(bh, inode);
     297                 :            :                 else
     298                 :          0 :                         mark_buffer_dirty(bh);
     299   [ #  #  #  # ]:          0 :                 if (inode && inode_needs_sync(inode)) {
     300                 :          0 :                         sync_dirty_buffer(bh);
     301   [ #  #  #  # ]:          0 :                         if (buffer_req(bh) && !buffer_uptodate(bh)) {
     302                 :            :                                 struct ext4_super_block *es;
     303                 :            : 
     304                 :          0 :                                 es = EXT4_SB(inode->i_sb)->s_es;
     305                 :          0 :                                 es->s_last_error_block =
     306                 :          0 :                                         cpu_to_le64(bh->b_blocknr);
     307                 :          0 :                                 ext4_error_inode(inode, where, line,
     308                 :            :                                                  bh->b_blocknr,
     309                 :            :                                         "IO error syncing itable block");
     310                 :            :                                 err = -EIO;
     311                 :            :                         }
     312                 :            :                 }
     313                 :            :         }
     314                 :    4384400 :         return err;
     315                 :            : }
     316                 :            : 
     317                 :      17430 : int __ext4_handle_dirty_super(const char *where, unsigned int line,
     318                 :            :                               handle_t *handle, struct super_block *sb)
     319                 :            : {
     320                 :      17430 :         struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
     321                 :            :         int err = 0;
     322                 :            : 
     323                 :      17430 :         ext4_superblock_csum_set(sb);
     324         [ +  - ]:      17430 :         if (ext4_handle_valid(handle)) {
     325                 :      17430 :                 err = jbd2_journal_dirty_metadata(handle, bh);
     326         [ -  + ]:      17430 :                 if (err)
     327                 :          0 :                         ext4_journal_abort_handle(where, line, __func__,
     328                 :            :                                                   bh, handle, err);
     329                 :            :         } else
     330                 :          0 :                 mark_buffer_dirty(bh);
     331                 :      17430 :         return err;
     332                 :            : }

Generated by: LCOV version 1.14