^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #ifndef _XFS_CKSUM_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #define _XFS_CKSUM_H 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #define XFS_CRC_SEED (~(uint32_t)0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Calculate the intermediate checksum for a buffer that has the CRC field
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * inside it. The offset of the 32bit crc fields is passed as the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * cksum_offset parameter. We do not modify the buffer during verification,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * hence we have to split the CRC calculation across the cksum_offset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static inline uint32_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) xfs_start_cksum_safe(char *buffer, size_t length, unsigned long cksum_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) uint32_t zero = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) uint32_t crc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) /* Calculate CRC up to the checksum. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) crc = crc32c(XFS_CRC_SEED, buffer, cksum_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /* Skip checksum field */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) crc = crc32c(crc, &zero, sizeof(__u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /* Calculate the rest of the CRC. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) return crc32c(crc, &buffer[cksum_offset + sizeof(__be32)],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) length - (cksum_offset + sizeof(__be32)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * Fast CRC method where the buffer is modified. Callers must have exclusive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * access to the buffer while the calculation takes place.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static inline uint32_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) xfs_start_cksum_update(char *buffer, size_t length, unsigned long cksum_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* zero the CRC field */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) *(__le32 *)(buffer + cksum_offset) = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* single pass CRC calculation for the entire buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return crc32c(XFS_CRC_SEED, buffer, length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * Convert the intermediate checksum to the final ondisk format.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * The CRC32c calculation uses LE format even on BE machines, but returns the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * result in host endian format. Hence we need to byte swap it back to LE format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * so that it is consistent on disk.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static inline __le32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) xfs_end_cksum(uint32_t crc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return ~cpu_to_le32(crc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * Helper to generate the checksum for a buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * This modifies the buffer temporarily - callers must have exclusive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * access to the buffer while the calculation takes place.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static inline void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) xfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) uint32_t crc = xfs_start_cksum_update(buffer, length, cksum_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *(__le32 *)(buffer + cksum_offset) = xfs_end_cksum(crc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * Helper to verify the checksum for a buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) xfs_verify_cksum(char *buffer, size_t length, unsigned long cksum_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) uint32_t crc = xfs_start_cksum_safe(buffer, length, cksum_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return *(__le32 *)(buffer + cksum_offset) == xfs_end_cksum(crc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #endif /* _XFS_CKSUM_H */