18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* -*- mode: c; c-basic-offset: 8; -*- 38c2ecf20Sopenharmony_ci * vim: noexpandtab sw=8 ts=8 sts=0: 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * blockcheck.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Checksum and ECC codes for the OCFS2 userspace library. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (C) 2006, 2008 Oracle. All rights reserved. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/crc32.h> 158c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 168c2ecf20Sopenharmony_ci#include <linux/bitops.h> 178c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/fs.h> 208c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <cluster/masklog.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "ocfs2.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "blockcheck.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * We use the following conventions: 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * d = # data bits 338c2ecf20Sopenharmony_ci * p = # parity bits 348c2ecf20Sopenharmony_ci * c = # total code bits (d + p) 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * Calculate the bit offset in the hamming code buffer based on the bit's 408c2ecf20Sopenharmony_ci * offset in the data buffer. Since the hamming code reserves all 418c2ecf20Sopenharmony_ci * power-of-two bits for parity, the data bit number and the code bit 428c2ecf20Sopenharmony_ci * number are offset by all the parity bits beforehand. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Recall that bit numbers in hamming code are 1-based. This function 458c2ecf20Sopenharmony_ci * takes the 0-based data bit from the caller. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * An example. Take bit 1 of the data buffer. 1 is a power of two (2^0), 488c2ecf20Sopenharmony_ci * so it's a parity bit. 2 is a power of two (2^1), so it's a parity bit. 498c2ecf20Sopenharmony_ci * 3 is not a power of two. So bit 1 of the data buffer ends up as bit 3 508c2ecf20Sopenharmony_ci * in the code buffer. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * The caller can pass in *p if it wants to keep track of the most recent 538c2ecf20Sopenharmony_ci * number of parity bits added. This allows the function to start the 548c2ecf20Sopenharmony_ci * calculation at the last place. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistatic unsigned int calc_code_bit(unsigned int i, unsigned int *p_cache) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci unsigned int b, p = 0; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci /* 618c2ecf20Sopenharmony_ci * Data bits are 0-based, but we're talking code bits, which 628c2ecf20Sopenharmony_ci * are 1-based. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci b = i + 1; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* Use the cache if it is there */ 678c2ecf20Sopenharmony_ci if (p_cache) 688c2ecf20Sopenharmony_ci p = *p_cache; 698c2ecf20Sopenharmony_ci b += p; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* 728c2ecf20Sopenharmony_ci * For every power of two below our bit number, bump our bit. 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * We compare with (b + 1) because we have to compare with what b 758c2ecf20Sopenharmony_ci * would be _if_ it were bumped up by the parity bit. Capice? 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * p is set above. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ci for (; (1 << p) < (b + 1); p++) 808c2ecf20Sopenharmony_ci b++; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (p_cache) 838c2ecf20Sopenharmony_ci *p_cache = p; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return b; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* 898c2ecf20Sopenharmony_ci * This is the low level encoder function. It can be called across 908c2ecf20Sopenharmony_ci * multiple hunks just like the crc32 code. 'd' is the number of bits 918c2ecf20Sopenharmony_ci * _in_this_hunk_. nr is the bit offset of this hunk. So, if you had 928c2ecf20Sopenharmony_ci * two 512B buffers, you would do it like so: 938c2ecf20Sopenharmony_ci * 948c2ecf20Sopenharmony_ci * parity = ocfs2_hamming_encode(0, buf1, 512 * 8, 0); 958c2ecf20Sopenharmony_ci * parity = ocfs2_hamming_encode(parity, buf2, 512 * 8, 512 * 8); 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * If you just have one buffer, use ocfs2_hamming_encode_block(). 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ciu32 ocfs2_hamming_encode(u32 parity, void *data, unsigned int d, unsigned int nr) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci unsigned int i, b, p = 0; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci BUG_ON(!d); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* 1068c2ecf20Sopenharmony_ci * b is the hamming code bit number. Hamming code specifies a 1078c2ecf20Sopenharmony_ci * 1-based array, but C uses 0-based. So 'i' is for C, and 'b' is 1088c2ecf20Sopenharmony_ci * for the algorithm. 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * The i++ in the for loop is so that the start offset passed 1118c2ecf20Sopenharmony_ci * to ocfs2_find_next_bit_set() is one greater than the previously 1128c2ecf20Sopenharmony_ci * found bit. 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci for (i = 0; (i = ocfs2_find_next_bit(data, d, i)) < d; i++) 1158c2ecf20Sopenharmony_ci { 1168c2ecf20Sopenharmony_ci /* 1178c2ecf20Sopenharmony_ci * i is the offset in this hunk, nr + i is the total bit 1188c2ecf20Sopenharmony_ci * offset. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci b = calc_code_bit(nr + i, &p); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * Data bits in the resultant code are checked by 1248c2ecf20Sopenharmony_ci * parity bits that are part of the bit number 1258c2ecf20Sopenharmony_ci * representation. Huh? 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * <wikipedia href="https://en.wikipedia.org/wiki/Hamming_code"> 1288c2ecf20Sopenharmony_ci * In other words, the parity bit at position 2^k 1298c2ecf20Sopenharmony_ci * checks bits in positions having bit k set in 1308c2ecf20Sopenharmony_ci * their binary representation. Conversely, for 1318c2ecf20Sopenharmony_ci * instance, bit 13, i.e. 1101(2), is checked by 1328c2ecf20Sopenharmony_ci * bits 1000(2) = 8, 0100(2)=4 and 0001(2) = 1. 1338c2ecf20Sopenharmony_ci * </wikipedia> 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci * Note that 'k' is the _code_ bit number. 'b' in 1368c2ecf20Sopenharmony_ci * our loop. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ci parity ^= b; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* While the data buffer was treated as little endian, the 1428c2ecf20Sopenharmony_ci * return value is in host endian. */ 1438c2ecf20Sopenharmony_ci return parity; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciu32 ocfs2_hamming_encode_block(void *data, unsigned int blocksize) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci return ocfs2_hamming_encode(0, data, blocksize * 8, 0); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* 1528c2ecf20Sopenharmony_ci * Like ocfs2_hamming_encode(), this can handle hunks. nr is the bit 1538c2ecf20Sopenharmony_ci * offset of the current hunk. If bit to be fixed is not part of the 1548c2ecf20Sopenharmony_ci * current hunk, this does nothing. 1558c2ecf20Sopenharmony_ci * 1568c2ecf20Sopenharmony_ci * If you only have one hunk, use ocfs2_hamming_fix_block(). 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_civoid ocfs2_hamming_fix(void *data, unsigned int d, unsigned int nr, 1598c2ecf20Sopenharmony_ci unsigned int fix) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci unsigned int i, b; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci BUG_ON(!d); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* 1668c2ecf20Sopenharmony_ci * If the bit to fix has an hweight of 1, it's a parity bit. One 1678c2ecf20Sopenharmony_ci * busted parity bit is its own error. Nothing to do here. 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_ci if (hweight32(fix) == 1) 1708c2ecf20Sopenharmony_ci return; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* 1738c2ecf20Sopenharmony_ci * nr + d is the bit right past the data hunk we're looking at. 1748c2ecf20Sopenharmony_ci * If fix after that, nothing to do 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ci if (fix >= calc_code_bit(nr + d, NULL)) 1778c2ecf20Sopenharmony_ci return; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * nr is the offset in the data hunk we're starting at. Let's 1818c2ecf20Sopenharmony_ci * start b at the offset in the code buffer. See hamming_encode() 1828c2ecf20Sopenharmony_ci * for a more detailed description of 'b'. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci b = calc_code_bit(nr, NULL); 1858c2ecf20Sopenharmony_ci /* If the fix is before this hunk, nothing to do */ 1868c2ecf20Sopenharmony_ci if (fix < b) 1878c2ecf20Sopenharmony_ci return; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci for (i = 0; i < d; i++, b++) 1908c2ecf20Sopenharmony_ci { 1918c2ecf20Sopenharmony_ci /* Skip past parity bits */ 1928c2ecf20Sopenharmony_ci while (hweight32(b) == 1) 1938c2ecf20Sopenharmony_ci b++; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* 1968c2ecf20Sopenharmony_ci * i is the offset in this data hunk. 1978c2ecf20Sopenharmony_ci * nr + i is the offset in the total data buffer. 1988c2ecf20Sopenharmony_ci * b is the offset in the total code buffer. 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * Thus, when b == fix, bit i in the current hunk needs 2018c2ecf20Sopenharmony_ci * fixing. 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_ci if (b == fix) 2048c2ecf20Sopenharmony_ci { 2058c2ecf20Sopenharmony_ci if (ocfs2_test_bit(i, data)) 2068c2ecf20Sopenharmony_ci ocfs2_clear_bit(i, data); 2078c2ecf20Sopenharmony_ci else 2088c2ecf20Sopenharmony_ci ocfs2_set_bit(i, data); 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_civoid ocfs2_hamming_fix_block(void *data, unsigned int blocksize, 2158c2ecf20Sopenharmony_ci unsigned int fix) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci ocfs2_hamming_fix(data, blocksize * 8, 0, fix); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/* 2228c2ecf20Sopenharmony_ci * Debugfs handling. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic int blockcheck_u64_get(void *data, u64 *val) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci *val = *(u64 *)data; 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ciDEFINE_SIMPLE_ATTRIBUTE(blockcheck_fops, blockcheck_u64_get, NULL, "%llu\n"); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci if (stats) { 2378c2ecf20Sopenharmony_ci debugfs_remove_recursive(stats->b_debug_dir); 2388c2ecf20Sopenharmony_ci stats->b_debug_dir = NULL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats, 2438c2ecf20Sopenharmony_ci struct dentry *parent) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct dentry *dir; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci dir = debugfs_create_dir("blockcheck", parent); 2488c2ecf20Sopenharmony_ci stats->b_debug_dir = dir; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci debugfs_create_file("blocks_checked", S_IFREG | S_IRUSR, dir, 2518c2ecf20Sopenharmony_ci &stats->b_check_count, &blockcheck_fops); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci debugfs_create_file("checksums_failed", S_IFREG | S_IRUSR, dir, 2548c2ecf20Sopenharmony_ci &stats->b_failure_count, &blockcheck_fops); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci debugfs_create_file("ecc_recoveries", S_IFREG | S_IRUSR, dir, 2578c2ecf20Sopenharmony_ci &stats->b_recover_count, &blockcheck_fops); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci#else 2618c2ecf20Sopenharmony_cistatic inline void ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats, 2628c2ecf20Sopenharmony_ci struct dentry *parent) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic inline void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* Always-called wrappers for starting and stopping the debugfs files */ 2728c2ecf20Sopenharmony_civoid ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats, 2738c2ecf20Sopenharmony_ci struct dentry *parent) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci ocfs2_blockcheck_debug_install(stats, parent); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_civoid ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci ocfs2_blockcheck_debug_remove(stats); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void ocfs2_blockcheck_inc_check(struct ocfs2_blockcheck_stats *stats) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci u64 new_count; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (!stats) 2888c2ecf20Sopenharmony_ci return; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci spin_lock(&stats->b_lock); 2918c2ecf20Sopenharmony_ci stats->b_check_count++; 2928c2ecf20Sopenharmony_ci new_count = stats->b_check_count; 2938c2ecf20Sopenharmony_ci spin_unlock(&stats->b_lock); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (!new_count) 2968c2ecf20Sopenharmony_ci mlog(ML_NOTICE, "Block check count has wrapped\n"); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic void ocfs2_blockcheck_inc_failure(struct ocfs2_blockcheck_stats *stats) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci u64 new_count; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (!stats) 3048c2ecf20Sopenharmony_ci return; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci spin_lock(&stats->b_lock); 3078c2ecf20Sopenharmony_ci stats->b_failure_count++; 3088c2ecf20Sopenharmony_ci new_count = stats->b_failure_count; 3098c2ecf20Sopenharmony_ci spin_unlock(&stats->b_lock); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (!new_count) 3128c2ecf20Sopenharmony_ci mlog(ML_NOTICE, "Checksum failure count has wrapped\n"); 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic void ocfs2_blockcheck_inc_recover(struct ocfs2_blockcheck_stats *stats) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci u64 new_count; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (!stats) 3208c2ecf20Sopenharmony_ci return; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci spin_lock(&stats->b_lock); 3238c2ecf20Sopenharmony_ci stats->b_recover_count++; 3248c2ecf20Sopenharmony_ci new_count = stats->b_recover_count; 3258c2ecf20Sopenharmony_ci spin_unlock(&stats->b_lock); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!new_count) 3288c2ecf20Sopenharmony_ci mlog(ML_NOTICE, "ECC recovery count has wrapped\n"); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/* 3348c2ecf20Sopenharmony_ci * These are the low-level APIs for using the ocfs2_block_check structure. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/* 3388c2ecf20Sopenharmony_ci * This function generates check information for a block. 3398c2ecf20Sopenharmony_ci * data is the block to be checked. bc is a pointer to the 3408c2ecf20Sopenharmony_ci * ocfs2_block_check structure describing the crc32 and the ecc. 3418c2ecf20Sopenharmony_ci * 3428c2ecf20Sopenharmony_ci * bc should be a pointer inside data, as the function will 3438c2ecf20Sopenharmony_ci * take care of zeroing it before calculating the check information. If 3448c2ecf20Sopenharmony_ci * bc does not point inside data, the caller must make sure any inline 3458c2ecf20Sopenharmony_ci * ocfs2_block_check structures are zeroed. 3468c2ecf20Sopenharmony_ci * 3478c2ecf20Sopenharmony_ci * The data buffer must be in on-disk endian (little endian for ocfs2). 3488c2ecf20Sopenharmony_ci * bc will be filled with little-endian values and will be ready to go to 3498c2ecf20Sopenharmony_ci * disk. 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_civoid ocfs2_block_check_compute(void *data, size_t blocksize, 3528c2ecf20Sopenharmony_ci struct ocfs2_block_check *bc) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci u32 crc; 3558c2ecf20Sopenharmony_ci u32 ecc; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci memset(bc, 0, sizeof(struct ocfs2_block_check)); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci crc = crc32_le(~0, data, blocksize); 3608c2ecf20Sopenharmony_ci ecc = ocfs2_hamming_encode_block(data, blocksize); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* 3638c2ecf20Sopenharmony_ci * No ecc'd ocfs2 structure is larger than 4K, so ecc will be no 3648c2ecf20Sopenharmony_ci * larger than 16 bits. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci BUG_ON(ecc > USHRT_MAX); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci bc->bc_crc32e = cpu_to_le32(crc); 3698c2ecf20Sopenharmony_ci bc->bc_ecc = cpu_to_le16((u16)ecc); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* 3738c2ecf20Sopenharmony_ci * This function validates existing check information. Like _compute, 3748c2ecf20Sopenharmony_ci * the function will take care of zeroing bc before calculating check codes. 3758c2ecf20Sopenharmony_ci * If bc is not a pointer inside data, the caller must have zeroed any 3768c2ecf20Sopenharmony_ci * inline ocfs2_block_check structures. 3778c2ecf20Sopenharmony_ci * 3788c2ecf20Sopenharmony_ci * Again, the data passed in should be the on-disk endian. 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_ciint ocfs2_block_check_validate(void *data, size_t blocksize, 3818c2ecf20Sopenharmony_ci struct ocfs2_block_check *bc, 3828c2ecf20Sopenharmony_ci struct ocfs2_blockcheck_stats *stats) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci int rc = 0; 3858c2ecf20Sopenharmony_ci u32 bc_crc32e; 3868c2ecf20Sopenharmony_ci u16 bc_ecc; 3878c2ecf20Sopenharmony_ci u32 crc, ecc; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci ocfs2_blockcheck_inc_check(stats); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci bc_crc32e = le32_to_cpu(bc->bc_crc32e); 3928c2ecf20Sopenharmony_ci bc_ecc = le16_to_cpu(bc->bc_ecc); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci memset(bc, 0, sizeof(struct ocfs2_block_check)); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* Fast path - if the crc32 validates, we're good to go */ 3978c2ecf20Sopenharmony_ci crc = crc32_le(~0, data, blocksize); 3988c2ecf20Sopenharmony_ci if (crc == bc_crc32e) 3998c2ecf20Sopenharmony_ci goto out; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci ocfs2_blockcheck_inc_failure(stats); 4028c2ecf20Sopenharmony_ci mlog(ML_ERROR, 4038c2ecf20Sopenharmony_ci "CRC32 failed: stored: 0x%x, computed 0x%x. Applying ECC.\n", 4048c2ecf20Sopenharmony_ci (unsigned int)bc_crc32e, (unsigned int)crc); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* Ok, try ECC fixups */ 4078c2ecf20Sopenharmony_ci ecc = ocfs2_hamming_encode_block(data, blocksize); 4088c2ecf20Sopenharmony_ci ocfs2_hamming_fix_block(data, blocksize, ecc ^ bc_ecc); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci /* And check the crc32 again */ 4118c2ecf20Sopenharmony_ci crc = crc32_le(~0, data, blocksize); 4128c2ecf20Sopenharmony_ci if (crc == bc_crc32e) { 4138c2ecf20Sopenharmony_ci ocfs2_blockcheck_inc_recover(stats); 4148c2ecf20Sopenharmony_ci goto out; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Fixed CRC32 failed: stored: 0x%x, computed 0x%x\n", 4188c2ecf20Sopenharmony_ci (unsigned int)bc_crc32e, (unsigned int)crc); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci rc = -EIO; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ciout: 4238c2ecf20Sopenharmony_ci bc->bc_crc32e = cpu_to_le32(bc_crc32e); 4248c2ecf20Sopenharmony_ci bc->bc_ecc = cpu_to_le16(bc_ecc); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return rc; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/* 4308c2ecf20Sopenharmony_ci * This function generates check information for a list of buffer_heads. 4318c2ecf20Sopenharmony_ci * bhs is the blocks to be checked. bc is a pointer to the 4328c2ecf20Sopenharmony_ci * ocfs2_block_check structure describing the crc32 and the ecc. 4338c2ecf20Sopenharmony_ci * 4348c2ecf20Sopenharmony_ci * bc should be a pointer inside data, as the function will 4358c2ecf20Sopenharmony_ci * take care of zeroing it before calculating the check information. If 4368c2ecf20Sopenharmony_ci * bc does not point inside data, the caller must make sure any inline 4378c2ecf20Sopenharmony_ci * ocfs2_block_check structures are zeroed. 4388c2ecf20Sopenharmony_ci * 4398c2ecf20Sopenharmony_ci * The data buffer must be in on-disk endian (little endian for ocfs2). 4408c2ecf20Sopenharmony_ci * bc will be filled with little-endian values and will be ready to go to 4418c2ecf20Sopenharmony_ci * disk. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_civoid ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr, 4448c2ecf20Sopenharmony_ci struct ocfs2_block_check *bc) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci int i; 4478c2ecf20Sopenharmony_ci u32 crc, ecc; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci BUG_ON(nr < 0); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (!nr) 4528c2ecf20Sopenharmony_ci return; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci memset(bc, 0, sizeof(struct ocfs2_block_check)); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci for (i = 0, crc = ~0, ecc = 0; i < nr; i++) { 4578c2ecf20Sopenharmony_ci crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size); 4588c2ecf20Sopenharmony_ci /* 4598c2ecf20Sopenharmony_ci * The number of bits in a buffer is obviously b_size*8. 4608c2ecf20Sopenharmony_ci * The offset of this buffer is b_size*i, so the bit offset 4618c2ecf20Sopenharmony_ci * of this buffer is b_size*8*i. 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci ecc = (u16)ocfs2_hamming_encode(ecc, bhs[i]->b_data, 4648c2ecf20Sopenharmony_ci bhs[i]->b_size * 8, 4658c2ecf20Sopenharmony_ci bhs[i]->b_size * 8 * i); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* 4698c2ecf20Sopenharmony_ci * No ecc'd ocfs2 structure is larger than 4K, so ecc will be no 4708c2ecf20Sopenharmony_ci * larger than 16 bits. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_ci BUG_ON(ecc > USHRT_MAX); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci bc->bc_crc32e = cpu_to_le32(crc); 4758c2ecf20Sopenharmony_ci bc->bc_ecc = cpu_to_le16((u16)ecc); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/* 4798c2ecf20Sopenharmony_ci * This function validates existing check information on a list of 4808c2ecf20Sopenharmony_ci * buffer_heads. Like _compute_bhs, the function will take care of 4818c2ecf20Sopenharmony_ci * zeroing bc before calculating check codes. If bc is not a pointer 4828c2ecf20Sopenharmony_ci * inside data, the caller must have zeroed any inline 4838c2ecf20Sopenharmony_ci * ocfs2_block_check structures. 4848c2ecf20Sopenharmony_ci * 4858c2ecf20Sopenharmony_ci * Again, the data passed in should be the on-disk endian. 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ciint ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, 4888c2ecf20Sopenharmony_ci struct ocfs2_block_check *bc, 4898c2ecf20Sopenharmony_ci struct ocfs2_blockcheck_stats *stats) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci int i, rc = 0; 4928c2ecf20Sopenharmony_ci u32 bc_crc32e; 4938c2ecf20Sopenharmony_ci u16 bc_ecc; 4948c2ecf20Sopenharmony_ci u32 crc, ecc, fix; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci BUG_ON(nr < 0); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (!nr) 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci ocfs2_blockcheck_inc_check(stats); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci bc_crc32e = le32_to_cpu(bc->bc_crc32e); 5048c2ecf20Sopenharmony_ci bc_ecc = le16_to_cpu(bc->bc_ecc); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci memset(bc, 0, sizeof(struct ocfs2_block_check)); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* Fast path - if the crc32 validates, we're good to go */ 5098c2ecf20Sopenharmony_ci for (i = 0, crc = ~0; i < nr; i++) 5108c2ecf20Sopenharmony_ci crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size); 5118c2ecf20Sopenharmony_ci if (crc == bc_crc32e) 5128c2ecf20Sopenharmony_ci goto out; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci ocfs2_blockcheck_inc_failure(stats); 5158c2ecf20Sopenharmony_ci mlog(ML_ERROR, 5168c2ecf20Sopenharmony_ci "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", 5178c2ecf20Sopenharmony_ci (unsigned int)bc_crc32e, (unsigned int)crc); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* Ok, try ECC fixups */ 5208c2ecf20Sopenharmony_ci for (i = 0, ecc = 0; i < nr; i++) { 5218c2ecf20Sopenharmony_ci /* 5228c2ecf20Sopenharmony_ci * The number of bits in a buffer is obviously b_size*8. 5238c2ecf20Sopenharmony_ci * The offset of this buffer is b_size*i, so the bit offset 5248c2ecf20Sopenharmony_ci * of this buffer is b_size*8*i. 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci ecc = (u16)ocfs2_hamming_encode(ecc, bhs[i]->b_data, 5278c2ecf20Sopenharmony_ci bhs[i]->b_size * 8, 5288c2ecf20Sopenharmony_ci bhs[i]->b_size * 8 * i); 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci fix = ecc ^ bc_ecc; 5318c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 5328c2ecf20Sopenharmony_ci /* 5338c2ecf20Sopenharmony_ci * Try the fix against each buffer. It will only affect 5348c2ecf20Sopenharmony_ci * one of them. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ci ocfs2_hamming_fix(bhs[i]->b_data, bhs[i]->b_size * 8, 5378c2ecf20Sopenharmony_ci bhs[i]->b_size * 8 * i, fix); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* And check the crc32 again */ 5418c2ecf20Sopenharmony_ci for (i = 0, crc = ~0; i < nr; i++) 5428c2ecf20Sopenharmony_ci crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size); 5438c2ecf20Sopenharmony_ci if (crc == bc_crc32e) { 5448c2ecf20Sopenharmony_ci ocfs2_blockcheck_inc_recover(stats); 5458c2ecf20Sopenharmony_ci goto out; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", 5498c2ecf20Sopenharmony_ci (unsigned int)bc_crc32e, (unsigned int)crc); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci rc = -EIO; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ciout: 5548c2ecf20Sopenharmony_ci bc->bc_crc32e = cpu_to_le32(bc_crc32e); 5558c2ecf20Sopenharmony_ci bc->bc_ecc = cpu_to_le16(bc_ecc); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return rc; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci/* 5618c2ecf20Sopenharmony_ci * These are the main API. They check the superblock flag before 5628c2ecf20Sopenharmony_ci * calling the underlying operations. 5638c2ecf20Sopenharmony_ci * 5648c2ecf20Sopenharmony_ci * They expect the buffer(s) to be in disk format. 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_civoid ocfs2_compute_meta_ecc(struct super_block *sb, void *data, 5678c2ecf20Sopenharmony_ci struct ocfs2_block_check *bc) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci if (ocfs2_meta_ecc(OCFS2_SB(sb))) 5708c2ecf20Sopenharmony_ci ocfs2_block_check_compute(data, sb->s_blocksize, bc); 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ciint ocfs2_validate_meta_ecc(struct super_block *sb, void *data, 5748c2ecf20Sopenharmony_ci struct ocfs2_block_check *bc) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci int rc = 0; 5778c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(sb); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (ocfs2_meta_ecc(osb)) 5808c2ecf20Sopenharmony_ci rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc, 5818c2ecf20Sopenharmony_ci &osb->osb_ecc_stats); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return rc; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_civoid ocfs2_compute_meta_ecc_bhs(struct super_block *sb, 5878c2ecf20Sopenharmony_ci struct buffer_head **bhs, int nr, 5888c2ecf20Sopenharmony_ci struct ocfs2_block_check *bc) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci if (ocfs2_meta_ecc(OCFS2_SB(sb))) 5918c2ecf20Sopenharmony_ci ocfs2_block_check_compute_bhs(bhs, nr, bc); 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ciint ocfs2_validate_meta_ecc_bhs(struct super_block *sb, 5958c2ecf20Sopenharmony_ci struct buffer_head **bhs, int nr, 5968c2ecf20Sopenharmony_ci struct ocfs2_block_check *bc) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci int rc = 0; 5998c2ecf20Sopenharmony_ci struct ocfs2_super *osb = OCFS2_SB(sb); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (ocfs2_meta_ecc(osb)) 6028c2ecf20Sopenharmony_ci rc = ocfs2_block_check_validate_bhs(bhs, nr, bc, 6038c2ecf20Sopenharmony_ci &osb->osb_ecc_stats); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return rc; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 608