| 1 | |
| 2 | |
| 3 | * Interface between ext4 and JBD
|
| 4 |
|
| 5 |
|
| 6 | #include "ext4_jbd2.h"
|
| 7 |
|
| 8 | #include <trace/events/ext4.h>
|
| 9 |
|
| 10 | int ext4_inode_journal_mode(struct inode *inode)
|
| 11 | {
|
| 12 | if (EXT4_JOURNAL(inode) == NULL)
|
| 13 | return EXT4_INODE_WRITEBACK_DATA_MODE;
|
| 14 |
|
| 15 | if (!S_ISREG(inode->i_mode) ||
|
| 16 | ext4_test_inode_flag(inode, EXT4_INODE_EA_INODE) ||
|
| 17 | test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
|
| 18 | (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) &&
|
| 19 | !test_opt(inode->i_sb, DELALLOC))) {
|
| 20 |
|
| 21 | if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode))
|
| 22 | return EXT4_INODE_ORDERED_DATA_MODE;
|
| 23 | return EXT4_INODE_JOURNAL_DATA_MODE;
|
| 24 | }
|
| 25 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
|
| 26 | return EXT4_INODE_ORDERED_DATA_MODE;
|
| 27 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
|
| 28 | return EXT4_INODE_WRITEBACK_DATA_MODE;
|
| 29 | BUG();
|
| 30 | }
|
| 31 |
|
| 32 |
|
| 33 | static handle_t *ext4_get_nojournal(void)
|
| 34 | {
|
| 35 | handle_t *handle = current->journal_info;
|
| 36 |
|
| 37 | BUG_ON(handle && !handle->h_invalid);
|
| 38 |
|
| 39 | if (!handle) {
|
| 40 | handle = jbd2_alloc_handle(GFP_NOFS);
|
| 41 | if (!handle)
|
| 42 | return ERR_PTR(-ENOMEM);
|
| 43 | handle->h_invalid = 1;
|
| 44 | |
| 45 | * This is done by start_this_handle() if journalling
|
| 46 | * is enabled.
|
| 47 |
|
| 48 | handle->saved_alloc_context = memalloc_nofs_save();
|
| 49 | current->journal_info = handle;
|
| 50 | }
|
| 51 | handle->h_ref++;
|
| 52 | return handle;
|
| 53 | }
|
| 54 |
|
| 55 |
|
| 56 |
|
| 57 | static void ext4_put_nojournal(handle_t *handle)
|
| 58 | {
|
| 59 | BUG_ON(handle->h_ref == 0);
|
| 60 |
|
| 61 | handle->h_ref--;
|
| 62 | if (handle->h_ref == 0) {
|
| 63 | memalloc_nofs_restore(handle->saved_alloc_context);
|
| 64 | jbd2_free_handle(handle);
|
| 65 | current->journal_info = NULL;
|
| 66 | }
|
| 67 | }
|
| 68 |
|
| 69 | |
| 70 | * Wrappers for jbd2_journal_start/end.
|
| 71 |
|
| 72 | static int ext4_journal_check_start(struct super_block *sb)
|
| 73 | {
|
| 74 | int ret;
|
| 75 | journal_t *journal;
|
| 76 |
|
| 77 | might_sleep();
|
| 78 |
|
| 79 | ret = ext4_emergency_state(sb);
|
| 80 | if (unlikely(ret))
|
| 81 | return ret;
|
| 82 |
|
| 83 | if (WARN_ON_ONCE(sb_rdonly(sb)))
|
| 84 | return -EROFS;
|
| 85 |
|
| 86 | WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
|
| 87 | journal = EXT4_SB(sb)->s_journal;
|
| 88 | |
| 89 | * Special case here: if the journal has aborted behind our
|
| 90 | * backs (eg. EIO in the commit thread), then we still need to
|
| 91 | * take the FS itself readonly cleanly.
|
| 92 |
|
| 93 | if (journal && is_journal_aborted(journal)) {
|
| 94 | ext4_abort(sb, -journal->j_errno, "Detected aborted journal");
|
| 95 | return -EROFS;
|
| 96 | }
|
| 97 | return 0;
|
| 98 | }
|
| 99 |
|
| 100 | handle_t *__ext4_journal_start_sb(struct inode *inode,
|
| 101 | struct super_block *sb, unsigned int line,
|
| 102 | int type, int blocks, int rsv_blocks,
|
| 103 | int revoke_creds)
|
| 104 | {
|
| 105 | journal_t *journal;
|
| 106 | int err;
|
| 107 | if (inode)
|
| 108 | trace_ext4_journal_start_inode(inode, blocks, rsv_blocks,
|
| 109 | revoke_creds, type,
|
| 110 | _RET_IP_);
|
| 111 | else
|
| 112 | trace_ext4_journal_start_sb(sb, blocks, rsv_blocks,
|
| 113 | revoke_creds, type,
|
| 114 | _RET_IP_);
|
| 115 | err = ext4_journal_check_start(sb);
|
| 116 | if (err < 0)
|
| 117 | return ERR_PTR(err);
|
| 118 |
|
| 119 | journal = EXT4_SB(sb)->s_journal;
|
| 120 | if (!journal || (EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY))
|
| 121 | return ext4_get_nojournal();
|
| 122 | return jbd2__journal_start(journal, blocks, rsv_blocks, revoke_creds,
|
| 123 | GFP_NOFS, type, line);
|
| 124 | }
|
| 125 |
|
| 126 | int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
|
| 127 | {
|
| 128 | struct super_block *sb;
|
| 129 | int err;
|
| 130 | int rc;
|
| 131 |
|
| 132 | if (!ext4_handle_valid(handle)) {
|
| 133 | ext4_put_nojournal(handle);
|
| 134 | return 0;
|
| 135 | }
|
| 136 |
|
| 137 | err = handle->h_err;
|
| 138 | if (!handle->h_transaction) {
|
| 139 | rc = jbd2_journal_stop(handle);
|
| 140 | return err ? err : rc;
|
| 141 | }
|
| 142 |
|
| 143 | sb = handle->h_transaction->t_journal->j_private;
|
| 144 | rc = jbd2_journal_stop(handle);
|
| 145 |
|
| 146 | if (!err)
|
| 147 | err = rc;
|
| 148 | if (err)
|
| 149 | __ext4_std_error(sb, where, line, err);
|
| 150 | return err;
|
| 151 | }
|
| 152 |
|
| 153 | handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
|
| 154 | int type)
|
| 155 | {
|
| 156 | struct super_block *sb;
|
| 157 | int err;
|
| 158 |
|
| 159 | if (!ext4_handle_valid(handle))
|
| 160 | return ext4_get_nojournal();
|
| 161 |
|
| 162 | sb = handle->h_journal->j_private;
|
| 163 | trace_ext4_journal_start_reserved(sb,
|
| 164 | jbd2_handle_buffer_credits(handle), _RET_IP_);
|
| 165 | err = ext4_journal_check_start(sb);
|
| 166 | if (err < 0) {
|
| 167 | jbd2_journal_free_reserved(handle);
|
| 168 | return ERR_PTR(err);
|
| 169 | }
|
| 170 |
|
| 171 | err = jbd2_journal_start_reserved(handle, type, line);
|
| 172 | if (err < 0)
|
| 173 | return ERR_PTR(err);
|
| 174 | return handle;
|
| 175 | }
|
| 176 |
|
| 177 | int __ext4_journal_ensure_credits(handle_t *handle, int check_cred,
|
| 178 | int extend_cred, int revoke_cred)
|
| 179 | {
|
| 180 | if (!ext4_handle_valid(handle))
|
| 181 | return 0;
|
| 182 | if (is_handle_aborted(handle))
|
| 183 | return -EROFS;
|
| 184 | if (jbd2_handle_buffer_credits(handle) >= check_cred &&
|
| 185 | handle->h_revoke_credits >= revoke_cred)
|
| 186 | return 0;
|
| 187 | extend_cred = max(0, extend_cred - jbd2_handle_buffer_credits(handle));
|
| 188 | revoke_cred = max(0, revoke_cred - handle->h_revoke_credits);
|
| 189 | return ext4_journal_extend(handle, extend_cred, revoke_cred);
|
| 190 | }
|
| 191 |
|
| 192 | static void ext4_journal_abort_handle(const char *caller, unsigned int line,
|
| 193 | const char *err_fn,
|
| 194 | struct buffer_head *bh,
|
| 195 | handle_t *handle, int err)
|
| 196 | {
|
| 197 | char nbuf[16];
|
| 198 | const char *errstr = ext4_decode_error(NULL, err, nbuf);
|
| 199 |
|
| 200 | BUG_ON(!ext4_handle_valid(handle));
|
| 201 |
|
| 202 | if (bh)
|
| 203 | BUFFER_TRACE(bh, "abort");
|
| 204 |
|
| 205 | if (!handle->h_err)
|
| 206 | handle->h_err = err;
|
| 207 |
|
| 208 | if (is_handle_aborted(handle))
|
| 209 | return;
|
| 210 |
|
| 211 | printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
|
| 212 | caller, line, errstr, err_fn);
|
| 213 |
|
| 214 | jbd2_journal_abort_handle(handle);
|
| 215 | }
|
| 216 |
|
| 217 | static void ext4_check_bdev_write_error(struct super_block *sb)
|
| 218 | {
|
| 219 | struct address_space *mapping = sb->s_bdev->bd_mapping;
|
| 220 | struct ext4_sb_info *sbi = EXT4_SB(sb);
|
| 221 | int err;
|
| 222 |
|
| 223 | |
| 224 | * If the block device has write error flag, it may have failed to
|
| 225 | * async write out metadata buffers in the background. In this case,
|
| 226 | * we could read old data from disk and write it out again, which
|
| 227 | * may lead to on-disk filesystem inconsistency.
|
| 228 |
|
| 229 | if (errseq_check(&mapping->wb_err, READ_ONCE(sbi->s_bdev_wb_err))) {
|
| 230 | spin_lock(&sbi->s_bdev_wb_lock);
|
| 231 | err = errseq_check_and_advance(&mapping->wb_err, &sbi->s_bdev_wb_err);
|
| 232 | spin_unlock(&sbi->s_bdev_wb_lock);
|
| 233 | if (err)
|
| 234 | ext4_error_err(sb, -err,
|
| 235 | "Error while async write back metadata");
|
| 236 | }
|
| 237 | }
|
| 238 |
|
| 239 | int __ext4_journal_get_write_access(const char *where, unsigned int line,
|
| 240 | handle_t *handle, struct super_block *sb,
|
| 241 | struct buffer_head *bh,
|
| 242 | enum ext4_journal_trigger_type trigger_type)
|
| 243 | {
|
| 244 | int err;
|
| 245 |
|
| 246 | might_sleep();
|
| 247 |
|
| 248 | if (ext4_handle_valid(handle)) {
|
| 249 | err = jbd2_journal_get_write_access(handle, bh);
|
| 250 | if (err) {
|
| 251 | ext4_journal_abort_handle(where, line, __func__, bh,
|
| 252 | handle, err);
|
| 253 | return err;
|
| 254 | }
|
| 255 | } else
|
| 256 | ext4_check_bdev_write_error(sb);
|
| 257 | if (trigger_type == EXT4_JTR_NONE ||
|
| 258 | !ext4_has_feature_metadata_csum(sb))
|
| 259 | return 0;
|
| 260 | BUG_ON(trigger_type >= EXT4_JOURNAL_TRIGGER_COUNT);
|
| 261 | jbd2_journal_set_triggers(bh,
|
| 262 | &EXT4_SB(sb)->s_journal_triggers[trigger_type].tr_triggers);
|
| 263 | return 0;
|
| 264 | }
|
| 265 |
|
| 266 | |
| 267 | * The ext4 forget function must perform a revoke if we are freeing data
|
| 268 | * which has been journaled. Metadata (eg. indirect blocks) must be
|
| 269 | * revoked in all cases.
|
| 270 | *
|
| 271 | * "bh" may be NULL: a metadata block may have been freed from memory
|
| 272 | * but there may still be a record of it in the journal, and that record
|
| 273 | * still needs to be revoked.
|
| 274 |
|
| 275 | int __ext4_forget(const char *where, unsigned int line, handle_t *handle,
|
| 276 | int is_metadata, struct inode *inode,
|
| 277 | struct buffer_head *bh, ext4_fsblk_t blocknr)
|
| 278 | {
|
| 279 | int err;
|
| 280 |
|
| 281 | might_sleep();
|
| 282 |
|
| 283 | trace_ext4_forget(inode, is_metadata, blocknr);
|
| 284 | BUFFER_TRACE(bh, "enter");
|
| 285 |
|
| 286 | ext4_debug("forgetting bh %p: is_metadata=%d, mode %o, data mode %x\n",
|
| 287 | bh, is_metadata, inode->i_mode,
|
| 288 | test_opt(inode->i_sb, DATA_FLAGS));
|
| 289 |
|
| 290 | |
| 291 | * In the no journal case, we should wait for the ongoing buffer
|
| 292 | * to complete and do a forget.
|
| 293 |
|
| 294 | if (!ext4_handle_valid(handle)) {
|
| 295 | if (bh) {
|
| 296 | clear_buffer_dirty(bh);
|
| 297 | wait_on_buffer(bh);
|
| 298 | __bforget(bh);
|
| 299 | }
|
| 300 | return 0;
|
| 301 | }
|
| 302 |
|
| 303 | |
| 304 | * journaling: there is no need to, and a V1 superblock won't
|
| 305 | * support it. Otherwise, only skip the revoke on un-journaled
|
| 306 | * data blocks.
|
| 307 |
|
| 308 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
|
| 309 | (!is_metadata && !ext4_should_journal_data(inode))) {
|
| 310 | if (bh) {
|
| 311 | BUFFER_TRACE(bh, "call jbd2_journal_forget");
|
| 312 | err = jbd2_journal_forget(handle, bh);
|
| 313 | if (err)
|
| 314 | ext4_journal_abort_handle(where, line, __func__,
|
| 315 | bh, handle, err);
|
| 316 | return err;
|
| 317 | }
|
| 318 | return 0;
|
| 319 | }
|
| 320 |
|
| 321 | |
| 322 | * data!=journal && (is_metadata || should_journal_data(inode))
|
| 323 |
|
| 324 | BUFFER_TRACE(bh, "call jbd2_journal_revoke");
|
| 325 | err = jbd2_journal_revoke(handle, blocknr, bh);
|
| 326 | if (err) {
|
| 327 | ext4_journal_abort_handle(where, line, __func__,
|
| 328 | bh, handle, err);
|
| 329 | __ext4_error(inode->i_sb, where, line, true, -err, 0,
|
| 330 | "error %d when attempting revoke", err);
|
| 331 | }
|
| 332 | BUFFER_TRACE(bh, "exit");
|
| 333 | return err;
|
| 334 | }
|
| 335 |
|
| 336 | int __ext4_journal_get_create_access(const char *where, unsigned int line,
|
| 337 | handle_t *handle, struct super_block *sb,
|
| 338 | struct buffer_head *bh,
|
| 339 | enum ext4_journal_trigger_type trigger_type)
|
| 340 | {
|
| 341 | int err;
|
| 342 |
|
| 343 | if (!ext4_handle_valid(handle))
|
| 344 | return 0;
|
| 345 |
|
| 346 | err = jbd2_journal_get_create_access(handle, bh);
|
| 347 | if (err) {
|
| 348 | ext4_journal_abort_handle(where, line, __func__, bh, handle,
|
| 349 | err);
|
| 350 | return err;
|
| 351 | }
|
| 352 | if (trigger_type == EXT4_JTR_NONE ||
|
| 353 | !ext4_has_feature_metadata_csum(sb))
|
| 354 | return 0;
|
| 355 | BUG_ON(trigger_type >= EXT4_JOURNAL_TRIGGER_COUNT);
|
| 356 | jbd2_journal_set_triggers(bh,
|
| 357 | &EXT4_SB(sb)->s_journal_triggers[trigger_type].tr_triggers);
|
| 358 | return 0;
|
| 359 | }
|
| 360 |
|
| 361 | static void ext4_inode_attach_mmb(struct inode *inode)
|
| 362 | {
|
| 363 | struct mapping_metadata_bhs *mmb;
|
| 364 |
|
| 365 | |
| 366 | * It's difficult to handle failure when marking buffer dirty without
|
| 367 | * leaving filesystem corrupted
|
| 368 |
|
| 369 | mmb = kmalloc_obj(*mmb, GFP_NOFS | __GFP_NOFAIL | __GFP_ACCOUNT);
|
| 370 | mmb_init(mmb, &inode->i_data);
|
| 371 |
|
| 372 | if (cmpxchg(&EXT4_I(inode)->i_metadata_bhs, NULL, mmb))
|
| 373 | kfree(mmb);
|
| 374 | }
|
| 375 |
|
| 376 | int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
|
| 377 | handle_t *handle, struct inode *inode,
|
| 378 | struct buffer_head *bh)
|
| 379 | {
|
| 380 | int err = 0;
|
| 381 |
|
| 382 | might_sleep();
|
| 383 |
|
| 384 | set_buffer_meta(bh);
|
| 385 | set_buffer_prio(bh);
|
| 386 | set_buffer_uptodate(bh);
|
| 387 | if (ext4_handle_valid(handle)) {
|
| 388 | err = jbd2_journal_dirty_metadata(handle, bh);
|
| 389 |
|
| 390 | if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) {
|
| 391 | ext4_journal_abort_handle(where, line, __func__, bh,
|
| 392 | handle, err);
|
| 393 | if (inode == NULL) {
|
| 394 | pr_err("EXT4: jbd2_journal_dirty_metadata "
|
| 395 | "failed: handle type %u started at "
|
| 396 | "line %u, credits %u/%u, errcode %d",
|
| 397 | handle->h_type,
|
| 398 | handle->h_line_no,
|
| 399 | handle->h_requested_credits,
|
| 400 | jbd2_handle_buffer_credits(handle), err);
|
| 401 | return err;
|
| 402 | }
|
| 403 | ext4_error_inode(inode, where, line,
|
| 404 | bh->b_blocknr,
|
| 405 | "journal_dirty_metadata failed: "
|
| 406 | "handle type %u started at line %u, "
|
| 407 | "credits %u/%u, errcode %d",
|
| 408 | handle->h_type,
|
| 409 | handle->h_line_no,
|
| 410 | handle->h_requested_credits,
|
| 411 | jbd2_handle_buffer_credits(handle),
|
| 412 | err);
|
| 413 | }
|
| 414 | } else {
|
| 415 | if (inode) {
|
| 416 | if (!ext4_i_metadata_bhs(inode))
|
| 417 | ext4_inode_attach_mmb(inode);
|
| 418 | mmb_mark_buffer_dirty(bh, ext4_i_metadata_bhs(inode));
|
| 419 | } else {
|
| 420 | mark_buffer_dirty(bh);
|
| 421 | }
|
| 422 | if (inode && inode_needs_sync(inode)) {
|
| 423 | sync_dirty_buffer(bh);
|
| 424 | if (buffer_write_io_error(bh)) {
|
| 425 | ext4_error_inode_err(inode, where, line,
|
| 426 | bh->b_blocknr, EIO,
|
| 427 | "IO error syncing itable block");
|
| 428 | err = -EIO;
|
| 429 | }
|
| 430 | }
|
| 431 | }
|
| 432 | return err;
|
| 433 | }
|