]>
Commit | Line | Data |
---|---|---|
bc02e869 CH |
1 | #ifndef _XFS_CKSUM_H |
2 | #define _XFS_CKSUM_H 1 | |
3 | ||
4 | #define XFS_CRC_SEED (~(__uint32_t)0) | |
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 | |
cae028df 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. | |
bc02e869 CH |
11 | */ |
12 | static inline __uint32_t | |
cae028df | 13 | xfs_start_cksum_safe(char *buffer, size_t length, unsigned long cksum_offset) |
bc02e869 CH |
14 | { |
15 | __uint32_t zero = 0; | |
16 | __uint32_t crc; | |
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 | ||
cae028df 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 | */ | |
33 | static inline __uint32_t | |
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 | ||
bc02e869 CH |
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 | |
51 | xfs_end_cksum(__uint32_t crc) | |
52 | { | |
53 | return ~cpu_to_le32(crc); | |
54 | } | |
55 | ||
56 | /* | |
57 | * Helper to generate the checksum for a buffer. | |
cae028df DC |
58 | * |
59 | * This modifies the buffer temporarily - callers must have exclusive | |
60 | * access to the buffer while the calculation takes place. | |
bc02e869 CH |
61 | */ |
62 | static inline void | |
63 | xfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset) | |
64 | { | |
cae028df | 65 | __uint32_t crc = xfs_start_cksum_update(buffer, length, cksum_offset); |
bc02e869 CH |
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 | { | |
cae028df | 76 | __uint32_t crc = xfs_start_cksum_safe(buffer, length, cksum_offset); |
bc02e869 CH |
77 | |
78 | return *(__le32 *)(buffer + cksum_offset) == xfs_end_cksum(crc); | |
79 | } | |
80 | ||
81 | #endif /* _XFS_CKSUM_H */ |