From 36b20e5d0e8edf6b7d924404c18e345593155dab Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Mon, 27 Oct 2025 15:55:13 +0100 Subject: [PATCH] Explain the internal functionality of the IO system --- cmdline/io.c | 2 +- cmdline/io.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/cmdline/io.c b/cmdline/io.c index 7e870ba6..e18c7694 100644 --- a/cmdline/io.c +++ b/cmdline/io.c @@ -823,7 +823,7 @@ static void io_start_thread(struct snapraid_io* io, io->block_next = blockstart; io->done = 0; - io->reader_index = io->io_max - 1; + io->reader_index = io->io_max - 1; /* the first io_read_next() is going to set it to 0 */ io->writer_index = 0; /* clear writer errors */ diff --git a/cmdline/io.h b/cmdline/io.h index ef07ae5b..c9cd816d 100644 --- a/cmdline/io.h +++ b/cmdline/io.h @@ -129,10 +129,71 @@ struct snapraid_worker { #define IO_WRITER_ERROR_MAX (-IO_WRITER_ERROR_BASE) /** - * Reader. + * IO system that handle all parallel reads and writes. * - * This represents the pool of worker threads dedicated to read + * This represents the pool of worker threads dedicated to read and write * data from the disks. + * + * Typycal scenario is: + * + * # Initialize the process + * io_start(&io, blockstart, blockmax, block_enabled); + * + * for_each_block { + * # Now read starts + * # Get the current block to process and the vector of data buffers to use + * # buffer[0..diskmax-1] are data disks + * # buffer[diskmax..diskmax+levelmax-1] are parity disks + * # + * # INTERNAL: Broadcast a read_sched signal, to signal worker threads + * # that the previous "blockcur" position is now available and the + * # buffers can be used to read a new look-ahead position. + * unsigned blockcur = io_read_next(&io, &buffer); + * + * for_each_disk { + * # Read a disk into buffer[diskcur] + * # diskcur is the disk processed, and it may came in random order + * # depending on which disk is faster + * # + * # INTERNAL: It may wait for the read_done condition in case + * # the read is not yet done. + * # The reader thread will set the condition when ready. + * struct snapraid_task* task = io_data_read(&io, &diskcur, waiting_map, &waiting_mac); + * + * # compute the hash + * ... + * } + * + * # compute the parity + * ... + * + * # Now write starts + * # At this point the parity data should ALREADY be in the buffer[diskmax+levcur] + * # Note that the only reason that the process is separated for each parity + * # is to allow to identify which is the latest and slowest disk + * io_write_preset(&io, blockcur, !parity_going_to_be_updated); + * + * for_each_parity { + * unsigned levcur; + * + * # Write a parity from buffer[diskmax+levcur] + * # levcur is the disk processed, and it may came in random order + * # depending on which disk is faster + * # + * # INTERNAL: It may wait for the write_done condition in case + * # there isn't a free position in the parity write queue. + * # The writer thread will set the condition when ready. + * io_parity_write(&io, &levcur, waiting_map, &waiting_mac); + * } + * + * # End of the write + * # INTERNAL: Broadcast a write_sched signal, to signal worker threads + * # that a new position is ready to be written + * io_write_next(&io, blockcur, !parity_going_to_be_updated, writer_error); + * } + * + * # Stop all thread after writing all queued data + * io_stop(&io); */ struct snapraid_io { struct snapraid_state* state;