Extend filesystem support for deallocation in the middle

This could happen in some special cases
This commit is contained in:
Andrea Mazzoleni 2015-10-05 22:48:16 +02:00
parent b17e618d49
commit 25fe6a252c
4 changed files with 57 additions and 7 deletions

View file

@ -227,6 +227,33 @@ if HAVE_SYMLINK
endif
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) -a check
echo -- Filesystem allocation test
head -c 8192 /dev/zero > bench/disk1/TEST
head -c 8192 /dev/zero > bench/disk2/TEST
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync
# Now delete the file, and do a partial sync to force a deallocation in the middle of a file
rm bench/disk1/TEST
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) -E -S 1 -B 1 sync
# Now force a deallocation at the end
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) -E -S 7 -B 1 sync
rm bench/disk2/TEST
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) -E sync
echo -- Filesystem fragmentation test
head -c 8192 /dev/zero > bench/disk1/TEST1
head -c 8192 /dev/zero > bench/disk1/TEST2
head -c 8192 /dev/zero > bench/disk1/TEST3
head -c 8192 /dev/zero > bench/disk1/TEST4
head -c 8192 /dev/zero > bench/disk1/TEST5
head -c 8192 /dev/zero > bench/disk1/TEST6
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync
# Now delete some files, and create a bigger one to fill the holes
rm bench/disk1/TEST1
rm bench/disk1/TEST3
rm bench/disk1/TEST5
head -c 65536 /dev/zero > bench/disk1/TESTX
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync
rm -r bench/disk1/TEST*
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) -E sync
echo --- Create some files
$(TESTENV) ./mktest$(EXEEXT) generate 1 6 $(CHECKCOUNT) $(CHECKSIZE)
echo DUP > bench/disk1/DUP1

View file

@ -1166,7 +1166,7 @@ void fs_allocate(struct snapraid_disk* disk, block_off_t parity_pos, struct snap
/* a chunk doesn't exist, and we have to create a new one */
chunk = chunk_alloc(parity_pos, file, file_pos, 1);
/* insert te chunk in the trees */
/* insert the chunk in the trees */
parity_chunk = tommy_tree_insert(&disk->fs_parity, &chunk->parity_node, chunk);
file_chunk = tommy_tree_insert(&disk->fs_file, &chunk->file_node, chunk);
@ -1184,6 +1184,10 @@ void fs_allocate(struct snapraid_disk* disk, block_off_t parity_pos, struct snap
void fs_deallocate(struct snapraid_disk* disk, block_off_t parity_pos)
{
struct snapraid_chunk* chunk;
struct snapraid_chunk* second_chunk;
struct snapraid_chunk* parity_chunk;
struct snapraid_chunk* file_chunk;
block_off_t first_count, second_count;
chunk = fs_par2chunk_get(disk, parity_pos);
if (!chunk) {
@ -1221,10 +1225,29 @@ void fs_deallocate(struct snapraid_disk* disk, block_off_t parity_pos)
return;
}
/* LCOV_EXCL_START */
log_fatal("Internal inconsistency when deallocating a chunk in the middle in disk '%s'\n", disk->name);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
/* otherwise it's in the middle */
first_count = parity_pos - chunk->parity_pos;
second_count = chunk->count - first_count - 1;
/* adjust the first chunk */
chunk->count = first_count;
/* allocate the second chunk */
second_chunk = chunk_alloc(chunk->parity_pos + first_count + 1, chunk->file, chunk->file_pos + first_count + 1, second_count);
/* insert the chunk in the trees */
parity_chunk = tommy_tree_insert(&disk->fs_parity, &second_chunk->parity_node, second_chunk);
file_chunk = tommy_tree_insert(&disk->fs_file, &second_chunk->file_node, second_chunk);
if (parity_chunk != second_chunk || file_chunk != second_chunk) {
/* LCOV_EXCL_START */
log_fatal("Internal inconsistency when splitting a chunk in disk '%s'\n", disk->name);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* store the last accessed chunk */
disk->fs_last = second_chunk;
}
struct snapraid_block* fs_par2block_get(struct snapraid_disk* disk, block_off_t parity_pos)

View file

@ -894,7 +894,7 @@ void fs_allocate(struct snapraid_disk* disk, block_off_t parity_pos, struct snap
/**
* Deallocate the parity position.
*
* After this call you can the par2file/par2block operations
* After this call the par2file/par2block operations
* won't find anymore the parity association.
*/
void fs_deallocate(struct snapraid_disk* disk, block_off_t pos);

View file

@ -1403,7 +1403,7 @@ static int position_is_required(struct snapraid_state* state, block_off_t pos)
* Checks if the info block is REQUIREQ.
*
* This is used to ensure that we keep the last check used for scrubbing.
* and the we add it when importing old context files.
* and that we add it when importing old context files.
*
* Note that you can have position without info blocks, for example
* if all the blocks are not synced.