2018-06-06 10:42:14 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2013-08-12 18:49:22 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
|
|
|
* All Rights Reserved.
|
|
|
|
*/
|
|
|
|
#ifndef __XFS_LOG_FORMAT_H__
|
|
|
|
#define __XFS_LOG_FORMAT_H__
|
|
|
|
|
2013-08-12 18:50:01 +08:00
|
|
|
struct xfs_mount;
|
2013-08-12 18:50:02 +08:00
|
|
|
struct xfs_trans_res;
|
2013-08-12 18:50:01 +08:00
|
|
|
|
2013-08-12 18:49:23 +08:00
|
|
|
/*
|
|
|
|
* On-disk Log Format definitions.
|
|
|
|
*
|
|
|
|
* This file contains all the on-disk format definitions used within the log. It
|
|
|
|
* includes the physical log structure itself, as well as all the log item
|
|
|
|
* format structures that are written into the log and intepreted by log
|
|
|
|
* recovery. We start with the physical log format definitions, and then work
|
|
|
|
* through all the log items definitions and everything they encode into the
|
|
|
|
* log.
|
|
|
|
*/
|
2017-06-17 02:00:05 +08:00
|
|
|
typedef uint32_t xlog_tid_t;
|
2013-08-12 18:49:22 +08:00
|
|
|
|
|
|
|
#define XLOG_MIN_ICLOGS 2
|
|
|
|
#define XLOG_MAX_ICLOGS 8
|
|
|
|
#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe /* Invalid cycle number */
|
|
|
|
#define XLOG_VERSION_1 1
|
|
|
|
#define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */
|
|
|
|
#define XLOG_VERSION_OKBITS (XLOG_VERSION_1 | XLOG_VERSION_2)
|
|
|
|
#define XLOG_MIN_RECORD_BSIZE (16*1024) /* eventually 32k */
|
|
|
|
#define XLOG_BIG_RECORD_BSIZE (32*1024) /* 32k buffers */
|
|
|
|
#define XLOG_MAX_RECORD_BSIZE (256*1024)
|
|
|
|
#define XLOG_HEADER_CYCLE_SIZE (32*1024) /* cycle data in header */
|
|
|
|
#define XLOG_MIN_RECORD_BSHIFT 14 /* 16384 == 1 << 14 */
|
|
|
|
#define XLOG_BIG_RECORD_BSHIFT 15 /* 32k == 1 << 15 */
|
|
|
|
#define XLOG_MAX_RECORD_BSHIFT 18 /* 256k == 1 << 18 */
|
|
|
|
|
|
|
|
#define XLOG_HEADER_SIZE 512
|
|
|
|
|
2013-08-12 18:50:02 +08:00
|
|
|
/* Minimum number of transactions that must fit in the log (defined by mkfs) */
|
|
|
|
#define XFS_MIN_LOG_FACTOR 3
|
|
|
|
|
2013-08-12 18:49:22 +08:00
|
|
|
#define XLOG_REC_SHIFT(log) \
|
2021-08-19 09:46:37 +08:00
|
|
|
BTOBB(1 << (xfs_has_logv2(log->l_mp) ? \
|
2013-08-12 18:49:22 +08:00
|
|
|
XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT))
|
|
|
|
#define XLOG_TOTAL_REC_SHIFT(log) \
|
2021-08-19 09:46:37 +08:00
|
|
|
BTOBB(XLOG_MAX_ICLOGS << (xfs_has_logv2(log->l_mp) ? \
|
2013-08-12 18:49:22 +08:00
|
|
|
XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT))
|
|
|
|
|
|
|
|
/* get lsn fields */
|
|
|
|
#define CYCLE_LSN(lsn) ((uint)((lsn)>>32))
|
|
|
|
#define BLOCK_LSN(lsn) ((uint)(lsn))
|
|
|
|
|
|
|
|
/* this is used in a spot where we might otherwise double-endian-flip */
|
|
|
|
#define CYCLE_LSN_DISK(lsn) (((__be32 *)&(lsn))[0])
|
|
|
|
|
|
|
|
static inline xfs_lsn_t xlog_assign_lsn(uint cycle, uint block)
|
|
|
|
{
|
|
|
|
return ((xfs_lsn_t)cycle << 32) | block;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint xlog_get_cycle(char *ptr)
|
|
|
|
{
|
|
|
|
if (be32_to_cpu(*(__be32 *)ptr) == XLOG_HEADER_MAGIC_NUM)
|
|
|
|
return be32_to_cpu(*((__be32 *)ptr + 1));
|
|
|
|
else
|
|
|
|
return be32_to_cpu(*(__be32 *)ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Log Clients */
|
|
|
|
#define XFS_TRANSACTION 0x69
|
|
|
|
#define XFS_VOLUME 0x2
|
|
|
|
#define XFS_LOG 0xaa
|
|
|
|
|
|
|
|
#define XLOG_UNMOUNT_TYPE 0x556e /* Un for Unmount */
|
|
|
|
|
2018-07-21 00:28:39 +08:00
|
|
|
/*
|
|
|
|
* Log item for unmount records.
|
|
|
|
*
|
|
|
|
* The unmount record used to have a string "Unmount filesystem--" in the
|
|
|
|
* data section where the "Un" was really a magic number (XLOG_UNMOUNT_TYPE).
|
|
|
|
* We just write the magic number now; see xfs_log_unmount_write.
|
|
|
|
*/
|
|
|
|
struct xfs_unmount_log_format {
|
|
|
|
uint16_t magic; /* XLOG_UNMOUNT_TYPE */
|
|
|
|
uint16_t pad1;
|
|
|
|
uint32_t pad2; /* may as well make it 64 bits */
|
|
|
|
};
|
|
|
|
|
2013-08-12 18:49:22 +08:00
|
|
|
/* Region types for iovec's i_type */
|
|
|
|
#define XLOG_REG_TYPE_BFORMAT 1
|
|
|
|
#define XLOG_REG_TYPE_BCHUNK 2
|
|
|
|
#define XLOG_REG_TYPE_EFI_FORMAT 3
|
|
|
|
#define XLOG_REG_TYPE_EFD_FORMAT 4
|
|
|
|
#define XLOG_REG_TYPE_IFORMAT 5
|
|
|
|
#define XLOG_REG_TYPE_ICORE 6
|
|
|
|
#define XLOG_REG_TYPE_IEXT 7
|
|
|
|
#define XLOG_REG_TYPE_IBROOT 8
|
|
|
|
#define XLOG_REG_TYPE_ILOCAL 9
|
|
|
|
#define XLOG_REG_TYPE_IATTR_EXT 10
|
|
|
|
#define XLOG_REG_TYPE_IATTR_BROOT 11
|
|
|
|
#define XLOG_REG_TYPE_IATTR_LOCAL 12
|
|
|
|
#define XLOG_REG_TYPE_QFORMAT 13
|
|
|
|
#define XLOG_REG_TYPE_DQUOT 14
|
|
|
|
#define XLOG_REG_TYPE_QUOTAOFF 15
|
|
|
|
#define XLOG_REG_TYPE_LRHEADER 16
|
|
|
|
#define XLOG_REG_TYPE_UNMOUNT 17
|
|
|
|
#define XLOG_REG_TYPE_COMMIT 18
|
|
|
|
#define XLOG_REG_TYPE_TRANSHDR 19
|
|
|
|
#define XLOG_REG_TYPE_ICREATE 20
|
2016-08-03 10:04:45 +08:00
|
|
|
#define XLOG_REG_TYPE_RUI_FORMAT 21
|
|
|
|
#define XLOG_REG_TYPE_RUD_FORMAT 22
|
2016-10-04 00:11:20 +08:00
|
|
|
#define XLOG_REG_TYPE_CUI_FORMAT 23
|
|
|
|
#define XLOG_REG_TYPE_CUD_FORMAT 24
|
2016-10-04 00:11:25 +08:00
|
|
|
#define XLOG_REG_TYPE_BUI_FORMAT 25
|
|
|
|
#define XLOG_REG_TYPE_BUD_FORMAT 26
|
|
|
|
#define XLOG_REG_TYPE_MAX 26
|
2013-08-12 18:49:22 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Flags to log operation header
|
|
|
|
*
|
|
|
|
* The first write of a new transaction will be preceded with a start
|
|
|
|
* record, XLOG_START_TRANS. Once a transaction is committed, a commit
|
|
|
|
* record is written, XLOG_COMMIT_TRANS. If a single region can not fit into
|
|
|
|
* the remainder of the current active in-core log, it is split up into
|
|
|
|
* multiple regions. Each partial region will be marked with a
|
|
|
|
* XLOG_CONTINUE_TRANS until the last one, which gets marked with XLOG_END_TRANS.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#define XLOG_START_TRANS 0x01 /* Start a new transaction */
|
|
|
|
#define XLOG_COMMIT_TRANS 0x02 /* Commit this transaction */
|
|
|
|
#define XLOG_CONTINUE_TRANS 0x04 /* Cont this trans into new region */
|
|
|
|
#define XLOG_WAS_CONT_TRANS 0x08 /* Cont this trans into new region */
|
|
|
|
#define XLOG_END_TRANS 0x10 /* End a continued transaction */
|
|
|
|
#define XLOG_UNMOUNT_TRANS 0x20 /* Unmount a filesystem transaction */
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct xlog_op_header {
|
|
|
|
__be32 oh_tid; /* transaction id of operation : 4 b */
|
|
|
|
__be32 oh_len; /* bytes in data region : 4 b */
|
|
|
|
__u8 oh_clientid; /* who sent me this : 1 b */
|
|
|
|
__u8 oh_flags; /* : 1 b */
|
|
|
|
__u16 oh_res2; /* 32 bit align : 2 b */
|
|
|
|
} xlog_op_header_t;
|
|
|
|
|
|
|
|
/* valid values for h_fmt */
|
|
|
|
#define XLOG_FMT_UNKNOWN 0
|
|
|
|
#define XLOG_FMT_LINUX_LE 1
|
|
|
|
#define XLOG_FMT_LINUX_BE 2
|
|
|
|
#define XLOG_FMT_IRIX_BE 3
|
|
|
|
|
|
|
|
/* our fmt */
|
|
|
|
#ifdef XFS_NATIVE_HOST
|
|
|
|
#define XLOG_FMT XLOG_FMT_LINUX_BE
|
|
|
|
#else
|
|
|
|
#define XLOG_FMT XLOG_FMT_LINUX_LE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef struct xlog_rec_header {
|
|
|
|
__be32 h_magicno; /* log record (LR) identifier : 4 */
|
|
|
|
__be32 h_cycle; /* write cycle of log : 4 */
|
|
|
|
__be32 h_version; /* LR version : 4 */
|
|
|
|
__be32 h_len; /* len in bytes; should be 64-bit aligned: 4 */
|
|
|
|
__be64 h_lsn; /* lsn of this LR : 8 */
|
|
|
|
__be64 h_tail_lsn; /* lsn of 1st LR w/ buffers not committed: 8 */
|
|
|
|
__le32 h_crc; /* crc of log record : 4 */
|
|
|
|
__be32 h_prev_block; /* block number to previous LR : 4 */
|
|
|
|
__be32 h_num_logops; /* number of log operations in this LR : 4 */
|
|
|
|
__be32 h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE];
|
|
|
|
/* new fields */
|
|
|
|
__be32 h_fmt; /* format of log record : 4 */
|
|
|
|
uuid_t h_fs_uuid; /* uuid of FS : 16 */
|
|
|
|
__be32 h_size; /* iclog size : 4 */
|
|
|
|
} xlog_rec_header_t;
|
|
|
|
|
|
|
|
typedef struct xlog_rec_ext_header {
|
|
|
|
__be32 xh_cycle; /* write cycle of log : 4 */
|
|
|
|
__be32 xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */
|
|
|
|
} xlog_rec_ext_header_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Quite misnamed, because this union lays out the actual on-disk log buffer.
|
|
|
|
*/
|
|
|
|
typedef union xlog_in_core2 {
|
|
|
|
xlog_rec_header_t hic_header;
|
|
|
|
xlog_rec_ext_header_t hic_xheader;
|
|
|
|
char hic_sector[XLOG_HEADER_SIZE];
|
|
|
|
} xlog_in_core_2_t;
|
|
|
|
|
|
|
|
/* not an on-disk structure, but needed by log recovery in userspace */
|
|
|
|
typedef struct xfs_log_iovec {
|
|
|
|
void *i_addr; /* beginning address of region */
|
|
|
|
int i_len; /* length in bytes of region */
|
|
|
|
uint i_type; /* type of region */
|
|
|
|
} xfs_log_iovec_t;
|
|
|
|
|
2013-08-12 18:49:23 +08:00
|
|
|
|
2013-08-12 18:49:28 +08:00
|
|
|
/*
|
|
|
|
* Transaction Header definitions.
|
|
|
|
*
|
|
|
|
* This is the structure written in the log at the head of every transaction. It
|
|
|
|
* identifies the type and id of the transaction, and contains the number of
|
|
|
|
* items logged by the transaction so we know how many to expect during
|
|
|
|
* recovery.
|
|
|
|
*
|
|
|
|
* Do not change the below structure without redoing the code in
|
|
|
|
* xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans().
|
|
|
|
*/
|
|
|
|
typedef struct xfs_trans_header {
|
|
|
|
uint th_magic; /* magic number */
|
|
|
|
uint th_type; /* transaction type */
|
2017-06-17 02:00:05 +08:00
|
|
|
int32_t th_tid; /* transaction id (unused) */
|
2013-08-12 18:49:28 +08:00
|
|
|
uint th_num_items; /* num items logged by trans */
|
|
|
|
} xfs_trans_header_t;
|
|
|
|
|
|
|
|
#define XFS_TRANS_HEADER_MAGIC 0x5452414e /* TRAN */
|
|
|
|
|
2016-04-06 07:20:36 +08:00
|
|
|
/*
|
|
|
|
* The only type valid for th_type in CIL-enabled file system logs:
|
|
|
|
*/
|
|
|
|
#define XFS_TRANS_CHECKPOINT 40
|
|
|
|
|
2013-08-12 18:49:28 +08:00
|
|
|
/*
|
|
|
|
* Log item types.
|
|
|
|
*/
|
|
|
|
#define XFS_LI_EFI 0x1236
|
|
|
|
#define XFS_LI_EFD 0x1237
|
|
|
|
#define XFS_LI_IUNLINK 0x1238
|
|
|
|
#define XFS_LI_INODE 0x123b /* aligned ino chunks, var-size ibufs */
|
|
|
|
#define XFS_LI_BUF 0x123c /* v2 bufs, variable sized inode bufs */
|
|
|
|
#define XFS_LI_DQUOT 0x123d
|
|
|
|
#define XFS_LI_QUOTAOFF 0x123e
|
|
|
|
#define XFS_LI_ICREATE 0x123f
|
2016-08-03 10:04:45 +08:00
|
|
|
#define XFS_LI_RUI 0x1240 /* rmap update intent */
|
|
|
|
#define XFS_LI_RUD 0x1241
|
2016-10-04 00:11:20 +08:00
|
|
|
#define XFS_LI_CUI 0x1242 /* refcount update intent */
|
|
|
|
#define XFS_LI_CUD 0x1243
|
2016-10-04 00:11:25 +08:00
|
|
|
#define XFS_LI_BUI 0x1244 /* bmbt update intent */
|
|
|
|
#define XFS_LI_BUD 0x1245
|
2013-08-12 18:49:28 +08:00
|
|
|
|
|
|
|
#define XFS_LI_TYPE_DESC \
|
|
|
|
{ XFS_LI_EFI, "XFS_LI_EFI" }, \
|
|
|
|
{ XFS_LI_EFD, "XFS_LI_EFD" }, \
|
|
|
|
{ XFS_LI_IUNLINK, "XFS_LI_IUNLINK" }, \
|
|
|
|
{ XFS_LI_INODE, "XFS_LI_INODE" }, \
|
|
|
|
{ XFS_LI_BUF, "XFS_LI_BUF" }, \
|
|
|
|
{ XFS_LI_DQUOT, "XFS_LI_DQUOT" }, \
|
|
|
|
{ XFS_LI_QUOTAOFF, "XFS_LI_QUOTAOFF" }, \
|
2016-08-03 10:04:45 +08:00
|
|
|
{ XFS_LI_ICREATE, "XFS_LI_ICREATE" }, \
|
|
|
|
{ XFS_LI_RUI, "XFS_LI_RUI" }, \
|
2016-10-04 00:11:20 +08:00
|
|
|
{ XFS_LI_RUD, "XFS_LI_RUD" }, \
|
|
|
|
{ XFS_LI_CUI, "XFS_LI_CUI" }, \
|
2016-10-04 00:11:25 +08:00
|
|
|
{ XFS_LI_CUD, "XFS_LI_CUD" }, \
|
|
|
|
{ XFS_LI_BUI, "XFS_LI_BUI" }, \
|
|
|
|
{ XFS_LI_BUD, "XFS_LI_BUD" }
|
2013-08-12 18:49:28 +08:00
|
|
|
|
2013-08-12 18:49:23 +08:00
|
|
|
/*
|
|
|
|
* Inode Log Item Format definitions.
|
|
|
|
*
|
|
|
|
* This is the structure used to lay out an inode log item in the
|
|
|
|
* log. The size of the inline data/extents/b-tree root to be logged
|
|
|
|
* (if any) is indicated in the ilf_dsize field. Changes to this structure
|
|
|
|
* must be added on to the end.
|
|
|
|
*/
|
2017-11-01 03:04:24 +08:00
|
|
|
struct xfs_inode_log_format {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t ilf_type; /* inode log item type */
|
|
|
|
uint16_t ilf_size; /* size of this item */
|
|
|
|
uint32_t ilf_fields; /* flags for fields logged */
|
|
|
|
uint16_t ilf_asize; /* size of attr d/ext/root */
|
|
|
|
uint16_t ilf_dsize; /* size of data/ext/root */
|
2017-10-10 02:37:22 +08:00
|
|
|
uint32_t ilf_pad; /* pad for 64 bit boundary */
|
2017-06-17 02:00:05 +08:00
|
|
|
uint64_t ilf_ino; /* inode number */
|
2013-08-12 18:49:23 +08:00
|
|
|
union {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint32_t ilfu_rdev; /* rdev value for dev inode*/
|
2017-11-17 01:20:17 +08:00
|
|
|
uint8_t __pad[16]; /* unused */
|
2013-08-12 18:49:23 +08:00
|
|
|
} ilf_u;
|
2017-06-17 02:00:05 +08:00
|
|
|
int64_t ilf_blkno; /* blkno of inode buffer */
|
|
|
|
int32_t ilf_len; /* len of inode buffer */
|
|
|
|
int32_t ilf_boffset; /* off of inode in buffer */
|
2017-11-01 03:04:24 +08:00
|
|
|
};
|
2013-08-12 18:49:23 +08:00
|
|
|
|
2017-10-10 02:37:22 +08:00
|
|
|
/*
|
|
|
|
* Old 32 bit systems will log in this format without the 64 bit
|
|
|
|
* alignment padding. Recovery will detect this and convert it to the
|
|
|
|
* correct format.
|
|
|
|
*/
|
|
|
|
struct xfs_inode_log_format_32 {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t ilf_type; /* inode log item type */
|
|
|
|
uint16_t ilf_size; /* size of this item */
|
|
|
|
uint32_t ilf_fields; /* flags for fields logged */
|
|
|
|
uint16_t ilf_asize; /* size of attr d/ext/root */
|
|
|
|
uint16_t ilf_dsize; /* size of data/ext/root */
|
|
|
|
uint64_t ilf_ino; /* inode number */
|
2013-08-12 18:49:23 +08:00
|
|
|
union {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint32_t ilfu_rdev; /* rdev value for dev inode*/
|
2017-11-17 01:20:17 +08:00
|
|
|
uint8_t __pad[16]; /* unused */
|
2013-08-12 18:49:23 +08:00
|
|
|
} ilf_u;
|
2017-06-17 02:00:05 +08:00
|
|
|
int64_t ilf_blkno; /* blkno of inode buffer */
|
|
|
|
int32_t ilf_len; /* len of inode buffer */
|
|
|
|
int32_t ilf_boffset; /* off of inode in buffer */
|
2017-10-10 02:37:22 +08:00
|
|
|
} __attribute__((packed));
|
2013-08-12 18:49:23 +08:00
|
|
|
|
2016-02-09 13:54:58 +08:00
|
|
|
|
2013-08-12 18:49:23 +08:00
|
|
|
/*
|
|
|
|
* Flags for xfs_trans_log_inode flags field.
|
|
|
|
*/
|
|
|
|
#define XFS_ILOG_CORE 0x001 /* log standard inode fields */
|
|
|
|
#define XFS_ILOG_DDATA 0x002 /* log i_df.if_data */
|
|
|
|
#define XFS_ILOG_DEXT 0x004 /* log i_df.if_extents */
|
|
|
|
#define XFS_ILOG_DBROOT 0x008 /* log i_df.i_broot */
|
|
|
|
#define XFS_ILOG_DEV 0x010 /* log the dev field */
|
2017-10-20 02:07:09 +08:00
|
|
|
#define XFS_ILOG_UUID 0x020 /* added long ago, but never used */
|
2013-08-12 18:49:23 +08:00
|
|
|
#define XFS_ILOG_ADATA 0x040 /* log i_af.if_data */
|
|
|
|
#define XFS_ILOG_AEXT 0x080 /* log i_af.if_extents */
|
|
|
|
#define XFS_ILOG_ABROOT 0x100 /* log i_af.i_broot */
|
xfs: recovery of swap extents operations for CRC filesystems
This is the recovery side of the btree block owner change operation
performed by swapext on CRC enabled filesystems. We detect that an
owner change is needed by the flag that has been placed on the inode
log format flag field. Because the inode recovery is being replayed
after the buffers that make up the BMBT in the given checkpoint, we
can walk all the buffers and directly modify them when we see the
flag set on an inode.
Because the inode can be relogged and hence present in multiple
chekpoints with the "change owner" flag set, we could do multiple
passes across the inode to do this change. While this isn't optimal,
we can't directly ignore the flag as there may be multiple
independent swap extent operations being replayed on the same inode
in different checkpoints so we can't ignore them.
Further, because the owner change operation uses ordered buffers, we
might have buffers that are newer on disk than the current
checkpoint and so already have the owner changed in them. Hence we
cannot just peek at a buffer in the tree and check that it has the
correct owner and assume that the change was completed.
So, for the moment just brute force the owner change every time we
see an inode with the flag set. Note that we have to be careful here
because the owner of the buffers may point to either the old owner
or the new owner. Currently the verifier can't verify the owner
directly, so there is no failure case here right now. If we verify
the owner exactly in future, then we'll have to take this into
account.
This was tested in terms of normal operation via xfstests - all of
the fsr tests now pass without failure. however, we really need to
modify xfs/227 to stress v3 inodes correctly to ensure we fully
cover this case for v5 filesystems.
In terms of recovery testing, I used a hacked version of xfs_fsr
that held the temp inode open for a few seconds before exiting so
that the filesystem could be shut down with an open owner change
recovery flags set on at least the temp inode. fsr leaves the temp
inode unlinked and in btree format, so this was necessary for the
owner change to be reliably replayed.
logprint confirmed the tmp inode in the log had the correct flag set:
INO: cnt:3 total:3 a:0x69e9e0 len:56 a:0x69ea20 len:176 a:0x69eae0 len:88
INODE: #regs:3 ino:0x44 flags:0x209 dsize:88
^^^^^
0x200 is set, indicating a data fork owner change needed to be
replayed on inode 0x44. A printk in the revoery code confirmed that
the inode change was recovered:
XFS (vdc): Mounting Filesystem
XFS (vdc): Starting recovery (logdev: internal)
recovering owner change ino 0x44
XFS (vdc): Version 5 superblock detected. This kernel L support enabled!
Use of these features in this kernel is at your own risk!
XFS (vdc): Ending recovery (logdev: internal)
The script used to test this was:
$ cat ./recovery-fsr.sh
#!/bin/bash
dev=/dev/vdc
mntpt=/mnt/scratch
testfile=$mntpt/testfile
umount $mntpt
mkfs.xfs -f -m crc=1 $dev
mount $dev $mntpt
chmod 777 $mntpt
for i in `seq 10000 -1 0`; do
xfs_io -f -d -c "pwrite $(($i * 4096)) 4096" $testfile > /dev/null 2>&1
done
xfs_bmap -vp $testfile |head -20
xfs_fsr -d -v $testfile &
sleep 10
/home/dave/src/xfstests-dev/src/godown -f $mntpt
wait
umount $mntpt
xfs_logprint -t $dev |tail -20
time mount $dev $mntpt
xfs_bmap -vp $testfile
umount $mntpt
$
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Mark Tinguely <tinguely@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
2013-08-30 08:23:45 +08:00
|
|
|
#define XFS_ILOG_DOWNER 0x200 /* change the data fork owner on replay */
|
|
|
|
#define XFS_ILOG_AOWNER 0x400 /* change the attr fork owner on replay */
|
2013-08-12 18:49:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The timestamps are dirty, but not necessarily anything else in the inode
|
|
|
|
* core. Unlike the other fields above this one must never make it to disk
|
|
|
|
* in the ilf_fields of the inode_log_format, but is purely store in-memory in
|
|
|
|
* ili_fields in the inode_log_item.
|
|
|
|
*/
|
|
|
|
#define XFS_ILOG_TIMESTAMP 0x4000
|
|
|
|
|
|
|
|
#define XFS_ILOG_NONCORE (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \
|
|
|
|
XFS_ILOG_DBROOT | XFS_ILOG_DEV | \
|
2017-10-20 02:07:09 +08:00
|
|
|
XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
|
|
|
|
XFS_ILOG_ABROOT | XFS_ILOG_DOWNER | \
|
|
|
|
XFS_ILOG_AOWNER)
|
2013-08-12 18:49:23 +08:00
|
|
|
|
|
|
|
#define XFS_ILOG_DFORK (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \
|
|
|
|
XFS_ILOG_DBROOT)
|
|
|
|
|
|
|
|
#define XFS_ILOG_AFORK (XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
|
|
|
|
XFS_ILOG_ABROOT)
|
|
|
|
|
|
|
|
#define XFS_ILOG_ALL (XFS_ILOG_CORE | XFS_ILOG_DDATA | \
|
|
|
|
XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \
|
2017-10-20 02:07:09 +08:00
|
|
|
XFS_ILOG_DEV | XFS_ILOG_ADATA | \
|
|
|
|
XFS_ILOG_AEXT | XFS_ILOG_ABROOT | \
|
|
|
|
XFS_ILOG_TIMESTAMP | XFS_ILOG_DOWNER | \
|
|
|
|
XFS_ILOG_AOWNER)
|
2013-08-12 18:49:23 +08:00
|
|
|
|
|
|
|
static inline int xfs_ilog_fbroot(int w)
|
|
|
|
{
|
|
|
|
return (w == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int xfs_ilog_fext(int w)
|
|
|
|
{
|
|
|
|
return (w == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int xfs_ilog_fdata(int w)
|
|
|
|
{
|
|
|
|
return (w == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Incore version of the on-disk inode core structures. We log this directly
|
|
|
|
* into the journal in host CPU format (for better or worse) and as such
|
|
|
|
* directly mirrors the xfs_dinode structure as it must contain all the same
|
|
|
|
* information.
|
|
|
|
*/
|
2021-04-22 04:48:27 +08:00
|
|
|
typedef uint64_t xfs_log_timestamp_t;
|
2020-08-25 07:01:34 +08:00
|
|
|
|
|
|
|
/* Legacy timestamp encoding format. */
|
2021-04-22 04:48:27 +08:00
|
|
|
struct xfs_log_legacy_timestamp {
|
2017-06-17 02:00:05 +08:00
|
|
|
int32_t t_sec; /* timestamp seconds */
|
|
|
|
int32_t t_nsec; /* timestamp nanoseconds */
|
2020-08-25 07:01:34 +08:00
|
|
|
};
|
2013-08-12 18:49:23 +08:00
|
|
|
|
|
|
|
/*
|
2016-02-09 13:54:58 +08:00
|
|
|
* Define the format of the inode core that is logged. This structure must be
|
|
|
|
* kept identical to struct xfs_dinode except for the endianness annotations.
|
2013-08-12 18:49:23 +08:00
|
|
|
*/
|
2016-02-09 13:54:58 +08:00
|
|
|
struct xfs_log_dinode {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */
|
|
|
|
uint16_t di_mode; /* mode and type of file */
|
|
|
|
int8_t di_version; /* inode version */
|
|
|
|
int8_t di_format; /* format of di_c data */
|
|
|
|
uint8_t di_pad3[2]; /* unused in v2/3 inodes */
|
|
|
|
uint32_t di_uid; /* owner's user id */
|
|
|
|
uint32_t di_gid; /* owner's group id */
|
|
|
|
uint32_t di_nlink; /* number of links to file */
|
|
|
|
uint16_t di_projid_lo; /* lower part of owner's project id */
|
|
|
|
uint16_t di_projid_hi; /* higher part of owner's project id */
|
|
|
|
uint8_t di_pad[6]; /* unused, zeroed space */
|
|
|
|
uint16_t di_flushiter; /* incremented on flush */
|
2021-04-22 04:48:27 +08:00
|
|
|
xfs_log_timestamp_t di_atime; /* time last accessed */
|
|
|
|
xfs_log_timestamp_t di_mtime; /* time last modified */
|
|
|
|
xfs_log_timestamp_t di_ctime; /* time created/inode modified */
|
2013-08-12 18:49:23 +08:00
|
|
|
xfs_fsize_t di_size; /* number of bytes in file */
|
2014-07-30 07:12:05 +08:00
|
|
|
xfs_rfsblock_t di_nblocks; /* # of direct & btree blocks used */
|
2013-08-12 18:49:23 +08:00
|
|
|
xfs_extlen_t di_extsize; /* basic/minimum extent size for file */
|
|
|
|
xfs_extnum_t di_nextents; /* number of extents in data fork */
|
|
|
|
xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/
|
2017-06-17 02:00:05 +08:00
|
|
|
uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */
|
|
|
|
int8_t di_aformat; /* format of attr fork's data */
|
|
|
|
uint32_t di_dmevmask; /* DMIG event mask */
|
|
|
|
uint16_t di_dmstate; /* DMIG state info */
|
|
|
|
uint16_t di_flags; /* random flags, XFS_DIFLAG_... */
|
|
|
|
uint32_t di_gen; /* generation number */
|
2013-08-12 18:49:23 +08:00
|
|
|
|
|
|
|
/* di_next_unlinked is the only non-core field in the old dinode */
|
|
|
|
xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */
|
|
|
|
|
|
|
|
/* start of the extended dinode, writable fields */
|
2017-06-17 02:00:05 +08:00
|
|
|
uint32_t di_crc; /* CRC of the inode */
|
|
|
|
uint64_t di_changecount; /* number of attribute changes */
|
xfs: logging the on disk inode LSN can make it go backwards
When we log an inode, we format the "log inode" core and set an LSN
in that inode core. We do that via xfs_inode_item_format_core(),
which calls:
xfs_inode_to_log_dinode(ip, dic, ip->i_itemp->ili_item.li_lsn);
to format the log inode. It writes the LSN from the inode item into
the log inode, and if recovery decides the inode item needs to be
replayed, it recovers the log inode LSN field and writes it into the
on disk inode LSN field.
Now this might seem like a reasonable thing to do, but it is wrong
on multiple levels. Firstly, if the item is not yet in the AIL,
item->li_lsn is zero. i.e. the first time the inode it is logged and
formatted, the LSN we write into the log inode will be zero. If we
only log it once, recovery will run and can write this zero LSN into
the inode.
This means that the next time the inode is logged and log recovery
runs, it will *always* replay changes to the inode regardless of
whether the inode is newer on disk than the version in the log and
that violates the entire purpose of recording the LSN in the inode
at writeback time (i.e. to stop it going backwards in time on disk
during recovery).
Secondly, if we commit the CIL to the journal so the inode item
moves to the AIL, and then relog the inode, the LSN that gets
stamped into the log inode will be the LSN of the inode's current
location in the AIL, not it's age on disk. And it's not the LSN that
will be associated with the current change. That means when log
recovery replays this inode item, the LSN that ends up on disk is
the LSN for the previous changes in the log, not the current
changes being replayed. IOWs, after recovery the LSN on disk is not
in sync with the LSN of the modifications that were replayed into
the inode. This, again, violates the recovery ordering semantics
that on-disk writeback LSNs provide.
Hence the inode LSN in the log dinode is -always- invalid.
Thirdly, recovery actually has the LSN of the log transaction it is
replaying right at hand - it uses it to determine if it should
replay the inode by comparing it to the on-disk inode's LSN. But it
doesn't use that LSN to stamp the LSN into the inode which will be
written back when the transaction is fully replayed. It uses the one
in the log dinode, which we know is always going to be incorrect.
Looking back at the change history, the inode logging was broken by
commit 93f958f9c41f ("xfs: cull unnecessary icdinode fields") way
back in 2016 by a stupid idiot who thought he knew how this code
worked. i.e. me. That commit replaced an in memory di_lsn field that
was updated only at inode writeback time from the inode item.li_lsn
value - and hence always contained the same LSN that appeared in the
on-disk inode - with a read of the inode item LSN at inode format
time. CLearly these are not the same thing.
Before 93f958f9c41f, the log recovery behaviour was irrelevant,
because the LSN in the log inode always matched the on-disk LSN at
the time the inode was logged, hence recovery of the transaction
would never make the on-disk LSN in the inode go backwards or get
out of sync.
A symptom of the problem is this, caught from a failure of
generic/482. Before log recovery, the inode has been allocated but
never used:
xfs_db> inode 393388
xfs_db> p
core.magic = 0x494e
core.mode = 0
....
v3.crc = 0x99126961 (correct)
v3.change_count = 0
v3.lsn = 0
v3.flags2 = 0
v3.cowextsize = 0
v3.crtime.sec = Thu Jan 1 10:00:00 1970
v3.crtime.nsec = 0
After log recovery:
xfs_db> p
core.magic = 0x494e
core.mode = 020444
....
v3.crc = 0x23e68f23 (correct)
v3.change_count = 2
v3.lsn = 0
v3.flags2 = 0
v3.cowextsize = 0
v3.crtime.sec = Thu Jul 22 17:03:03 2021
v3.crtime.nsec = 751000000
...
You can see that the LSN of the on-disk inode is 0, even though it
clearly has been written to disk. I point out this inode, because
the generic/482 failure occurred because several adjacent inodes in
this specific inode cluster were not replayed correctly and still
appeared to be zero on disk when all the other metadata (inobt,
finobt, directories, etc) indicated they should be allocated and
written back.
The fix for this is two-fold. The first is that we need to either
revert the LSN changes in 93f958f9c41f or stop logging the inode LSN
altogether. If we do the former, log recovery does not need to
change but we add 8 bytes of memory per inode to store what is
largely a write-only inode field. If we do the latter, log recovery
needs to stamp the on-disk inode in the same manner that inode
writeback does.
I prefer the latter, because we shouldn't really be trying to log
and replay changes to the on disk LSN as the on-disk value is the
canonical source of the on-disk version of the inode. It also
matches the way we recover buffer items - we create a buf_log_item
that carries the current recovery transaction LSN that gets stamped
into the buffer by the write verifier when it gets written back
when the transaction is fully recovered.
However, this might break log recovery on older kernels even more,
so I'm going to simply ignore the logged value in recovery and stamp
the on-disk inode with the LSN of the transaction being recovered
that will trigger writeback on transaction recovery completion. This
will ensure that the on-disk inode LSN always reflects the LSN of
the last change that was written to disk, regardless of whether it
comes from log recovery or runtime writeback.
Fixes: 93f958f9c41f ("xfs: cull unnecessary icdinode fields")
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
2021-07-28 07:23:49 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The LSN we write to this field during formatting is not a reflection
|
|
|
|
* of the current on-disk LSN. It should never be used for recovery
|
|
|
|
* sequencing, nor should it be recovered into the on-disk inode at all.
|
|
|
|
* See xlog_recover_inode_commit_pass2() and xfs_log_dinode_to_disk()
|
|
|
|
* for details.
|
|
|
|
*/
|
|
|
|
xfs_lsn_t di_lsn;
|
|
|
|
|
2017-06-17 02:00:05 +08:00
|
|
|
uint64_t di_flags2; /* more random flags */
|
|
|
|
uint32_t di_cowextsize; /* basic cow extent size for file */
|
|
|
|
uint8_t di_pad2[12]; /* more padding for future expansion */
|
2013-08-12 18:49:23 +08:00
|
|
|
|
|
|
|
/* fields only written to during inode creation */
|
2021-04-22 04:48:27 +08:00
|
|
|
xfs_log_timestamp_t di_crtime; /* time created */
|
2013-08-12 18:49:23 +08:00
|
|
|
xfs_ino_t di_ino; /* inode number */
|
|
|
|
uuid_t di_uuid; /* UUID of the filesystem */
|
|
|
|
|
|
|
|
/* structure must be padded to 64 bit alignment */
|
2016-02-09 13:54:58 +08:00
|
|
|
};
|
2013-08-12 18:49:23 +08:00
|
|
|
|
2020-03-18 23:15:10 +08:00
|
|
|
#define xfs_log_dinode_size(mp) \
|
2021-08-19 09:46:55 +08:00
|
|
|
(xfs_has_v3inodes((mp)) ? \
|
2020-03-18 23:15:10 +08:00
|
|
|
sizeof(struct xfs_log_dinode) : \
|
|
|
|
offsetof(struct xfs_log_dinode, di_next_unlinked))
|
2013-08-12 18:49:24 +08:00
|
|
|
|
|
|
|
/*
|
2019-11-08 05:24:52 +08:00
|
|
|
* Buffer Log Format definitions
|
2013-08-12 18:49:24 +08:00
|
|
|
*
|
2019-11-08 05:24:52 +08:00
|
|
|
* These are the physical dirty bitmap definitions for the log format structure.
|
2013-08-12 18:49:24 +08:00
|
|
|
*/
|
|
|
|
#define XFS_BLF_CHUNK 128
|
|
|
|
#define XFS_BLF_SHIFT 7
|
|
|
|
#define BIT_TO_WORD_SHIFT 5
|
|
|
|
#define NBWORD (NBBY * sizeof(unsigned int))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This flag indicates that the buffer contains on disk inodes
|
|
|
|
* and requires special recovery handling.
|
|
|
|
*/
|
|
|
|
#define XFS_BLF_INODE_BUF (1<<0)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This flag indicates that the buffer should not be replayed
|
|
|
|
* during recovery because its blocks are being freed.
|
|
|
|
*/
|
|
|
|
#define XFS_BLF_CANCEL (1<<1)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This flag indicates that the buffer contains on disk
|
|
|
|
* user or group dquots and may require special recovery handling.
|
|
|
|
*/
|
|
|
|
#define XFS_BLF_UDQUOT_BUF (1<<2)
|
|
|
|
#define XFS_BLF_PDQUOT_BUF (1<<3)
|
|
|
|
#define XFS_BLF_GDQUOT_BUF (1<<4)
|
|
|
|
|
|
|
|
/*
|
2020-01-08 08:12:25 +08:00
|
|
|
* This is the structure used to lay out a buf log item in the log. The data
|
|
|
|
* map describes which 128 byte chunks of the buffer have been logged.
|
|
|
|
*
|
|
|
|
* The placement of blf_map_size causes blf_data_map to start at an odd
|
|
|
|
* multiple of sizeof(unsigned int) offset within the struct. Because the data
|
|
|
|
* bitmap size will always be an even number, the end of the data_map (and
|
|
|
|
* therefore the structure) will also be at an odd multiple of sizeof(unsigned
|
|
|
|
* int). Some 64-bit compilers will insert padding at the end of the struct to
|
|
|
|
* ensure 64-bit alignment of blf_blkno, but 32-bit ones will not. Therefore,
|
|
|
|
* XFS_BLF_DATAMAP_SIZE must be an odd number to make the padding explicit and
|
|
|
|
* keep the structure size consistent between 32-bit and 64-bit platforms.
|
2013-08-12 18:49:24 +08:00
|
|
|
*/
|
2020-01-08 08:12:25 +08:00
|
|
|
#define __XFS_BLF_DATAMAP_SIZE ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD)
|
|
|
|
#define XFS_BLF_DATAMAP_SIZE (__XFS_BLF_DATAMAP_SIZE + 1)
|
2013-08-12 18:49:24 +08:00
|
|
|
|
|
|
|
typedef struct xfs_buf_log_format {
|
|
|
|
unsigned short blf_type; /* buf log item type indicator */
|
|
|
|
unsigned short blf_size; /* size of this item */
|
2016-11-08 08:55:48 +08:00
|
|
|
unsigned short blf_flags; /* misc state */
|
|
|
|
unsigned short blf_len; /* number of blocks in this buf */
|
2017-06-17 02:00:05 +08:00
|
|
|
int64_t blf_blkno; /* starting blkno of this buf */
|
2013-08-12 18:49:24 +08:00
|
|
|
unsigned int blf_map_size; /* used size of data bitmap in words */
|
|
|
|
unsigned int blf_data_map[XFS_BLF_DATAMAP_SIZE]; /* dirty bitmap */
|
|
|
|
} xfs_buf_log_format_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* All buffers now need to tell recovery where the magic number
|
|
|
|
* is so that it can verify and calculate the CRCs on the buffer correctly
|
|
|
|
* once the changes have been replayed into the buffer.
|
|
|
|
*
|
|
|
|
* The type value is held in the upper 5 bits of the blf_flags field, which is
|
|
|
|
* an unsigned 16 bit field. Hence we need to shift it 11 bits up and down.
|
|
|
|
*/
|
|
|
|
#define XFS_BLFT_BITS 5
|
|
|
|
#define XFS_BLFT_SHIFT 11
|
|
|
|
#define XFS_BLFT_MASK (((1 << XFS_BLFT_BITS) - 1) << XFS_BLFT_SHIFT)
|
|
|
|
|
|
|
|
enum xfs_blft {
|
|
|
|
XFS_BLFT_UNKNOWN_BUF = 0,
|
|
|
|
XFS_BLFT_UDQUOT_BUF,
|
|
|
|
XFS_BLFT_PDQUOT_BUF,
|
|
|
|
XFS_BLFT_GDQUOT_BUF,
|
|
|
|
XFS_BLFT_BTREE_BUF,
|
|
|
|
XFS_BLFT_AGF_BUF,
|
|
|
|
XFS_BLFT_AGFL_BUF,
|
|
|
|
XFS_BLFT_AGI_BUF,
|
|
|
|
XFS_BLFT_DINO_BUF,
|
|
|
|
XFS_BLFT_SYMLINK_BUF,
|
|
|
|
XFS_BLFT_DIR_BLOCK_BUF,
|
|
|
|
XFS_BLFT_DIR_DATA_BUF,
|
|
|
|
XFS_BLFT_DIR_FREE_BUF,
|
|
|
|
XFS_BLFT_DIR_LEAF1_BUF,
|
|
|
|
XFS_BLFT_DIR_LEAFN_BUF,
|
|
|
|
XFS_BLFT_DA_NODE_BUF,
|
|
|
|
XFS_BLFT_ATTR_LEAF_BUF,
|
|
|
|
XFS_BLFT_ATTR_RMT_BUF,
|
|
|
|
XFS_BLFT_SB_BUF,
|
2016-02-09 13:41:31 +08:00
|
|
|
XFS_BLFT_RTBITMAP_BUF,
|
|
|
|
XFS_BLFT_RTSUMMARY_BUF,
|
2013-08-12 18:49:24 +08:00
|
|
|
XFS_BLFT_MAX_BUF = (1 << XFS_BLFT_BITS),
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
xfs_blft_to_flags(struct xfs_buf_log_format *blf, enum xfs_blft type)
|
|
|
|
{
|
|
|
|
ASSERT(type > XFS_BLFT_UNKNOWN_BUF && type < XFS_BLFT_MAX_BUF);
|
|
|
|
blf->blf_flags &= ~XFS_BLFT_MASK;
|
|
|
|
blf->blf_flags |= ((type << XFS_BLFT_SHIFT) & XFS_BLFT_MASK);
|
|
|
|
}
|
|
|
|
|
2017-06-17 02:00:05 +08:00
|
|
|
static inline uint16_t
|
2013-08-12 18:49:24 +08:00
|
|
|
xfs_blft_from_flags(struct xfs_buf_log_format *blf)
|
|
|
|
{
|
|
|
|
return (blf->blf_flags & XFS_BLFT_MASK) >> XFS_BLFT_SHIFT;
|
|
|
|
}
|
|
|
|
|
2013-08-12 18:49:25 +08:00
|
|
|
/*
|
|
|
|
* EFI/EFD log format definitions
|
|
|
|
*/
|
|
|
|
typedef struct xfs_extent {
|
2014-07-30 07:12:05 +08:00
|
|
|
xfs_fsblock_t ext_start;
|
2013-08-12 18:49:25 +08:00
|
|
|
xfs_extlen_t ext_len;
|
|
|
|
} xfs_extent_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since an xfs_extent_t has types (start:64, len: 32)
|
|
|
|
* there are different alignments on 32 bit and 64 bit kernels.
|
|
|
|
* So we provide the different variants for use by a
|
|
|
|
* conversion routine.
|
|
|
|
*/
|
|
|
|
typedef struct xfs_extent_32 {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint64_t ext_start;
|
|
|
|
uint32_t ext_len;
|
2013-08-12 18:49:25 +08:00
|
|
|
} __attribute__((packed)) xfs_extent_32_t;
|
|
|
|
|
|
|
|
typedef struct xfs_extent_64 {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint64_t ext_start;
|
|
|
|
uint32_t ext_len;
|
|
|
|
uint32_t ext_pad;
|
2013-08-12 18:49:25 +08:00
|
|
|
} xfs_extent_64_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the structure used to lay out an efi log item in the
|
|
|
|
* log. The efi_extents field is a variable size array whose
|
|
|
|
* size is given by efi_nextents.
|
|
|
|
*/
|
|
|
|
typedef struct xfs_efi_log_format {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t efi_type; /* efi log item type */
|
|
|
|
uint16_t efi_size; /* size of this item */
|
|
|
|
uint32_t efi_nextents; /* # extents to free */
|
|
|
|
uint64_t efi_id; /* efi identifier */
|
2013-08-12 18:49:25 +08:00
|
|
|
xfs_extent_t efi_extents[1]; /* array of extents to free */
|
|
|
|
} xfs_efi_log_format_t;
|
|
|
|
|
|
|
|
typedef struct xfs_efi_log_format_32 {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t efi_type; /* efi log item type */
|
|
|
|
uint16_t efi_size; /* size of this item */
|
|
|
|
uint32_t efi_nextents; /* # extents to free */
|
|
|
|
uint64_t efi_id; /* efi identifier */
|
2013-08-12 18:49:25 +08:00
|
|
|
xfs_extent_32_t efi_extents[1]; /* array of extents to free */
|
|
|
|
} __attribute__((packed)) xfs_efi_log_format_32_t;
|
|
|
|
|
|
|
|
typedef struct xfs_efi_log_format_64 {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t efi_type; /* efi log item type */
|
|
|
|
uint16_t efi_size; /* size of this item */
|
|
|
|
uint32_t efi_nextents; /* # extents to free */
|
|
|
|
uint64_t efi_id; /* efi identifier */
|
2013-08-12 18:49:25 +08:00
|
|
|
xfs_extent_64_t efi_extents[1]; /* array of extents to free */
|
|
|
|
} xfs_efi_log_format_64_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the structure used to lay out an efd log item in the
|
|
|
|
* log. The efd_extents array is a variable size array whose
|
|
|
|
* size is given by efd_nextents;
|
|
|
|
*/
|
|
|
|
typedef struct xfs_efd_log_format {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t efd_type; /* efd log item type */
|
|
|
|
uint16_t efd_size; /* size of this item */
|
|
|
|
uint32_t efd_nextents; /* # of extents freed */
|
|
|
|
uint64_t efd_efi_id; /* id of corresponding efi */
|
2013-08-12 18:49:25 +08:00
|
|
|
xfs_extent_t efd_extents[1]; /* array of extents freed */
|
|
|
|
} xfs_efd_log_format_t;
|
|
|
|
|
|
|
|
typedef struct xfs_efd_log_format_32 {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t efd_type; /* efd log item type */
|
|
|
|
uint16_t efd_size; /* size of this item */
|
|
|
|
uint32_t efd_nextents; /* # of extents freed */
|
|
|
|
uint64_t efd_efi_id; /* id of corresponding efi */
|
2013-08-12 18:49:25 +08:00
|
|
|
xfs_extent_32_t efd_extents[1]; /* array of extents freed */
|
|
|
|
} __attribute__((packed)) xfs_efd_log_format_32_t;
|
|
|
|
|
|
|
|
typedef struct xfs_efd_log_format_64 {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t efd_type; /* efd log item type */
|
|
|
|
uint16_t efd_size; /* size of this item */
|
|
|
|
uint32_t efd_nextents; /* # of extents freed */
|
|
|
|
uint64_t efd_efi_id; /* id of corresponding efi */
|
2013-08-12 18:49:25 +08:00
|
|
|
xfs_extent_64_t efd_extents[1]; /* array of extents freed */
|
|
|
|
} xfs_efd_log_format_64_t;
|
|
|
|
|
2016-08-03 10:04:45 +08:00
|
|
|
/*
|
|
|
|
* RUI/RUD (reverse mapping) log format definitions
|
|
|
|
*/
|
|
|
|
struct xfs_map_extent {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint64_t me_owner;
|
|
|
|
uint64_t me_startblock;
|
|
|
|
uint64_t me_startoff;
|
|
|
|
uint32_t me_len;
|
|
|
|
uint32_t me_flags;
|
2016-08-03 10:04:45 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* rmap me_flags: upper bits are flags, lower byte is type code */
|
|
|
|
#define XFS_RMAP_EXTENT_MAP 1
|
2016-10-04 00:11:47 +08:00
|
|
|
#define XFS_RMAP_EXTENT_MAP_SHARED 2
|
2016-08-03 10:04:45 +08:00
|
|
|
#define XFS_RMAP_EXTENT_UNMAP 3
|
2016-10-04 00:11:47 +08:00
|
|
|
#define XFS_RMAP_EXTENT_UNMAP_SHARED 4
|
2016-08-03 10:04:45 +08:00
|
|
|
#define XFS_RMAP_EXTENT_CONVERT 5
|
2016-10-04 00:11:47 +08:00
|
|
|
#define XFS_RMAP_EXTENT_CONVERT_SHARED 6
|
2016-08-03 10:04:45 +08:00
|
|
|
#define XFS_RMAP_EXTENT_ALLOC 7
|
|
|
|
#define XFS_RMAP_EXTENT_FREE 8
|
|
|
|
#define XFS_RMAP_EXTENT_TYPE_MASK 0xFF
|
|
|
|
|
|
|
|
#define XFS_RMAP_EXTENT_ATTR_FORK (1U << 31)
|
|
|
|
#define XFS_RMAP_EXTENT_BMBT_BLOCK (1U << 30)
|
|
|
|
#define XFS_RMAP_EXTENT_UNWRITTEN (1U << 29)
|
|
|
|
|
|
|
|
#define XFS_RMAP_EXTENT_FLAGS (XFS_RMAP_EXTENT_TYPE_MASK | \
|
|
|
|
XFS_RMAP_EXTENT_ATTR_FORK | \
|
|
|
|
XFS_RMAP_EXTENT_BMBT_BLOCK | \
|
|
|
|
XFS_RMAP_EXTENT_UNWRITTEN)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the structure used to lay out an rui log item in the
|
|
|
|
* log. The rui_extents field is a variable size array whose
|
|
|
|
* size is given by rui_nextents.
|
|
|
|
*/
|
|
|
|
struct xfs_rui_log_format {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t rui_type; /* rui log item type */
|
|
|
|
uint16_t rui_size; /* size of this item */
|
|
|
|
uint32_t rui_nextents; /* # extents to free */
|
|
|
|
uint64_t rui_id; /* rui identifier */
|
2016-09-19 08:24:27 +08:00
|
|
|
struct xfs_map_extent rui_extents[]; /* array of extents to rmap */
|
2016-08-03 10:04:45 +08:00
|
|
|
};
|
|
|
|
|
2016-09-19 08:24:27 +08:00
|
|
|
static inline size_t
|
|
|
|
xfs_rui_log_format_sizeof(
|
|
|
|
unsigned int nr)
|
|
|
|
{
|
|
|
|
return sizeof(struct xfs_rui_log_format) +
|
|
|
|
nr * sizeof(struct xfs_map_extent);
|
|
|
|
}
|
|
|
|
|
2016-08-03 10:04:45 +08:00
|
|
|
/*
|
|
|
|
* This is the structure used to lay out an rud log item in the
|
|
|
|
* log. The rud_extents array is a variable size array whose
|
|
|
|
* size is given by rud_nextents;
|
|
|
|
*/
|
|
|
|
struct xfs_rud_log_format {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t rud_type; /* rud log item type */
|
|
|
|
uint16_t rud_size; /* size of this item */
|
|
|
|
uint32_t __pad;
|
|
|
|
uint64_t rud_rui_id; /* id of corresponding rui */
|
2016-08-03 10:04:45 +08:00
|
|
|
};
|
|
|
|
|
2016-10-04 00:11:20 +08:00
|
|
|
/*
|
|
|
|
* CUI/CUD (refcount update) log format definitions
|
|
|
|
*/
|
|
|
|
struct xfs_phys_extent {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint64_t pe_startblock;
|
|
|
|
uint32_t pe_len;
|
|
|
|
uint32_t pe_flags;
|
2016-10-04 00:11:20 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* refcount pe_flags: upper bits are flags, lower byte is type code */
|
|
|
|
/* Type codes are taken directly from enum xfs_refcount_intent_type. */
|
|
|
|
#define XFS_REFCOUNT_EXTENT_TYPE_MASK 0xFF
|
|
|
|
|
|
|
|
#define XFS_REFCOUNT_EXTENT_FLAGS (XFS_REFCOUNT_EXTENT_TYPE_MASK)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the structure used to lay out a cui log item in the
|
|
|
|
* log. The cui_extents field is a variable size array whose
|
|
|
|
* size is given by cui_nextents.
|
|
|
|
*/
|
|
|
|
struct xfs_cui_log_format {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t cui_type; /* cui log item type */
|
|
|
|
uint16_t cui_size; /* size of this item */
|
|
|
|
uint32_t cui_nextents; /* # extents to free */
|
|
|
|
uint64_t cui_id; /* cui identifier */
|
2016-10-04 00:11:20 +08:00
|
|
|
struct xfs_phys_extent cui_extents[]; /* array of extents */
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline size_t
|
|
|
|
xfs_cui_log_format_sizeof(
|
|
|
|
unsigned int nr)
|
|
|
|
{
|
|
|
|
return sizeof(struct xfs_cui_log_format) +
|
|
|
|
nr * sizeof(struct xfs_phys_extent);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the structure used to lay out a cud log item in the
|
|
|
|
* log. The cud_extents array is a variable size array whose
|
|
|
|
* size is given by cud_nextents;
|
|
|
|
*/
|
|
|
|
struct xfs_cud_log_format {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t cud_type; /* cud log item type */
|
|
|
|
uint16_t cud_size; /* size of this item */
|
|
|
|
uint32_t __pad;
|
|
|
|
uint64_t cud_cui_id; /* id of corresponding cui */
|
2016-10-04 00:11:20 +08:00
|
|
|
};
|
|
|
|
|
2016-10-04 00:11:25 +08:00
|
|
|
/*
|
|
|
|
* BUI/BUD (inode block mapping) log format definitions
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* bmbt me_flags: upper bits are flags, lower byte is type code */
|
|
|
|
/* Type codes are taken directly from enum xfs_bmap_intent_type. */
|
|
|
|
#define XFS_BMAP_EXTENT_TYPE_MASK 0xFF
|
|
|
|
|
|
|
|
#define XFS_BMAP_EXTENT_ATTR_FORK (1U << 31)
|
|
|
|
#define XFS_BMAP_EXTENT_UNWRITTEN (1U << 30)
|
|
|
|
|
|
|
|
#define XFS_BMAP_EXTENT_FLAGS (XFS_BMAP_EXTENT_TYPE_MASK | \
|
|
|
|
XFS_BMAP_EXTENT_ATTR_FORK | \
|
|
|
|
XFS_BMAP_EXTENT_UNWRITTEN)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the structure used to lay out an bui log item in the
|
|
|
|
* log. The bui_extents field is a variable size array whose
|
|
|
|
* size is given by bui_nextents.
|
|
|
|
*/
|
|
|
|
struct xfs_bui_log_format {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t bui_type; /* bui log item type */
|
|
|
|
uint16_t bui_size; /* size of this item */
|
|
|
|
uint32_t bui_nextents; /* # extents to free */
|
|
|
|
uint64_t bui_id; /* bui identifier */
|
2016-10-04 00:11:25 +08:00
|
|
|
struct xfs_map_extent bui_extents[]; /* array of extents to bmap */
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline size_t
|
|
|
|
xfs_bui_log_format_sizeof(
|
|
|
|
unsigned int nr)
|
|
|
|
{
|
|
|
|
return sizeof(struct xfs_bui_log_format) +
|
|
|
|
nr * sizeof(struct xfs_map_extent);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the structure used to lay out an bud log item in the
|
|
|
|
* log. The bud_extents array is a variable size array whose
|
|
|
|
* size is given by bud_nextents;
|
|
|
|
*/
|
|
|
|
struct xfs_bud_log_format {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t bud_type; /* bud log item type */
|
|
|
|
uint16_t bud_size; /* size of this item */
|
|
|
|
uint32_t __pad;
|
|
|
|
uint64_t bud_bui_id; /* id of corresponding bui */
|
2016-10-04 00:11:25 +08:00
|
|
|
};
|
|
|
|
|
2013-08-12 18:49:26 +08:00
|
|
|
/*
|
|
|
|
* Dquot Log format definitions.
|
|
|
|
*
|
|
|
|
* The first two fields must be the type and size fitting into
|
|
|
|
* 32 bits : log_recovery code assumes that.
|
|
|
|
*/
|
|
|
|
typedef struct xfs_dq_logformat {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t qlf_type; /* dquot log item type */
|
|
|
|
uint16_t qlf_size; /* size of this item */
|
2013-08-12 18:49:26 +08:00
|
|
|
xfs_dqid_t qlf_id; /* usr/grp/proj id : 32 bits */
|
2017-06-17 02:00:05 +08:00
|
|
|
int64_t qlf_blkno; /* blkno of dquot buffer */
|
|
|
|
int32_t qlf_len; /* len of dquot buffer */
|
|
|
|
uint32_t qlf_boffset; /* off of dquot in buffer */
|
2013-08-12 18:49:26 +08:00
|
|
|
} xfs_dq_logformat_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* log format struct for QUOTAOFF records.
|
|
|
|
* The first two fields must be the type and size fitting into
|
|
|
|
* 32 bits : log_recovery code assumes that.
|
|
|
|
* We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer
|
|
|
|
* to the first and ensures that the first logitem is taken out of the AIL
|
|
|
|
* only when the last one is securely committed.
|
|
|
|
*/
|
|
|
|
typedef struct xfs_qoff_logformat {
|
|
|
|
unsigned short qf_type; /* quotaoff log item type */
|
|
|
|
unsigned short qf_size; /* size of this item */
|
|
|
|
unsigned int qf_flags; /* USR and/or GRP */
|
|
|
|
char qf_pad[12]; /* padding for future */
|
|
|
|
} xfs_qoff_logformat_t;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Disk quotas status in m_qflags, and also sb_qflags. 16 bits.
|
|
|
|
*/
|
|
|
|
#define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */
|
|
|
|
#define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */
|
|
|
|
#define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */
|
|
|
|
#define XFS_PQUOTA_ACCT 0x0008 /* project quota accounting ON */
|
|
|
|
#define XFS_OQUOTA_ENFD 0x0010 /* other (grp/prj) quota limits enforced */
|
|
|
|
#define XFS_OQUOTA_CHKD 0x0020 /* quotacheck run on other (grp/prj) quotas */
|
|
|
|
#define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Conversion to and from the combined OQUOTA flag (if necessary)
|
|
|
|
* is done only in xfs_sb_qflags_to_disk() and xfs_sb_qflags_from_disk()
|
|
|
|
*/
|
|
|
|
#define XFS_GQUOTA_ENFD 0x0080 /* group quota limits enforced */
|
|
|
|
#define XFS_GQUOTA_CHKD 0x0100 /* quotacheck run on group quotas */
|
|
|
|
#define XFS_PQUOTA_ENFD 0x0200 /* project quota limits enforced */
|
|
|
|
#define XFS_PQUOTA_CHKD 0x0400 /* quotacheck run on project quotas */
|
|
|
|
|
|
|
|
#define XFS_ALL_QUOTA_ACCT \
|
|
|
|
(XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
|
|
|
|
#define XFS_ALL_QUOTA_ENFD \
|
|
|
|
(XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_ENFD)
|
|
|
|
#define XFS_ALL_QUOTA_CHKD \
|
|
|
|
(XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD)
|
|
|
|
|
2013-08-30 14:21:21 +08:00
|
|
|
#define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
|
|
|
|
XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
|
|
|
|
XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD|\
|
|
|
|
XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD|\
|
|
|
|
XFS_PQUOTA_CHKD)
|
|
|
|
|
2013-08-12 18:49:27 +08:00
|
|
|
/*
|
|
|
|
* Inode create log item structure
|
|
|
|
*
|
|
|
|
* Log recovery assumes the first two entries are the type and size and they fit
|
|
|
|
* in 32 bits. Also in host order (ugh) so they have to be 32 bit aligned so
|
|
|
|
* decoding can be done correctly.
|
|
|
|
*/
|
|
|
|
struct xfs_icreate_log {
|
2017-06-17 02:00:05 +08:00
|
|
|
uint16_t icl_type; /* type of log format structure */
|
|
|
|
uint16_t icl_size; /* size of log format structure */
|
2013-08-12 18:49:27 +08:00
|
|
|
__be32 icl_ag; /* ag being allocated in */
|
|
|
|
__be32 icl_agbno; /* start block of inode range */
|
|
|
|
__be32 icl_count; /* number of inodes to initialise */
|
|
|
|
__be32 icl_isize; /* size of inodes */
|
|
|
|
__be32 icl_length; /* length of extent to initialise */
|
|
|
|
__be32 icl_gen; /* inode generation number to use */
|
|
|
|
};
|
|
|
|
|
2013-08-12 18:49:22 +08:00
|
|
|
#endif /* __XFS_LOG_FORMAT_H__ */
|