// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * All Rights Reserved. */ #include "xfs.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_bit.h" #include "xfs_mount.h" #include "xfs_trans.h" #include "xfs_buf_item.h" #include "xfs_trans_priv.h" #include "xfs_trace.h" #include "xfs_log.h" #include "xfs_log_priv.h" #include "xfs_log_recover.h" #include "xfs_error.h" #include "xfs_inode.h" #include "xfs_dir2.h" #include "xfs_quota.h" /* * This is the number of entries in the l_buf_cancel_table used during * recovery. */ #define XLOG_BC_TABLE_SIZE … #define XLOG_BUF_CANCEL_BUCKET(log, blkno) … /* * This structure is used during recovery to record the buf log items which * have been canceled and should not be replayed. */ struct xfs_buf_cancel { … }; static struct xfs_buf_cancel * xlog_find_buffer_cancelled( struct xlog *log, xfs_daddr_t blkno, uint len) { … } static bool xlog_add_buffer_cancelled( struct xlog *log, xfs_daddr_t blkno, uint len) { … } /* * Check if there is and entry for blkno, len in the buffer cancel record table. */ bool xlog_is_buffer_cancelled( struct xlog *log, xfs_daddr_t blkno, uint len) { … } /* * Check if there is and entry for blkno, len in the buffer cancel record table, * and decremented the reference count on it if there is one. * * Remove the cancel record once the refcount hits zero, so that if the same * buffer is re-used again after its last cancellation we actually replay the * changes made at that point. */ static bool xlog_put_buffer_cancelled( struct xlog *log, xfs_daddr_t blkno, uint len) { … } /* log buffer item recovery */ /* * Sort buffer items for log recovery. Most buffer items should end up on the * buffer list and are recovered first, with the following exceptions: * * 1. XFS_BLF_CANCEL buffers must be processed last because some log items * might depend on the incor ecancellation record, and replaying a cancelled * buffer item can remove the incore record. * * 2. XFS_BLF_INODE_BUF buffers are handled after most regular items so that * we replay di_next_unlinked only after flushing the inode 'free' state * to the inode buffer. * * See xlog_recover_reorder_trans for more details. */ STATIC enum xlog_recover_reorder xlog_recover_buf_reorder( struct xlog_recover_item *item) { … } STATIC void xlog_recover_buf_ra_pass2( struct xlog *log, struct xlog_recover_item *item) { … } /* * Build up the table of buf cancel records so that we don't replay cancelled * data in the second pass. */ static int xlog_recover_buf_commit_pass1( struct xlog *log, struct xlog_recover_item *item) { … } /* * Validate the recovered buffer is of the correct type and attach the * appropriate buffer operations to them for writeback. Magic numbers are in a * few places: * the first 16 bits of the buffer (inode buffer, dquot buffer), * the first 32 bits of the buffer (most blocks), * inside a struct xfs_da_blkinfo at the start of the buffer. */ static void xlog_recover_validate_buf_type( struct xfs_mount *mp, struct xfs_buf *bp, struct xfs_buf_log_format *buf_f, xfs_lsn_t current_lsn) { … } /* * Perform a 'normal' buffer recovery. Each logged region of the * buffer should be copied over the corresponding region in the * given buffer. The bitmap in the buf log format structure indicates * where to place the logged data. */ STATIC void xlog_recover_do_reg_buffer( struct xfs_mount *mp, struct xlog_recover_item *item, struct xfs_buf *bp, struct xfs_buf_log_format *buf_f, xfs_lsn_t current_lsn) { … } /* * Perform a dquot buffer recovery. * Simple algorithm: if we have found a QUOTAOFF log item of the same type * (ie. USR or GRP), then just toss this buffer away; don't recover it. * Else, treat it as a regular buffer and do recovery. * * Return false if the buffer was tossed and true if we recovered the buffer to * indicate to the caller if the buffer needs writing. */ STATIC bool xlog_recover_do_dquot_buffer( struct xfs_mount *mp, struct xlog *log, struct xlog_recover_item *item, struct xfs_buf *bp, struct xfs_buf_log_format *buf_f) { … } /* * Perform recovery for a buffer full of inodes. In these buffers, the only * data which should be recovered is that which corresponds to the * di_next_unlinked pointers in the on disk inode structures. The rest of the * data for the inodes is always logged through the inodes themselves rather * than the inode buffer and is recovered in xlog_recover_inode_pass2(). * * The only time when buffers full of inodes are fully recovered is when the * buffer is full of newly allocated inodes. In this case the buffer will * not be marked as an inode buffer and so will be sent to * xlog_recover_do_reg_buffer() below during recovery. */ STATIC int xlog_recover_do_inode_buffer( struct xfs_mount *mp, struct xlog_recover_item *item, struct xfs_buf *bp, struct xfs_buf_log_format *buf_f) { … } /* * V5 filesystems know the age of the buffer on disk being recovered. We can * have newer objects on disk than we are replaying, and so for these cases we * don't want to replay the current change as that will make the buffer contents * temporarily invalid on disk. * * The magic number might not match the buffer type we are going to recover * (e.g. reallocated blocks), so we ignore the xfs_buf_log_format flags. Hence * extract the LSN of the existing object in the buffer based on it's current * magic number. If we don't recognise the magic number in the buffer, then * return a LSN of -1 so that the caller knows it was an unrecognised block and * so can recover the buffer. * * Note: we cannot rely solely on magic number matches to determine that the * buffer has a valid LSN - we also need to verify that it belongs to this * filesystem, so we need to extract the object's LSN and compare it to that * which we read from the superblock. If the UUIDs don't match, then we've got a * stale metadata block from an old filesystem instance that we need to recover * over the top of. */ static xfs_lsn_t xlog_recover_get_buf_lsn( struct xfs_mount *mp, struct xfs_buf *bp, struct xfs_buf_log_format *buf_f) { … } /* * This routine replays a modification made to a buffer at runtime. * There are actually two types of buffer, regular and inode, which * are handled differently. Inode buffers are handled differently * in that we only recover a specific set of data from them, namely * the inode di_next_unlinked fields. This is because all other inode * data is actually logged via inode records and any data we replay * here which overlaps that may be stale. * * When meta-data buffers are freed at run time we log a buffer item * with the XFS_BLF_CANCEL bit set to indicate that previous copies * of the buffer in the log should not be replayed at recovery time. * This is so that if the blocks covered by the buffer are reused for * file data before we crash we don't end up replaying old, freed * meta-data into a user's file. * * To handle the cancellation of buffer log items, we make two passes * over the log during recovery. During the first we build a table of * those buffers which have been cancelled, and during the second we * only replay those buffers which do not have corresponding cancel * records in the table. See xlog_recover_buf_pass[1,2] above * for more details on the implementation of the table of cancel records. */ STATIC int xlog_recover_buf_commit_pass2( struct xlog *log, struct list_head *buffer_list, struct xlog_recover_item *item, xfs_lsn_t current_lsn) { … } const struct xlog_recover_item_ops xlog_buf_item_ops = …; #ifdef DEBUG void xlog_check_buf_cancel_table( struct xlog *log) { … } #endif int xlog_alloc_buf_cancel_table( struct xlog *log) { … } void xlog_free_buf_cancel_table( struct xlog *log) { … }