184be0ffcSDave Chinner #ifndef _XFS_CKSUM_H 284be0ffcSDave Chinner #define _XFS_CKSUM_H 1 384be0ffcSDave Chinner 484be0ffcSDave Chinner #define XFS_CRC_SEED (~(__uint32_t)0) 584be0ffcSDave Chinner 684be0ffcSDave Chinner /* 784be0ffcSDave Chinner * Calculate the intermediate checksum for a buffer that has the CRC field 884be0ffcSDave Chinner * inside it. The offset of the 32bit crc fields is passed as the 9*cae028dfSDave Chinner * cksum_offset parameter. We do not modify the buffer during verification, 10*cae028dfSDave Chinner * hence we have to split the CRC calculation across the cksum_offset. 1184be0ffcSDave Chinner */ 1284be0ffcSDave Chinner static inline __uint32_t 13*cae028dfSDave Chinner xfs_start_cksum_safe(char *buffer, size_t length, unsigned long cksum_offset) 1484be0ffcSDave Chinner { 1584be0ffcSDave Chinner __uint32_t zero = 0; 1684be0ffcSDave Chinner __uint32_t crc; 1784be0ffcSDave Chinner 1884be0ffcSDave Chinner /* Calculate CRC up to the checksum. */ 1984be0ffcSDave Chinner crc = crc32c(XFS_CRC_SEED, buffer, cksum_offset); 2084be0ffcSDave Chinner 2184be0ffcSDave Chinner /* Skip checksum field */ 2284be0ffcSDave Chinner crc = crc32c(crc, &zero, sizeof(__u32)); 2384be0ffcSDave Chinner 2484be0ffcSDave Chinner /* Calculate the rest of the CRC. */ 2584be0ffcSDave Chinner return crc32c(crc, &buffer[cksum_offset + sizeof(__be32)], 2684be0ffcSDave Chinner length - (cksum_offset + sizeof(__be32))); 2784be0ffcSDave Chinner } 2884be0ffcSDave Chinner 2984be0ffcSDave Chinner /* 30*cae028dfSDave Chinner * Fast CRC method where the buffer is modified. Callers must have exclusive 31*cae028dfSDave Chinner * access to the buffer while the calculation takes place. 32*cae028dfSDave Chinner */ 33*cae028dfSDave Chinner static inline __uint32_t 34*cae028dfSDave Chinner xfs_start_cksum_update(char *buffer, size_t length, unsigned long cksum_offset) 35*cae028dfSDave Chinner { 36*cae028dfSDave Chinner /* zero the CRC field */ 37*cae028dfSDave Chinner *(__le32 *)(buffer + cksum_offset) = 0; 38*cae028dfSDave Chinner 39*cae028dfSDave Chinner /* single pass CRC calculation for the entire buffer */ 40*cae028dfSDave Chinner return crc32c(XFS_CRC_SEED, buffer, length); 41*cae028dfSDave Chinner } 42*cae028dfSDave Chinner 43*cae028dfSDave Chinner /* 4484be0ffcSDave Chinner * Convert the intermediate checksum to the final ondisk format. 4584be0ffcSDave Chinner * 4684be0ffcSDave Chinner * The CRC32c calculation uses LE format even on BE machines, but returns the 4784be0ffcSDave Chinner * result in host endian format. Hence we need to byte swap it back to LE format 4884be0ffcSDave Chinner * so that it is consistent on disk. 4984be0ffcSDave Chinner */ 5084be0ffcSDave Chinner static inline __le32 5184be0ffcSDave Chinner xfs_end_cksum(__uint32_t crc) 5284be0ffcSDave Chinner { 5384be0ffcSDave Chinner return ~cpu_to_le32(crc); 5484be0ffcSDave Chinner } 5584be0ffcSDave Chinner 5684be0ffcSDave Chinner /* 5784be0ffcSDave Chinner * Helper to generate the checksum for a buffer. 58*cae028dfSDave Chinner * 59*cae028dfSDave Chinner * This modifies the buffer temporarily - callers must have exclusive 60*cae028dfSDave Chinner * access to the buffer while the calculation takes place. 6184be0ffcSDave Chinner */ 6284be0ffcSDave Chinner static inline void 6384be0ffcSDave Chinner xfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset) 6484be0ffcSDave Chinner { 65*cae028dfSDave Chinner __uint32_t crc = xfs_start_cksum_update(buffer, length, cksum_offset); 6684be0ffcSDave Chinner 6784be0ffcSDave Chinner *(__le32 *)(buffer + cksum_offset) = xfs_end_cksum(crc); 6884be0ffcSDave Chinner } 6984be0ffcSDave Chinner 7084be0ffcSDave Chinner /* 7184be0ffcSDave Chinner * Helper to verify the checksum for a buffer. 7284be0ffcSDave Chinner */ 7384be0ffcSDave Chinner static inline int 7484be0ffcSDave Chinner xfs_verify_cksum(char *buffer, size_t length, unsigned long cksum_offset) 7584be0ffcSDave Chinner { 76*cae028dfSDave Chinner __uint32_t crc = xfs_start_cksum_safe(buffer, length, cksum_offset); 7784be0ffcSDave Chinner 7884be0ffcSDave Chinner return *(__le32 *)(buffer + cksum_offset) == xfs_end_cksum(crc); 7984be0ffcSDave Chinner } 8084be0ffcSDave Chinner 8184be0ffcSDave Chinner #endif /* _XFS_CKSUM_H */ 82