From 5d9b1aee00938a32709997c5ff7f8b10911d38d4 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Wed, 16 Sep 2026 08:49:15 +0200 Subject: [PATCH] Clarify RAID buffer access, aliasing, and zero-size behavior --- raid/README | 38 ++++++++++++++++++++++++-------------- raid/raid.h | 25 ++++++++++++++++++++----- raid/test/speedtest.c | 2 +- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/raid/README b/raid/README index f79fc3a3..9c068102 100644 --- a/raid/README +++ b/raid/README @@ -37,29 +37,33 @@ library startup before normal RAID operations. Computes 'np' parity blocks from 'nd' data blocks. Vector 'v' contains 'nd + np' block pointers (data blocks v[0..nd-1], parity blocks v[nd..nd+np-1]). Each block must be aligned to a 64-byte boundary. - Data blocks are read-only; parity blocks are written. 'streaming' must be - either 0 or 1. If it is 1, non-temporal streaming stores are used where - supported to avoid polluting the CPU cache when parity is written directly - to disk. If it is 0, normal cached stores are used. + Data entries are used only for reading and may reference read-only memory. + Parity entries are outputs and must reference writable memory. + 'streaming' must be either 0 or 1. If it is 1, non-temporal streaming stores + are used where supported to avoid polluting the CPU cache when parity is + written directly to disk. If it is 0, normal cached stores are used. void raid_rec(int nr, int *ir, int nd, int np, size_t size, void **v) Recovers 'nr' failed blocks (data or parity) listed in sorted index array 'ir'. Indexes start at 0 (data 0..nd-1, parity nd..nd+np-1). Each block pointed to by 'v' must be aligned to a 64-byte boundary. Pointers in 'v' for good blocks are read; pointers for bad blocks are target destinations. - Requires nr <= np. + Requires nr <= np. If nr is 0, 'ir' may be null; 'v' must be non-null but + no block pointers are accessed. void raid_data(int nr, int *id, int *ip, int nd, size_t size, void **v) Recovers 'nr' failed data blocks listed in sorted array 'id', using parities listed in sorted array 'ip'. Each block pointed to by 'v' must be aligned to a 64-byte boundary. Parity blocks in 'v' are unmodified. - Requires nr <= nd and nr <= RAID_PARITY_MAX. + Requires nr <= nd and nr <= RAID_PARITY_MAX. If nr is 0, 'id' and 'ip' + may be null; 'v' must be non-null but no block pointers are accessed. int raid_check(int nr, int *ir, int nd, int np, size_t size, void **v) Validates whether candidate failed block set 'ir' matches available parity redundancy. Each block pointed to by 'v' must be aligned to a 64-byte boundary. Returns 0 if candidate set matches, or -1 if invalid. Requires - nr < np. Does not modify data or parity blocks. + nr < np. If nr is 0, 'ir' may be null. Does not modify data or parity + blocks. Returns -1 if size is 0. int raid_scan(int *ir, int nd, int np, size_t size, void **v) Searches for up to 'np - 1' failed blocks using available redundancy. @@ -69,6 +73,7 @@ library startup before normal RAID operations. checking uniqueness. Each block pointed to by 'v' must be aligned to a 64-byte boundary. Fills 'ir' with the matching block indexes and returns their number (0 if no error), or -1 if no compatible combination is found. + Returns -1 if size is 0. int raid_selftest(void) Runs startup verification tests for parity generation, recovery, and @@ -88,18 +93,23 @@ Memory, Alignment and Aliasing Requirements v[nd ... nd+np-1] -> Parity blocks (PAR1, PAR2, ..., PAR6) - Block Size: Parameter 'size' MUST be a multiple of 64 bytes - (size % 64 == 0). + (size % 64 == 0). A zero size makes generation and recovery empty + operations; validation and scanning return -1 because no redundancy data + is available. - Memory Alignment: All data and parity blocks pointed to by 'v[]' MUST be aligned to a 64-byte boundary. This requirement applies to each individual block buffer, not to the pointer array 'v' itself. - - Buffer Aliasing: Entries in 'v[]' MAY point to the same block buffer. - Blocks are processed from lower to higher offsets. For each processed - byte or vector chunk, all required inputs are read before outputs are - written. Parity outputs are written in increasing parity order. - Consequently, when multiple parity outputs point to the same block, - later parity outputs overwrite earlier ones. + - Buffer Aliasing: In raid_gen(), entries in 'v[]' MAY point to the same + block buffer. Blocks are processed from lower to higher offsets. For each + processed byte or vector chunk, all required inputs are read before outputs + are written. Parity outputs are written in increasing parity order. When + multiple parity outputs point to the same block, later parity outputs + overwrite earlier ones. + + In raid_rec() and raid_data(), each block being recovered MUST have a + distinct destination buffer that does not alias any other block in 'v[]'. This guarantee applies to block aliasing (identical block pointers); arbitrary partial overlap between distinct block ranges is not supported. diff --git a/raid/raid.h b/raid/raid.h index b8ce9e11..d4595a87 100644 --- a/raid/raid.h +++ b/raid/raid.h @@ -195,11 +195,14 @@ int raid_selftest(void); * @np Number of parity blocks to compute. It must be between 1 and * RAID_PARITY_MAX. RAID_MODE_VANDERMONDE_RAID supports at most 3. * @size Size of the blocks pointed to by @v. It must be a multiple of 64. + * It may be 0, in which case no block data is read or written. * @v Vector of pointers to the blocks of data and parity. * It has (@nd + @np) elements. The starting elements are the blocks for * data, following with the parity blocks. - * Data entries are used as inputs and parity entries as outputs. + * Data entries are used only for reading and may reference read-only memory. + * Parity entries are outputs and must reference writable memory. * Entries may point to the same block buffer. + * Each block has @size bytes and must be aligned to a 64-byte boundary. * @streaming Store policy hint: 1 for streaming / non-temporal stores * (bypassing cache) where supported, or 0 for normal cached / temporal stores. * No other values are valid. @@ -239,13 +242,16 @@ void raid_gen(int nd, int np, size_t size, void **v, int streaming); * All indexes must be nonnegative and smaller than @nd + @np. * The first parity is represented with value @nd, the second with value * @nd + 1, just like positions in the @v vector. + * It may be 0 if @nr is 0. * @nd Number of data blocks. It must be between 1 and RAID_DATA_MAX. * @np Number of parity blocks. It must be between 1 and RAID_PARITY_MAX. * RAID_MODE_VANDERMONDE_RAID supports at most 3. * @size Size of the blocks pointed by @v. It must be a multiple of 64. + * It may be 0, in which case no block data is read or written. * @v Vector of pointers to the blocks of data and parity. - * It has (@nd + @np) elements. The starting elements are the blocks - * for data, following with the parity blocks. + * If @nr is greater than 0, it has (@nd + @np) elements. The starting + * elements are the blocks for data, followed by the parity blocks. + * If @nr is 0, @v must be nonzero but no block pointers are accessed. * Each block being recovered must have a distinct destination buffer * that does not alias any other block in this vector. * Each block has @size bytes and must be aligned to a 64-byte boundary. @@ -263,15 +269,19 @@ void raid_rec(int nr, int *ir, int nd, int np, size_t size, void **v); * @id[] Vector of @nr indexes of the data blocks to recover. * The indexes start from 0. They must be in order. * All indexes must be nonnegative and smaller than @nd. + * It may be 0 if @nr is 0. * @ip[] Vector of @nr indexes of the parity blocks to use for recovery. * The indexes start from 0. They must be in order. * All indexes must be nonnegative and smaller than RAID_PARITY_MAX. * In RAID_MODE_VANDERMONDE_RAID they must be smaller than 3. + * It may be 0 if @nr is 0. * @nd Number of data blocks. It must be between 1 and RAID_DATA_MAX. * @size Size of the blocks pointed to by @v. It must be a multiple of 64. + * It may be 0, in which case no block data is read or written. * @v Vector of pointers to the blocks of data and parity. - * It has (@nd + @ip[@nr - 1] + 1) elements. The starting elements are the - * blocks for data, following with the parity blocks. + * If @nr is greater than 0, it has (@nd + @ip[@nr - 1] + 1) elements. + * The starting elements are the blocks for data, followed by the parity + * blocks. If @nr is 0, @v must be nonzero but no block pointers are accessed. * Each data block being recovered must have a distinct destination buffer * that does not alias any other block in this vector. * Each block has @size bytes and must be aligned to a 64-byte boundary. @@ -297,10 +307,13 @@ void raid_data(int nr, int *id, int *ip, int nd, size_t size, void **v); * All indexes must be nonnegative and smaller than @nd + @np. * The first parity is represented with value @nd, the second with value * @nd + 1, just like positions in the @v vector. + * It may be 0 if @nr is 0. * @nd Number of data blocks. It must be between 1 and RAID_DATA_MAX. * @np Number of parity blocks. It must be between 1 and RAID_PARITY_MAX. * RAID_MODE_VANDERMONDE_RAID supports at most 3. * @size Size of the blocks pointed by @v. It must be a multiple of 64. + * If it is 0, the function returns -1 because no redundancy data is + * available for validation. * @v Vector of pointers to the blocks of data and parity. * It has (@nd + @np) elements. The starting elements are the blocks * for data, following with the parity blocks. @@ -350,6 +363,8 @@ int raid_check(int nr, int *ir, int nd, int np, size_t size, void **v); * @np Number of parity blocks. It must be between 0 and RAID_PARITY_MAX. * RAID_MODE_VANDERMONDE_RAID supports at most 3. * @size Size of the blocks pointed by @v. It must be a multiple of 64. + * If it is 0, the function returns -1 because no redundancy data is + * available for validation. * @v Vector of pointers to the blocks of data and parity. * It has (@nd + @np) elements. The starting elements are the blocks * for data, following with the parity blocks. diff --git a/raid/test/speedtest.c b/raid/test/speedtest.c index 1eb03a91..0d40894e 100644 --- a/raid/test/speedtest.c +++ b/raid/test/speedtest.c @@ -2134,7 +2134,7 @@ void speed(void) printf("Speed test using %u data buffers of %u bytes, for a total of %u KiB.\n", nd, size, nd * size / 1024); printf("Memory blocks have a displacement of %u bytes to improve cache performance.\n", raid_optimal_displacement(nv)); - printf("The reported values are the aggregate bandwidth of all data blocks in MiB/s,\n"); + printf("The reported values are the aggregate bandwidth of all data blocks in MB/s,\n"); printf("not counting parity blocks.\n"); printf("\n");