summaryrefslogtreecommitdiffstats
path: root/fs/jbd2
diff options
context:
space:
mode:
authorzhangyi (F) <yi.zhang@huawei.com>2019-02-10 23:26:06 -0500
committerTheodore Ts'o <tytso@mit.edu>2019-02-10 23:26:06 -0500
commit597599268e3b91cac71faf48743f4783dec682fc (patch)
tree21b1920d57bef665bf26da39c818aee067948964 /fs/jbd2
parent904cdbd41d749a476863a0ca41f6f396774f26e4 (diff)
jbd2: discard dirty data when forgetting an un-journalled buffer
We do not unmap and clear dirty flag when forgetting a buffer without journal or does not belongs to any transaction, so the invalid dirty data may still be written to the disk later. It's fine if the corresponding block is never used before the next mount, and it's also fine that we invoke clean_bdev_aliases() related functions to unmap the block device mapping when re-allocating such freed block as data block. But this logic is somewhat fragile and risky that may lead to data corruption if we forget to clean bdev aliases. So, It's better to discard dirty data during forget time. We have been already handled all the cases of forgetting journalled buffer, this patch deal with the remaining two cases. - buffer is not journalled yet, - buffer is journalled but doesn't belongs to any transaction. We invoke __bforget() instead of __brelese() when forgetting an un-journalled buffer in jbd2_journal_forget(). After this patch we can remove all clean_bdev_aliases() related calls in ext4. Suggested-by: Jan Kara <jack@suse.cz> Signed-off-by: zhangyi (F) <yi.zhang@huawei.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Reviewed-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/jbd2')
-rw-r--r--fs/jbd2/transaction.c42
1 files changed, 38 insertions, 4 deletions
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 6f4dff182c91..135f0a10f557 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -1597,9 +1597,7 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
1597 __jbd2_journal_unfile_buffer(jh); 1597 __jbd2_journal_unfile_buffer(jh);
1598 if (!buffer_jbd(bh)) { 1598 if (!buffer_jbd(bh)) {
1599 spin_unlock(&journal->j_list_lock); 1599 spin_unlock(&journal->j_list_lock);
1600 jbd_unlock_bh_state(bh); 1600 goto not_jbd;
1601 __bforget(bh);
1602 goto drop;
1603 } 1601 }
1604 } 1602 }
1605 spin_unlock(&journal->j_list_lock); 1603 spin_unlock(&journal->j_list_lock);
@@ -1632,9 +1630,40 @@ int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
1632 if (was_modified) 1630 if (was_modified)
1633 drop_reserve = 1; 1631 drop_reserve = 1;
1634 } 1632 }
1633 } else {
1634 /*
1635 * Finally, if the buffer is not belongs to any
1636 * transaction, we can just drop it now if it has no
1637 * checkpoint.
1638 */
1639 spin_lock(&journal->j_list_lock);
1640 if (!jh->b_cp_transaction) {
1641 JBUFFER_TRACE(jh, "belongs to none transaction");
1642 spin_unlock(&journal->j_list_lock);
1643 goto not_jbd;
1644 }
1645
1646 /*
1647 * Otherwise, if the buffer has been written to disk,
1648 * it is safe to remove the checkpoint and drop it.
1649 */
1650 if (!buffer_dirty(bh)) {
1651 __jbd2_journal_remove_checkpoint(jh);
1652 spin_unlock(&journal->j_list_lock);
1653 goto not_jbd;
1654 }
1655
1656 /*
1657 * The buffer is still not written to disk, we should
1658 * attach this buffer to current transaction so that the
1659 * buffer can be checkpointed only after the current
1660 * transaction commits.
1661 */
1662 clear_buffer_dirty(bh);
1663 __jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
1664 spin_unlock(&journal->j_list_lock);
1635 } 1665 }
1636 1666
1637not_jbd:
1638 jbd_unlock_bh_state(bh); 1667 jbd_unlock_bh_state(bh);
1639 __brelse(bh); 1668 __brelse(bh);
1640drop: 1669drop:
@@ -1643,6 +1672,11 @@ drop:
1643 handle->h_buffer_credits++; 1672 handle->h_buffer_credits++;
1644 } 1673 }
1645 return err; 1674 return err;
1675
1676not_jbd:
1677 jbd_unlock_bh_state(bh);
1678 __bforget(bh);
1679 goto drop;
1646} 1680}
1647 1681
1648/** 1682/**