diff --git a/HISTORY b/HISTORY index cc41de73..b52f0803 100644 --- a/HISTORY +++ b/HISTORY @@ -20,6 +20,8 @@ SnapRAID HISTORY * Always fill the memory after allocating it to avoid the OOM (Out Of Memory) killer in Linux. * Fixed compilation in Solaris for lacking both futimes() and futimens(). + * Now 'sync' ensures that the parity file are not too small to contains the + loaded data. 1.12 2012/9 ============= diff --git a/check.c b/check.c index 6a5f209c..29dc24a3 100644 --- a/check.c +++ b/check.c @@ -1187,6 +1187,7 @@ void state_check(struct snapraid_state* state, int check, int fix, block_off_t b { block_off_t blockmax; data_off_t size; + data_off_t out_size; int ret; struct snapraid_parity parity; struct snapraid_parity qarity; @@ -1201,7 +1202,7 @@ void state_check(struct snapraid_state* state, int check, int fix, block_off_t b exit(EXIT_FAILURE); } - blockmax = parity_resize(state); + blockmax = parity_size(state); size = blockmax * (data_off_t)state->block_size; if (blockstart > blockmax) { @@ -1218,19 +1219,31 @@ void state_check(struct snapraid_state* state, int check, int fix, block_off_t b /* if fixing, create the file and open for writing */ /* if it fails, we cannot continue */ parity_ptr = &parity; - ret = parity_create(parity_ptr, state->parity, size, 0); + ret = parity_create(parity_ptr, state->parity, &out_size); if (ret == -1) { fprintf(stderr, "WARNING! Without an accessible Parity file, it isn't possible to fix any error.\n"); exit(EXIT_FAILURE); } + ret = parity_chsize(parity_ptr, size, &out_size); + if (ret == -1) { + fprintf(stderr, "WARNING! Without an accessible Parity file, it isn't possible to sync.\n"); + exit(EXIT_FAILURE); + } + if (state->level >= 2) { qarity_ptr = &qarity; - ret = parity_create(qarity_ptr, state->qarity, size, 0); + ret = parity_create(qarity_ptr, state->qarity, &out_size); if (ret == -1) { fprintf(stderr, "WARNING! Without an accessible Q-Parity file, it isn't possible to fix any error.\n"); exit(EXIT_FAILURE); } + + ret = parity_chsize(qarity_ptr, size, &out_size); + if (ret == -1) { + fprintf(stderr, "WARNING! Without an accessible Q-Parity file, it isn't possible to sync.\n"); + exit(EXIT_FAILURE); + } } else { qarity_ptr = 0; } diff --git a/dry.c b/dry.c index a12bd221..49465166 100644 --- a/dry.c +++ b/dry.c @@ -156,7 +156,7 @@ void state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t printf("Drying...\n"); - blockmax = parity_resize(state); + blockmax = parity_size(state); if (blockstart > blockmax) { fprintf(stderr, "Error in the specified starting block %u. It's bigger than the parity size %u.\n", blockstart, blockmax); diff --git a/parity.c b/parity.c index 0954852f..c7daa43b 100644 --- a/parity.c +++ b/parity.c @@ -24,7 +24,7 @@ /****************************************************************************/ /* parity */ -block_off_t parity_resize(struct snapraid_state* state) +block_off_t parity_size(struct snapraid_state* state) { block_off_t parity_block; tommy_node* i; @@ -90,15 +90,12 @@ void parity_overflow(struct snapraid_state* state, data_off_t size) } } -int parity_create(struct snapraid_parity* parity, const char* path, data_off_t size, data_off_t* out_size) +int parity_create(struct snapraid_parity* parity, const char* path, data_off_t* out_size) { int ret; pathcpy(parity->path, sizeof(parity->path), path); - if (out_size) - *out_size = 0; - /* opening in sequential mode in Windows */ parity->f = open(parity->path, O_RDWR | O_CREAT | O_BINARY | O_SEQUENTIAL, 0600); if (parity->f == -1) { @@ -115,8 +112,20 @@ int parity_create(struct snapraid_parity* parity, const char* path, data_off_t s /* get the size of the existing data */ parity->valid_size = parity->st.st_size; - if (out_size) - *out_size = parity->st.st_size; + *out_size = parity->st.st_size; + + return 0; + +bail: + close(parity->f); + parity->f = -1; + parity->valid_size = 0; + return -1; +} + +int parity_chsize(struct snapraid_parity* parity, data_off_t size, data_off_t* out_size) +{ + int ret; if (parity->st.st_size < size) { int f_ret; @@ -158,8 +167,7 @@ int parity_create(struct snapraid_parity* parity, const char* path, data_off_t s } /* return the new size */ - if (out_size) - *out_size = parity->st.st_size; + *out_size = parity->st.st_size; /* now check the error */ if (f_ret != 0) { @@ -185,8 +193,7 @@ int parity_create(struct snapraid_parity* parity, const char* path, data_off_t s } /* return the new real size */ - if (out_size) - *out_size = parity->st.st_size; + *out_size = parity->st.st_size; /* adjust the valid to the new size */ parity->valid_size = size; @@ -204,8 +211,6 @@ int parity_create(struct snapraid_parity* parity, const char* path, data_off_t s return 0; bail: - close(parity->f); - parity->f = -1; parity->valid_size = 0; return -1; } diff --git a/parity.h b/parity.h index 29a0a198..a1c498bd 100644 --- a/parity.h +++ b/parity.h @@ -31,7 +31,7 @@ struct snapraid_parity { /** * Computes the size of the parity data in number of blocks. */ -block_off_t parity_resize(struct snapraid_state* state); +block_off_t parity_size(struct snapraid_state* state); /** * Reports all the files outside the specified parity size. @@ -40,9 +40,15 @@ void parity_overflow(struct snapraid_state* state, data_off_t size); /** * Creates the parity file. - * \param out_size Return the final size of the parity file. Returned also in error cases. + * \param out_size Return the size of the parity file. */ -int parity_create(struct snapraid_parity* parity, const char* path, data_off_t size, data_off_t* out_size); +int parity_create(struct snapraid_parity* parity, const char* path, data_off_t* out_size); + +/** + * Changes the parity size. + * \param out_size Return the size of the parity file. The out_size is set also on error to reflect a partial resize. + */ +int parity_chsize(struct snapraid_parity* parity, data_off_t size, data_off_t* out_size); /** * Opens an already existing parity file. diff --git a/state.c b/state.c index 1658153e..d06af7b8 100644 --- a/state.c +++ b/state.c @@ -44,6 +44,7 @@ void state_init(struct snapraid_state* state) tommy_list_init(&state->maplist); tommy_list_init(&state->contentlist); tommy_list_init(&state->filterlist); + state->loaded_blockmax = 0; } void state_done(struct snapraid_state* state) @@ -645,6 +646,7 @@ void state_read(struct snapraid_state* state) struct snapraid_disk* disk; struct snapraid_file* file; block_off_t blockidx; + block_off_t blockmax; unsigned line; unsigned count_file; unsigned count_block; @@ -707,6 +709,7 @@ void state_read(struct snapraid_state* state) file = 0; line = 1; blockidx = 0; + blockmax = 0; while (1) { char buffer[PATH_MAX]; @@ -748,6 +751,10 @@ void state_read(struct snapraid_state* state) exit(EXIT_FAILURE); } + /* keep track of the max block number */ + if (blockidx > blockmax) + blockmax = blockidx; + block = &file->blockvec[blockidx]; if (block->parity_pos != POS_INVALID) { @@ -1191,6 +1198,8 @@ void state_read(struct snapraid_state* state) sclose(f); + state->loaded_blockmax = blockmax; + /* update the mapping */ state_map(state); diff --git a/state.h b/state.h index 42700b06..d8bccb5f 100644 --- a/state.h +++ b/state.h @@ -51,6 +51,7 @@ struct snapraid_state { tommy_list disklist; /**< List of all the disks. */ tommy_list maplist; /**< List of all the disk mappings. */ tommy_list filterlist; /**< List of inclusion/exclusion. */ + block_off_t loaded_blockmax; /**< Previous size of the parity file, computed from the loaded state. */ time_t progress_start; /**< Start of processing for progress visualization. */ time_t progress_last; /**< Last update of progress visualization. */ time_t progress_interruption; /**< Start of the measure interruption. */ diff --git a/sync.c b/sync.c index afdb84a2..5f004cec 100644 --- a/sync.c +++ b/sync.c @@ -352,8 +352,9 @@ bail: int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t blockcount) { block_off_t blockmax; + data_off_t loaded_size; data_off_t size; - data_off_t size_after; + data_off_t out_size; tommy_node* i; int ret; struct snapraid_parity parity; @@ -364,10 +365,11 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t printf("Initializing...\n"); - blockmax = parity_resize(state); + blockmax = parity_size(state); size = blockmax * (data_off_t)state->block_size; + loaded_size = state->loaded_blockmax * (data_off_t)state->block_size; - /* remove all the deleted blocks over the upper limit */ + /* remove all the deleted blocks over the new parity size */ for(i=state->disklist;i!=0;i=i->next) { struct snapraid_disk* disk = i->data; block_off_t diskblockmax = tommy_array_size(&disk->blockarr); @@ -395,18 +397,42 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t /* create the file and open for writing */ parity_ptr = &parity; - ret = parity_create(parity_ptr, state->parity, size, &size_after); + ret = parity_create(parity_ptr, state->parity, &out_size); if (ret == -1) { - parity_overflow(state, size_after); + fprintf(stderr, "WARNING! Without an accessible Parity file, it isn't possible to sync.\n"); + exit(EXIT_FAILURE); + } + + /* if the file is too small */ + if (out_size < loaded_size) { + fprintf(stderr, "DANGER! The Parity file %s is smaller than the expected %lld.\n", state->parity, loaded_size); + exit(EXIT_FAILURE); + } + + ret = parity_chsize(parity_ptr, size, &out_size); + if (ret == -1) { + parity_overflow(state, out_size); fprintf(stderr, "WARNING! Without an accessible Parity file, it isn't possible to sync.\n"); exit(EXIT_FAILURE); } if (state->level >= 2) { qarity_ptr = &qarity; - ret = parity_create(qarity_ptr, state->qarity, size, &size_after); + ret = parity_create(qarity_ptr, state->qarity, &out_size); if (ret == -1) { - parity_overflow(state, size_after); + fprintf(stderr, "WARNING! Without an accessible Q-Parity file, it isn't possible to sync.\n"); + exit(EXIT_FAILURE); + } + + /* if the file is too small */ + if (out_size < loaded_size) { + fprintf(stderr, "DANGER! The Q-Parity file %s is smaller than the expected %lld.\n", state->qarity, loaded_size); + exit(EXIT_FAILURE); + } + + ret = parity_chsize(qarity_ptr, size, &out_size); + if (ret == -1) { + parity_overflow(state, out_size); fprintf(stderr, "WARNING! Without an accessible Q-Parity file, it isn't possible to sync.\n"); exit(EXIT_FAILURE); }