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        sb = handle->h_transaction->t_journal->j_private;
  91        err = handle->h_err;
  92        rc = jbd2_journal_stop(handle);
  93
  94        if (!err)
  95                err = rc;
  96        if (err)
  97                __ext4_std_error(sb, where, line, err);
  98        return err;
  99}
 100
 101handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
 102                                        int type)
 103{
 104        struct super_block *sb;
 105        int err;
 106
 107        if (!ext4_handle_valid(handle))
 108                return ext4_get_nojournal();
 109
 110        sb = handle->h_journal->j_private;
 111        trace_ext4_journal_start_reserved(sb, handle->h_buffer_credits,
 112                                          _RET_IP_);
 113        err = ext4_journal_check_start(sb);
 114        if (err < 0) {
 115                jbd2_journal_free_reserved(handle);
 116                return ERR_PTR(err);
 117        }
 118
 119        err = jbd2_journal_start_reserved(handle, type, line);
 120        if (err < 0)
 121                return ERR_PTR(err);
 122        return handle;
 123}
 124
 125static void ext4_journal_abort_handle(const char *caller, unsigned int line,
 126                                      const char *err_fn,
 127                                      struct buffer_head *bh,
 128                                      handle_t *handle, int err)
 129{
 130        char nbuf[16];
 131        const char *errstr = ext4_decode_error(NULL, err, nbuf);
 132
 133        BUG_ON(!ext4_handle_valid(handle));
 134
 135        if (bh)
 136                BUFFER_TRACE(bh, "abort");
 137
 138        if (!handle->h_err)
 139                handle->h_err = err;
 140
 141        if (is_handle_aborted(handle))
 142                return;
 143
 144        printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
 145               caller, line, errstr, err_fn);
 146
 147        jbd2_journal_abort_handle(handle);
 148}
 149
 150int __ext4_journal_get_write_access(const char *where, unsigned int line,
 151                                    handle_t *handle, struct buffer_head *bh)
 152{
 153        int err = 0;
 154
 155        might_sleep();
 156
 157        if (ext4_handle_valid(handle)) {
 158                err = jbd2_journal_get_write_access(handle, bh);
 159                if (err)
 160                        ext4_journal_abort_handle(where, line, __func__, bh,
 161                                                  handle, err);
 162        }
 163        return err;
 164}
 165
 166/*
 167 * The ext4 forget function must perform a revoke if we are freeing data
 168 * which has been journaled.  Metadata (eg. indirect blocks) must be
 169 * revoked in all cases.
 170 *
 171 * "bh" may be NULL: a metadata block may have been freed from memory
 172 * but there may still be a record of it in the journal, and that record
 173 * still needs to be revoked.
 174 *
 175 * If the handle isn't valid we're not journaling, but we still need to
 176 * call into ext4_journal_revoke() to put the buffer head.
 177 */
 178int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
 179                  int is_metadata, struct inode *inode,
 180                  struct buffer_head *bh, ext4_fsblk_t blocknr)
 181{
 182        int err;
 183
 184        might_sleep();
 185
 186        trace_ext4_forget(inode, is_metadata, blocknr);
 187        BUFFER_TRACE(bh, "enter");
 188
 189        jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, "
 190                  "data mode %x\n",
 191                  bh, is_metadata, inode->i_mode,
 192                  test_opt(inode->i_sb, DATA_FLAGS));
 193
 194        /* In the no journal case, we can just do a bforget and return */
 195        if (!ext4_handle_valid(handle)) {
 196                bforget(bh);
 197                return 0;
 198        }
 199
 200        /* Never use the revoke function if we are doing full data
 201         * journaling: there is no need to, and a V1 superblock won't
 202         * support it.  Otherwise, only skip the revoke on un-journaled
 203         * data blocks. */
 204
 205        if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
 206            (!is_metadata && !ext4_should_journal_data(inode))) {
 207                if (bh) {
 208                        BUFFER_TRACE(bh, "call jbd2_journal_forget");
 209                        err = jbd2_journal_forget(handle, bh);
 210                        if (err)
 211                                ext4_journal_abort_handle(where, line, __func__,
 212                                                          bh, handle, err);
 213                        return err;
 214                }
 215                return 0;
 216        }
 217
 218        /*
 219         * data!=journal && (is_metadata || should_journal_data(inode))
 220         */
 221        BUFFER_TRACE(bh, "call jbd2_journal_revoke");
 222        err = jbd2_journal_revoke(handle, blocknr, bh);
 223        if (err) {
 224                ext4_journal_abort_handle(where, line, __func__,
 225                                          bh, handle, err);
 226                __ext4_abort(inode->i_sb, where, line,
 227                           "error %d when attempting revoke", err);
 228        }
 229        BUFFER_TRACE(bh, "exit");
 230        return err;
 231}
 232
 233int __ext4_journal_get_create_access(const char *where, unsigned int line,
 234                                handle_t *handle, struct buffer_head *bh)
 235{
 236        int err = 0;
 237
 238        if (ext4_handle_valid(handle)) {
 239                err = jbd2_journal_get_create_access(handle, bh);
 240                if (err)
 241                        ext4_journal_abort_handle(where, line, __func__,
 242                                                  bh, handle, err);
 243        }
 244        return err;
 245}
 246
 247int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
 248                                 handle_t *handle, struct inode *inode,
 249                                 struct buffer_head *bh)
 250{
 251        int err = 0;
 252
 253        might_sleep();
 254
 255        set_buffer_meta(bh);
 256        set_buffer_prio(bh);
 257        if (ext4_handle_valid(handle)) {
 258                err = jbd2_journal_dirty_metadata(handle, bh);
 259                /* Errors can only happen due to aborted journal or a nasty bug */
 260                if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
 261                        ext4_journal_abort_handle(where, line, __func__, bh,
 262                                                  handle, err);
 263                        if (inode == NULL) {
 264                                pr_err("EXT4: jbd2_journal_dirty_metadata "
 265                                       "failed: handle type %u started at "
 266                                       "line %u, credits %u/%u, errcode %d",
 267                                       handle->h_type,
 268                                       handle->h_line_no,
 269                                       handle->h_requested_credits,
 270                                       handle->h_buffer_credits, err);
 271                                return err;
 272                        }
 273                        ext4_error_inode(inode, where, line,
 274                                         bh->b_blocknr,
 275                                         "journal_dirty_metadata failed: "
 276                                         "handle type %u started at line %u, "
 277                                         "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                }
 283        } else {
 284                if (inode)
 285                        mark_buffer_dirty_inode(bh, inode);
 286                else
 287                        mark_buffer_dirty(bh);
 288                if (inode && inode_needs_sync(inode)) {
 289                        sync_dirty_buffer(bh);
 290                        if (buffer_req(bh) && !buffer_uptodate(bh)) {
 291                                struct ext4_super_block *es;
 292
 293                                es = EXT4_SB(inode->i_sb)->s_es;
 294                                es->s_last_error_block =
 295                                        cpu_to_le64(bh->b_blocknr);
 296                                ext4_error_inode(inode, where, line,
 297                                                 bh->b_blocknr,
 298                                        "IO error syncing itable block");
 299                                err = -EIO;
 300                        }
 301                }
 302        }
 303        return err;
 304}
 305
 306int __ext4_handle_dirty_super(const char *where, unsigned int line,
 307                              handle_t *handle, struct super_block *sb)
 308{
 309        struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
 310        int err = 0;
 311
 312        ext4_superblock_csum_set(sb);
 313        if (ext4_handle_valid(handle)) {
 314                err = jbd2_journal_dirty_metadata(handle, bh);
 315                if (err)
 316                        ext4_journal_abort_handle(where, line, __func__,
 317                                                  bh, handle, err);
 318        } else
 319                mark_buffer_dirty(bh);
 320        return err;
 321}
 322