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