diff --git a/cmdline/io.c b/cmdline/io.c index 4e1c7b77..f4c085ca 100644 --- a/cmdline/io.c +++ b/cmdline/io.c @@ -274,14 +274,20 @@ static struct snapraid_task* io_reader_step(struct snapraid_worker* worker) * * This is the synchronization point for workers with the io. */ -static struct snapraid_task* io_writer_step(struct snapraid_worker* worker) +static struct snapraid_task* io_writer_step(struct snapraid_worker* worker, int state) { struct snapraid_io* io = worker->io; struct snapraid_task* task = 0; + int error_index; /* the synchronization is protected by the io mutex */ pthread_mutex_lock(&io->mutex); + /* counts the number of errors in the global state */ + error_index = state - IO_WRITER_ERROR_BASE; + if (error_index >= 0 && error_index < IO_WRITER_ERROR_MAX) + ++io->writer_error[error_index]; + while (1) { unsigned index; @@ -359,7 +365,7 @@ block_off_t io_read_next(struct snapraid_io* io, void*** buffer) return blockcur_caller; } -void io_write_next(struct snapraid_io* io, unsigned blockcur, int skip) +void io_write_next(struct snapraid_io* io, unsigned blockcur, int skip, int* writer_error) { unsigned i; @@ -373,6 +379,12 @@ void io_write_next(struct snapraid_io* io, unsigned blockcur, int skip) /* the synchronization is protected by the io mutex */ pthread_mutex_lock(&io->mutex); + /* report errors */ + for (i = 0; i < IO_WRITER_ERROR_MAX; ++i) { + writer_error[i] = io->writer_error[i]; + io->writer_error[i] = 0; + } + if (skip) { /* skip the next write */ io_writer_sched_empty(io, io->writer_index, blockcur); @@ -554,28 +566,35 @@ static void* io_reader_thread(void* arg) return 0; } + static void* io_writer_thread(void* arg) { struct snapraid_worker* worker = arg; + int latest_state = TASK_STATE_DONE; while (1) { struct snapraid_task* task; /* get the new task */ - task = io_writer_step(worker); + task = io_writer_step(worker, latest_state); /* if no task, it means to exit */ if (!task) break; /* nothing more to do */ - if (task->state == TASK_STATE_EMPTY) + if (task->state == TASK_STATE_EMPTY) { + latest_state = TASK_STATE_DONE; continue; + } assert(task->state == TASK_STATE_READY); /* work on the assigned task */ worker->func(worker, task); + + /* save the resulting state */ + latest_state = task->state; } return 0; @@ -597,6 +616,10 @@ void io_start(struct snapraid_io* io, io->reader_index = IO_MAX - 1; io->writer_index = 0; + /* clear writer errors */ + for (i = 0; i < IO_WRITER_ERROR_MAX; ++i) + io->writer_error[i] = 0; + /* setup the initial read pending tasks, except the latest one, */ /* the latest will be initialized at the fist io_read_next() call */ for (i = 0; i < IO_MAX - 1; ++i) { diff --git a/cmdline/io.h b/cmdline/io.h index da240a87..6ecf7eff 100644 --- a/cmdline/io.h +++ b/cmdline/io.h @@ -120,6 +120,12 @@ struct snapraid_worker { unsigned buffer_skew; }; +/** + * Number of error kind for writers. + */ +#define IO_WRITER_ERROR_BASE TASK_STATE_IOERROR_CONTINUE +#define IO_WRITER_ERROR_MAX (-IO_WRITER_ERROR_BASE) + /** * Reader. * @@ -258,6 +264,11 @@ struct snapraid_io { * it's incremented, and a write_sched() signal is sent. */ unsigned writer_index; + + /** + * Counts the error happening in the writers. + */ + int writer_error[IO_WRITER_ERROR_MAX]; }; /** @@ -343,7 +354,8 @@ void io_parity_write(struct snapraid_io* io, unsigned* levcur); * \param io InputOutput context. * \param blockcur The parity position to write. * \param skip Skip the writes, in case parity doesn't need to be updated. + * \param writer_error Return the number of errors. Vector of IO_WRITER_ERROR_MAX elements. */ -void io_write_next(struct snapraid_io* io, unsigned blockcur, int skip); +void io_write_next(struct snapraid_io* io, unsigned blockcur, int skip, int* writer_error); #endif diff --git a/cmdline/sync.c b/cmdline/sync.c index 6f4b7c79..b3923cfd 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -747,6 +747,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari snapraid_info info; int rehash; void** buffer; + int writer_error[IO_WRITER_ERROR_MAX]; /* go to the next block */ blockcur = io_read_next(&io, &buffer); @@ -1193,7 +1194,32 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari } /* write finished */ - io_write_next(&io, blockcur, !parity_going_to_be_updated); + io_write_next(&io, blockcur, !parity_going_to_be_updated, writer_error); + + /* handle errors reported */ + for (j = 0; j < IO_WRITER_ERROR_MAX; ++j) { + if (writer_error[j]) { + switch (j + IO_WRITER_ERROR_BASE) { + case TASK_STATE_IOERROR_CONTINUE : + ++io_error; + if (io_error >= state->opt.io_error_limit) { + log_fatal("DANGER! Unexpected input/output write error in a parity disk, it isn't possible to sync.\n"); + log_fatal("Stopping at block %u\n", blockcur); + goto bail; + } + break; + case TASK_STATE_ERROR_CONTINUE : + ++error; + break; + case TASK_STATE_IOERROR : + ++io_error; + goto bail; + case TASK_STATE_ERROR : + ++error; + goto bail; + } + } + } /* mark the state as needing write */ state->need_write = 1;