root/fs/ext4/ext4_jbd2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ext4_get_nojournal
  2. ext4_put_nojournal
  3. ext4_journal_check_start
  4. __ext4_journal_start_sb
  5. __ext4_journal_stop
  6. __ext4_journal_start_reserved
  7. ext4_journal_abort_handle
  8. __ext4_journal_get_write_access
  9. __ext4_forget
  10. __ext4_journal_get_create_access
  11. __ext4_handle_dirty_metadata
  12. __ext4_handle_dirty_super

   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 static handle_t *ext4_get_nojournal(void)
  12 {
  13         handle_t *handle = current->journal_info;
  14         unsigned long ref_cnt = (unsigned long)handle;
  15 
  16         BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT);
  17 
  18         ref_cnt++;
  19         handle = (handle_t *)ref_cnt;
  20 
  21         current->journal_info = handle;
  22         return handle;
  23 }
  24 
  25 
  26 /* Decrement the non-pointer handle value */
  27 static void ext4_put_nojournal(handle_t *handle)
  28 {
  29         unsigned long ref_cnt = (unsigned long)handle;
  30 
  31         BUG_ON(ref_cnt == 0);
  32 
  33         ref_cnt--;
  34         handle = (handle_t *)ref_cnt;
  35 
  36         current->journal_info = handle;
  37 }
  38 
  39 /*
  40  * Wrappers for jbd2_journal_start/end.
  41  */
  42 static int ext4_journal_check_start(struct super_block *sb)
  43 {
  44         journal_t *journal;
  45 
  46         might_sleep();
  47 
  48         if (unlikely(ext4_forced_shutdown(EXT4_SB(sb))))
  49                 return -EIO;
  50 
  51         if (sb_rdonly(sb))
  52                 return -EROFS;
  53         WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
  54         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         if (journal && is_journal_aborted(journal)) {
  61                 ext4_abort(sb, "Detected aborted journal");
  62                 return -EROFS;
  63         }
  64         return 0;
  65 }
  66 
  67 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         trace_ext4_journal_start(sb, blocks, rsv_blocks, _RET_IP_);
  74         err = ext4_journal_check_start(sb);
  75         if (err < 0)
  76                 return ERR_PTR(err);
  77 
  78         journal = EXT4_SB(sb)->s_journal;
  79         if (!journal)
  80                 return ext4_get_nojournal();
  81         return jbd2__journal_start(journal, blocks, rsv_blocks, GFP_NOFS,
  82                                    type, line);
  83 }
  84 
  85 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         if (!ext4_handle_valid(handle)) {
  92                 ext4_put_nojournal(handle);
  93                 return 0;
  94         }
  95 
  96         err = handle->h_err;
  97         if (!handle->h_transaction) {
  98                 rc = jbd2_journal_stop(handle);
  99                 return err ? err : rc;
 100         }
 101 
 102         sb = handle->h_transaction->t_journal->j_private;
 103         rc = jbd2_journal_stop(handle);
 104 
 105         if (!err)
 106                 err = rc;
 107         if (err)
 108                 __ext4_std_error(sb, where, line, err);
 109         return err;
 110 }
 111 
 112 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         if (!ext4_handle_valid(handle))
 119                 return ext4_get_nojournal();
 120 
 121         sb = handle->h_journal->j_private;
 122         trace_ext4_journal_start_reserved(sb, handle->h_buffer_credits,
 123                                           _RET_IP_);
 124         err = ext4_journal_check_start(sb);
 125         if (err < 0) {
 126                 jbd2_journal_free_reserved(handle);
 127                 return ERR_PTR(err);
 128         }
 129 
 130         err = jbd2_journal_start_reserved(handle, type, line);
 131         if (err < 0)
 132                 return ERR_PTR(err);
 133         return handle;
 134 }
 135 
 136 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         const char *errstr = ext4_decode_error(NULL, err, nbuf);
 143 
 144         BUG_ON(!ext4_handle_valid(handle));
 145 
 146         if (bh)
 147                 BUFFER_TRACE(bh, "abort");
 148 
 149         if (!handle->h_err)
 150                 handle->h_err = err;
 151 
 152         if (is_handle_aborted(handle))
 153                 return;
 154 
 155         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 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         might_sleep();
 167 
 168         if (ext4_handle_valid(handle)) {
 169                 err = jbd2_journal_get_write_access(handle, bh);
 170                 if (err)
 171                         ext4_journal_abort_handle(where, line, __func__, bh,
 172                                                   handle, err);
 173         }
 174         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 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         might_sleep();
 196 
 197         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         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         if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
 217             (!is_metadata && !ext4_should_journal_data(inode))) {
 218                 if (bh) {
 219                         BUFFER_TRACE(bh, "call jbd2_journal_forget");
 220                         err = jbd2_journal_forget(handle, bh);
 221                         if (err)
 222                                 ext4_journal_abort_handle(where, line, __func__,
 223                                                           bh, handle, err);
 224                         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         err = jbd2_journal_revoke(handle, blocknr, bh);
 234         if (err) {
 235                 ext4_journal_abort_handle(where, line, __func__,
 236                                           bh, handle, err);
 237                 __ext4_abort(inode->i_sb, where, line,
 238                            "error %d when attempting revoke", err);
 239         }
 240         BUFFER_TRACE(bh, "exit");
 241         return err;
 242 }
 243 
 244 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         if (ext4_handle_valid(handle)) {
 250                 err = jbd2_journal_get_create_access(handle, bh);
 251                 if (err)
 252                         ext4_journal_abort_handle(where, line, __func__,
 253                                                   bh, handle, err);
 254         }
 255         return err;
 256 }
 257 
 258 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         might_sleep();
 265 
 266         set_buffer_meta(bh);
 267         set_buffer_prio(bh);
 268         if (ext4_handle_valid(handle)) {
 269                 err = jbd2_journal_dirty_metadata(handle, bh);
 270                 /* Errors can only happen due to aborted journal or a nasty bug */
 271                 if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
 272                         ext4_journal_abort_handle(where, line, __func__, bh,
 273                                                   handle, err);
 274                         if (inode == NULL) {
 275                                 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                                 return err;
 283                         }
 284                         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                 if (inode)
 296                         mark_buffer_dirty_inode(bh, inode);
 297                 else
 298                         mark_buffer_dirty(bh);
 299                 if (inode && inode_needs_sync(inode)) {
 300                         sync_dirty_buffer(bh);
 301                         if (buffer_req(bh) && !buffer_uptodate(bh)) {
 302                                 struct ext4_super_block *es;
 303 
 304                                 es = EXT4_SB(inode->i_sb)->s_es;
 305                                 es->s_last_error_block =
 306                                         cpu_to_le64(bh->b_blocknr);
 307                                 ext4_error_inode(inode, where, line,
 308                                                  bh->b_blocknr,
 309                                         "IO error syncing itable block");
 310                                 err = -EIO;
 311                         }
 312                 }
 313         }
 314         return err;
 315 }
 316 
 317 int __ext4_handle_dirty_super(const char *where, unsigned int line,
 318                               handle_t *handle, struct super_block *sb)
 319 {
 320         struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
 321         int err = 0;
 322 
 323         ext4_superblock_csum_set(sb);
 324         if (ext4_handle_valid(handle)) {
 325                 err = jbd2_journal_dirty_metadata(handle, bh);
 326                 if (err)
 327                         ext4_journal_abort_handle(where, line, __func__,
 328                                                   bh, handle, err);
 329         } else
 330                 mark_buffer_dirty(bh);
 331         return err;
 332 }

/* [<][>][^][v][top][bottom][index][help] */