structures

file: /proc/sys/kernel/structures
variable: kernel.structures
Official reference

A typical on-disk structure needs to contain the following information::

struct xfs_ondisk_hdr {
    __be32  magic;		/* magic number */
    __be32  crc;		/* CRC, not logged */
    uuid_t  uuid;		/* filesystem identifier */
    __be64  owner;		/* parent object */
    __be64  blkno;		/* location on disk */
    __be64  lsn;		/* last modification in log, not logged */
};

Depending on the metadata, this information may be part of a header structure separate to the metadata contents, or may be distributed through an existing structure. The latter occurs with metadata that already contains some of this information, such as the superblock and AG headers.

Other metadata may have different formats for the information, but the same level of information is generally provided. For example:

- short btree blocks have a 32 bit owner (ag number) and a 32 bit block
  number for location. The two of these combined provide the same
  information as @owner and @blkno in eh above structure, but using 8
  bytes less space on disk.

- directory/attribute node blocks have a 16 bit magic number, and the
  header that contains the magic number has other information in it as
  well. hence the additional metadata headers change the overall format
  of the metadata.

A typical buffer read verifier is structured as follows::

#define XFS_FOO_CRC_OFF		offsetof(struct xfs_ondisk_hdr, crc)

static void
xfs_foo_read_verify(
    struct xfs_buf	*bp)
{
struct xfs_mount *mp = bp->b_mount;

    if ((xfs_sb_version_hascrc(&mp->m_sb) &&
	!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
				    XFS_FOO_CRC_OFF)) ||
	!xfs_foo_verify(bp)) {
	    XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
	    xfs_buf_ioerror(bp, EFSCORRUPTED);
    }
}

The code ensures that the CRC is only checked if the filesystem has CRCs enabled by checking the superblock of the feature bit, and then if the CRC verifies OK (or is not needed) it verifies the actual contents of the block.

The verifier function will take a couple of different forms, depending on whether the magic number can be used to determine the format of the block. In the case it can’t, the code is structured as follows::

static bool
xfs_foo_verify(
    struct xfs_buf		*bp)
{
    struct xfs_mount	*mp = bp->b_mount;
    struct xfs_ondisk_hdr	*hdr = bp->b_addr;

    if (hdr->magic != cpu_to_be32(XFS_FOO_MAGIC))
	    return false;

    if (!xfs_sb_version_hascrc(&mp->m_sb)) {
	    if (!uuid_equal(&hdr->uuid, &mp->m_sb.sb_uuid))
		    return false;
	    if (bp->b_bn != be64_to_cpu(hdr->blkno))
		    return false;
	    if (hdr->owner == 0)
		    return false;
    }

    /* object specific verification checks here */

    return true;
}

If there are different magic numbers for the different formats, the verifier will look like::

static bool
xfs_foo_verify(
    struct xfs_buf		*bp)
{
    struct xfs_mount	*mp = bp->b_mount;
    struct xfs_ondisk_hdr	*hdr = bp->b_addr;

    if (hdr->magic == cpu_to_be32(XFS_FOO_CRC_MAGIC)) {
	    if (!uuid_equal(&hdr->uuid, &mp->m_sb.sb_uuid))
		    return false;
	    if (bp->b_bn != be64_to_cpu(hdr->blkno))
		    return false;
	    if (hdr->owner == 0)
		    return false;
    } else if (hdr->magic != cpu_to_be32(XFS_FOO_MAGIC))
	    return false;

    /* object specific verification checks here */

    return true;
}

Write verifiers are very similar to the read verifiers, they just do things in the opposite order to the read verifiers. A typical write verifier::

static void
xfs_foo_write_verify(
    struct xfs_buf	*bp)
{
    struct xfs_mount	*mp = bp->b_mount;
    struct xfs_buf_log_item	*bip = bp->b_fspriv;

    if (!xfs_foo_verify(bp)) {
	    XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
	    xfs_buf_ioerror(bp, EFSCORRUPTED);
	    return;
    }

    if (!xfs_sb_version_hascrc(&mp->m_sb))
	    return;


    if (bip) {
	    struct xfs_ondisk_hdr	*hdr = bp->b_addr;
	    hdr->lsn = cpu_to_be64(bip->bli_item.li_lsn);
    }
    xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_FOO_CRC_OFF);
}

This will verify the internal structure of the metadata before we go any further, detecting corruptions that have occurred as the metadata has been modified in memory. If the metadata verifies OK, and CRCs are enabled, we then update the LSN field (when it was last modified) and calculate the CRC on the metadata. Once this is done, we can issue the IO.