LCOV - code coverage report
Current view: top level - fs/ext4 - ext4_jbd2.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 93 162 57.4 %
Date: 2022-03-28 16:04:14 Functions: 11 11 100.0 %
Branches: 46 132 34.8 %

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

Generated by: LCOV version 1.14