linux/fs/ext4/ext4_jbd2.c
<<
>>
Prefs
   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 */
  11static 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 */
  27static 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 */
  42static 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
  67handle_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
  85int __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
 112handle_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
 136static 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
 161int __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                struct super_block *sb;
 170
 171                sb = handle->h_transaction->t_journal->j_private;
 172                if (unlikely(ext4_forced_shutdown(EXT4_SB(sb)))) {
 173                        jbd2_journal_abort_handle(handle);
 174                        return -EIO;
 175                }
 176                err = jbd2_journal_get_write_access(handle, bh);
 177                if (err)
 178                        ext4_journal_abort_handle(where, line, __func__, bh,
 179                                                  handle, err);
 180        }
 181        return err;
 182}
 183
 184/*
 185 * The ext4 forget function must perform a revoke if we are freeing data
 186 * which has been journaled.  Metadata (eg. indirect blocks) must be
 187 * revoked in all cases.
 188 *
 189 * "bh" may be NULL: a metadata block may have been freed from memory
 190 * but there may still be a record of it in the journal, and that record
 191 * still needs to be revoked.
 192 *
 193 * If the handle isn't valid we're not journaling, but we still need to
 194 * call into ext4_journal_revoke() to put the buffer head.
 195 */
 196int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
 197                  int is_metadata, struct inode *inode,
 198                  struct buffer_head *bh, ext4_fsblk_t blocknr)
 199{
 200        int err;
 201
 202        might_sleep();
 203
 204        trace_ext4_forget(inode, is_metadata, blocknr);
 205        BUFFER_TRACE(bh, "enter");
 206
 207        jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, "
 208                  "data mode %x\n",
 209                  bh, is_metadata, inode->i_mode,
 210                  test_opt(inode->i_sb, DATA_FLAGS));
 211
 212        /* In the no journal case, we can just do a bforget and return */
 213        if (!ext4_handle_valid(handle)) {
 214                bforget(bh);
 215                return 0;
 216        }
 217
 218        /* Never use the revoke function if we are doing full data
 219         * journaling: there is no need to, and a V1 superblock won't
 220         * support it.  Otherwise, only skip the revoke on un-journaled
 221         * data blocks. */
 222
 223        if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
 224            (!is_metadata && !ext4_should_journal_data(inode))) {
 225                if (bh) {
 226                        BUFFER_TRACE(bh, "call jbd2_journal_forget");
 227                        err = jbd2_journal_forget(handle, bh);
 228                        if (err)
 229                                ext4_journal_abort_handle(where, line, __func__,
 230                                                          bh, handle, err);
 231                        return err;
 232                }
 233                return 0;
 234        }
 235
 236        /*
 237         * data!=journal && (is_metadata || should_journal_data(inode))
 238         */
 239        BUFFER_TRACE(bh, "call jbd2_journal_revoke");
 240        err = jbd2_journal_revoke(handle, blocknr, bh);
 241        if (err) {
 242                ext4_journal_abort_handle(where, line, __func__,
 243                                          bh, handle, err);
 244                __ext4_abort(inode->i_sb, where, line,
 245                           "error %d when attempting revoke", err);
 246        }
 247        BUFFER_TRACE(bh, "exit");
 248        return err;
 249}
 250
 251int __ext4_journal_get_create_access(const char *where, unsigned int line,
 252                                handle_t *handle, struct buffer_head *bh)
 253{
 254        int err = 0;
 255
 256        if (ext4_handle_valid(handle)) {
 257                err = jbd2_journal_get_create_access(handle, bh);
 258                if (err)
 259                        ext4_journal_abort_handle(where, line, __func__,
 260                                                  bh, handle, err);
 261        }
 262        return err;
 263}
 264
 265int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
 266                                 handle_t *handle, struct inode *inode,
 267                                 struct buffer_head *bh)
 268{
 269        int err = 0;
 270
 271        might_sleep();
 272
 273        set_buffer_meta(bh);
 274        set_buffer_prio(bh);
 275        if (ext4_handle_valid(handle)) {
 276                err = jbd2_journal_dirty_metadata(handle, bh);
 277                /* Errors can only happen due to aborted journal or a nasty bug */
 278                if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
 279                        ext4_journal_abort_handle(where, line, __func__, bh,
 280                                                  handle, err);
 281                        if (inode == NULL) {
 282                                pr_err("EXT4: jbd2_journal_dirty_metadata "
 283                                       "failed: handle type %u started at "
 284                                       "line %u, credits %u/%u, errcode %d",
 285                                       handle->h_type,
 286                                       handle->h_line_no,
 287                                       handle->h_requested_credits,
 288                                       handle->h_buffer_credits, err);
 289                                return err;
 290                        }
 291                        ext4_error_inode(inode, where, line,
 292                                         bh->b_blocknr,
 293                                         "journal_dirty_metadata failed: "
 294                                         "handle type %u started at line %u, "
 295                                         "credits %u/%u, errcode %d",
 296                                         handle->h_type,
 297                                         handle->h_line_no,
 298                                         handle->h_requested_credits,
 299                                         handle->h_buffer_credits, err);
 300                }
 301        } else {
 302                if (inode)
 303                        mark_buffer_dirty_inode(bh, inode);
 304                else
 305                        mark_buffer_dirty(bh);
 306                if (inode && inode_needs_sync(inode)) {
 307                        sync_dirty_buffer(bh);
 308                        if (buffer_req(bh) && !buffer_uptodate(bh)) {
 309                                struct ext4_super_block *es;
 310
 311                                es = EXT4_SB(inode->i_sb)->s_es;
 312                                es->s_last_error_block =
 313                                        cpu_to_le64(bh->b_blocknr);
 314                                ext4_error_inode(inode, where, line,
 315                                                 bh->b_blocknr,
 316                                        "IO error syncing itable block");
 317                                err = -EIO;
 318                        }
 319                }
 320        }
 321        return err;
 322}
 323
 324int __ext4_handle_dirty_super(const char *where, unsigned int line,
 325                              handle_t *handle, struct super_block *sb)
 326{
 327        struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
 328        int err = 0;
 329
 330        ext4_superblock_csum_set(sb);
 331        if (ext4_handle_valid(handle)) {
 332                err = jbd2_journal_dirty_metadata(handle, bh);
 333                if (err)
 334                        ext4_journal_abort_handle(where, line, __func__,
 335                                                  bh, handle, err);
 336        } else
 337                mark_buffer_dirty(bh);
 338        return err;
 339}
 340