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