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