162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _XFS_CKSUM_H 362306a36Sopenharmony_ci#define _XFS_CKSUM_H 1 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#define XFS_CRC_SEED (~(uint32_t)0) 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci * Calculate the intermediate checksum for a buffer that has the CRC field 962306a36Sopenharmony_ci * inside it. The offset of the 32bit crc fields is passed as the 1062306a36Sopenharmony_ci * cksum_offset parameter. We do not modify the buffer during verification, 1162306a36Sopenharmony_ci * hence we have to split the CRC calculation across the cksum_offset. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_cistatic inline uint32_t 1462306a36Sopenharmony_cixfs_start_cksum_safe(char *buffer, size_t length, unsigned long cksum_offset) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci uint32_t zero = 0; 1762306a36Sopenharmony_ci uint32_t crc; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci /* Calculate CRC up to the checksum. */ 2062306a36Sopenharmony_ci crc = crc32c(XFS_CRC_SEED, buffer, cksum_offset); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci /* Skip checksum field */ 2362306a36Sopenharmony_ci crc = crc32c(crc, &zero, sizeof(__u32)); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci /* Calculate the rest of the CRC. */ 2662306a36Sopenharmony_ci return crc32c(crc, &buffer[cksum_offset + sizeof(__be32)], 2762306a36Sopenharmony_ci length - (cksum_offset + sizeof(__be32))); 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * Fast CRC method where the buffer is modified. Callers must have exclusive 3262306a36Sopenharmony_ci * access to the buffer while the calculation takes place. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistatic inline uint32_t 3562306a36Sopenharmony_cixfs_start_cksum_update(char *buffer, size_t length, unsigned long cksum_offset) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci /* zero the CRC field */ 3862306a36Sopenharmony_ci *(__le32 *)(buffer + cksum_offset) = 0; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* single pass CRC calculation for the entire buffer */ 4162306a36Sopenharmony_ci return crc32c(XFS_CRC_SEED, buffer, length); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * Convert the intermediate checksum to the final ondisk format. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * The CRC32c calculation uses LE format even on BE machines, but returns the 4862306a36Sopenharmony_ci * result in host endian format. Hence we need to byte swap it back to LE format 4962306a36Sopenharmony_ci * so that it is consistent on disk. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistatic inline __le32 5262306a36Sopenharmony_cixfs_end_cksum(uint32_t crc) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci return ~cpu_to_le32(crc); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * Helper to generate the checksum for a buffer. 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * This modifies the buffer temporarily - callers must have exclusive 6162306a36Sopenharmony_ci * access to the buffer while the calculation takes place. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_cistatic inline void 6462306a36Sopenharmony_cixfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci uint32_t crc = xfs_start_cksum_update(buffer, length, cksum_offset); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci *(__le32 *)(buffer + cksum_offset) = xfs_end_cksum(crc); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* 7262306a36Sopenharmony_ci * Helper to verify the checksum for a buffer. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cistatic inline int 7562306a36Sopenharmony_cixfs_verify_cksum(char *buffer, size_t length, unsigned long cksum_offset) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci uint32_t crc = xfs_start_cksum_safe(buffer, length, cksum_offset); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return *(__le32 *)(buffer + cksum_offset) == xfs_end_cksum(crc); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#endif /* _XFS_CKSUM_H */ 83