Resolve file-to-parity mappings once per extent while writing content

This commit is contained in:
Andrea Mazzoleni 2026-09-09 21:58:54 +02:00
parent 69e3a845e4
commit a1ff18fcbd
4 changed files with 82 additions and 7 deletions

View file

@ -1475,7 +1475,7 @@ struct snapraid_file* fs_par2file_find(struct snapraid_disk* disk, block_off_t p
return file;
}
block_off_t fs_file2par_find(struct snapraid_disk* disk, struct snapraid_file* file, block_off_t file_pos)
block_off_t fs_file2par_find_run(struct snapraid_disk* disk, struct snapraid_file* file, block_off_t file_pos, block_off_t* count)
{
struct snapraid_extent* extent;
block_off_t ret;
@ -1488,12 +1488,20 @@ block_off_t fs_file2par_find(struct snapraid_disk* disk, struct snapraid_file* f
return POS_NULL;
}
if (count)
*count = extent->count - (file_pos - extent->file_pos);
ret = extent->parity_pos + (file_pos - extent->file_pos);
fs_unlock(disk);
return ret;
}
block_off_t fs_file2par_find(struct snapraid_disk* disk, struct snapraid_file* file, block_off_t file_pos)
{
return fs_file2par_find_run(disk, file, file_pos, 0);
}
/**
* Allocate a run of file blocks mapping it to a run of parity positions.
*

View file

@ -1209,13 +1209,21 @@ static inline struct snapraid_file* fs_par2file_get(struct snapraid_disk* disk,
block_off_t fs_file2par_find(struct snapraid_disk* disk, struct snapraid_file* file, block_off_t file_pos);
/**
* Get the parity position from the file position.
* Get the parity position from the file position. If count is specified, return
* the number of blocks remaining in the same extent, including the current one.
* Return POS_NULL if no parity is allocated.
*/
static inline block_off_t fs_file2par_get(struct snapraid_disk* disk, struct snapraid_file* file, block_off_t file_pos)
block_off_t fs_file2par_find_run(struct snapraid_disk* disk, struct snapraid_file* file, block_off_t file_pos, block_off_t* count);
/**
* Get the parity position and the number of blocks remaining in the same extent,
* including the current one, from the file position.
*/
static inline block_off_t fs_file2par_get_run(struct snapraid_disk* disk, struct snapraid_file* file, block_off_t file_pos, block_off_t* count)
{
block_off_t ret;
ret = fs_file2par_find(disk, file, file_pos);
ret = fs_file2par_find_run(disk, file, file_pos, count);
if (ret == POS_NULL) {
/* LCOV_EXCL_START */
log_fatal(EINTERNAL, "Internal inconsistency: Resolving file '%s' at position '%" PRIu64 "/%" PRIu64 "' in disk '%s'\n", file->sub, file_pos, file->blockmax, disk->name);
@ -1226,6 +1234,14 @@ static inline block_off_t fs_file2par_get(struct snapraid_disk* disk, struct sna
return ret;
}
/**
* Get the parity position from the file position.
*/
static inline block_off_t fs_file2par_get(struct snapraid_disk* disk, struct snapraid_file* file, block_off_t file_pos)
{
return fs_file2par_get_run(disk, file, file_pos, 0);
}
/**
* Get the block from the parity position.
* Return BLOCK_NULL==0 if the block is over the end of the disk or not used.

View file

@ -1852,6 +1852,42 @@ static void test_stream(void)
}
}
static void test_extent_run(void)
{
struct snapraid_disk* disk;
struct snapraid_file* file;
block_off_t parity_pos;
block_off_t count;
disk = disk_alloc("test", "", 0, "", 0);
file = file_alloc(4096, "file", 6 * 4096, 0, 0, 0);
fs_allocate(disk, 10, file, 0, 3);
fs_allocate(disk, 20, file, 3, 2);
fs_allocate(disk, 22, file, 5, 1);
parity_pos = fs_file2par_get_run(disk, file, 0, &count);
if (parity_pos != 10 || count != 3) {
log_fatal(EINTERNAL, "test_extent_run: first extent failed\n");
exit(EXIT_FAILURE);
}
parity_pos = fs_file2par_get_run(disk, file, 1, &count);
if (parity_pos != 11 || count != 2) {
log_fatal(EINTERNAL, "test_extent_run: extent remainder failed\n");
exit(EXIT_FAILURE);
}
parity_pos = fs_file2par_get_run(disk, file, 3, &count);
if (parity_pos != 20 || count != 3) {
log_fatal(EINTERNAL, "test_extent_run: extended extent failed\n");
exit(EXIT_FAILURE);
}
disk_free(disk);
file_free(file);
}
static void test_raid(void)
{
/* vandermonde raid parity generation with 32 data disks */
@ -2551,6 +2587,9 @@ void test(int argc, char* argv[])
/* buffered streaming i/o and crc verification */
test_stream();
/* extent-aware file-to-parity run lookup */
test_extent_run();
/* wildcard and path pattern matching */
test_wnmatch();

View file

@ -4161,7 +4161,9 @@ static void* state_write_thread(void* arg)
struct snapraid_block* block = file_block(file, begin);
unsigned char* end_block_ptr = (unsigned char*)block + block_stride;
unsigned v_state = block_state_get(block);
block_off_t v_pos = fs_file2par_get(disk, file, begin);
block_off_t extent_count;
block_off_t v_pos = fs_file2par_get_run(disk, file, begin, &extent_count);
block_off_t extent_end = begin + extent_count;
block_off_t v_count;
block_off_t end;
@ -4172,8 +4174,18 @@ static void* state_write_thread(void* arg)
block = (struct snapraid_block*)end_block_ptr;
if (v_state != block_state_get(block))
break;
if (v_pos + (end - begin) != fs_file2par_get(disk, file, end))
break;
/* Resolve the mapping only when crossing an extent boundary. */
if (end == extent_end) {
block_off_t next_count;
block_off_t next_pos = fs_file2par_get_run(disk, file, end, &next_count);
if (v_pos + (end - begin) != next_pos)
break;
extent_end += next_count;
}
end_block_ptr += block_stride;
++end;
}