qcow2: cache L1 table (speed up ~10% on my system)

This commit is contained in:
Ivan Baravy 2023-01-18 19:46:44 +00:00
parent 76c7819882
commit dd34949209
2 changed files with 29 additions and 12 deletions

6
io.c
View File

@ -25,7 +25,7 @@ io_init(int *running) {
void void
io_close(struct umka_io *io) { io_close(struct umka_io *io) {
io_async_close(io->async); io_async_close(io->async);
free(io); free(io);
} }
@ -44,8 +44,8 @@ ssize_t
io_write(int fd, const void *buf, size_t count, struct umka_io *io) { io_write(int fd, const void *buf, size_t count, struct umka_io *io) {
ssize_t res; ssize_t res;
if (!*io->running) { if (!*io->running) {
res = write(fd, buf, count); res = write(fd, buf, count);
} else { } else {
res = io_async_write(fd, buf, count, io->async); res = io_async_write(fd, buf, count, io->async);
} }
return res; return res;

View File

@ -16,6 +16,9 @@
#include "miniz/miniz.h" #include "miniz/miniz.h"
#include "io.h" #include "io.h"
#define L1_MAX_LEN (32u*1024u*1024u)
#define L1_MAX_ENTRIES (L1_MAX_LEN / sizeof(uint64_t))
struct vdisk_qcow2 { struct vdisk_qcow2 {
struct vdisk vdisk; struct vdisk vdisk;
int fd; int fd;
@ -33,6 +36,7 @@ struct vdisk_qcow2 {
off_t refcount_table_offset; off_t refcount_table_offset;
size_t l1_size; size_t l1_size;
uint64_t sector_idx_mask; uint64_t sector_idx_mask;
uint64_t *l1;
}; };
#define QCOW2_MAGIC "QFI\xfb" #define QCOW2_MAGIC "QFI\xfb"
@ -93,16 +97,8 @@ qcow2_read_guest_sector(struct vdisk_qcow2 *d, uint64_t sector, uint8_t *buf) {
uint64_t cluster_index = offset / d->cluster_size; uint64_t cluster_index = offset / d->cluster_size;
uint64_t l1_index = (cluster_index) / l2_entries; uint64_t l1_index = (cluster_index) / l2_entries;
uint64_t l2_index = (cluster_index) % l2_entries; uint64_t l2_index = (cluster_index) % l2_entries;
uint64_t l1_entry; uint64_t l1_entry = d->l1[l1_index];
uint64_t l2_entry; uint64_t l2_entry;
uint64_t l1_entry_offset = d->l1_table_offset + l1_index*sizeof(l1_entry);
lseek(d->fd, l1_entry_offset, SEEK_SET);
if (!io_read(d->fd, &l1_entry, sizeof(l1_entry), d->vdisk.io)) {
fprintf(stderr, "[vdisk.qcow2] can't read from image file: %s\n",
strerror(errno));
return;
}
l1_entry = be64(&l1_entry);
uint64_t l2_table_offset = l1_entry & L1_ENTRY_OFFSET_MASK; uint64_t l2_table_offset = l1_entry & L1_ENTRY_OFFSET_MASK;
if (!l2_table_offset) { if (!l2_table_offset) {
@ -162,6 +158,7 @@ vdisk_qcow2_close(void *userdata) {
} }
free(d->cluster); free(d->cluster);
free(d->cmp_cluster); free(d->cmp_cluster);
free(d->l1);
free(d); free(d);
COVERAGE_ON(); COVERAGE_ON();
} }
@ -306,5 +303,25 @@ vdisk_init_qcow2(const char *fname, struct umka_io *io) {
return NULL; return NULL;
} }
d->l1 = (uint64_t*)malloc(d->l1_size * sizeof(uint64_t));
if (!d->l1) {
fprintf(stderr, "[vdisk.qcow2] can't allocate memory: %s\n",
strerror(errno));
vdisk_qcow2_close(d);
return NULL;
}
lseek(d->fd, d->l1_table_offset, SEEK_SET);
if (!io_read(d->fd, d->l1, d->l1_size * sizeof(uint64_t), d->vdisk.io)) {
fprintf(stderr, "[vdisk.qcow2] can't read from image file: %s\n",
strerror(errno));
vdisk_qcow2_close(d);
return NULL;
}
for (uint64_t *x = d->l1; x < d->l1 + d->l1_size; x++) {
*x = be64(x);
}
return (struct vdisk*)d; return (struct vdisk*)d;
} }