Rewrite blocklist functions in order to get progress when

reading large extents and decrease amount of blocklist hook calls.
This commit is contained in:
Vladimir Serbinenko 2013-11-01 23:28:03 +01:00
parent 896f913571
commit cb72aa1809
20 changed files with 220 additions and 181 deletions

View file

@ -62,23 +62,47 @@ read_blocklist (grub_disk_addr_t sector, unsigned offset, unsigned length,
if (ctx->num_sectors > 0)
{
if (ctx->start_sector + ctx->num_sectors == sector
&& offset == 0 && length == GRUB_DISK_SECTOR_SIZE)
&& offset == 0 && length >= GRUB_DISK_SECTOR_SIZE)
{
ctx->num_sectors++;
return;
ctx->num_sectors += length >> GRUB_DISK_SECTOR_BITS;
sector += length >> GRUB_DISK_SECTOR_BITS;
length &= (GRUB_DISK_SECTOR_SIZE - 1);
}
if (!length)
return;
print_blocklist (ctx->start_sector, ctx->num_sectors, 0, 0, ctx);
ctx->num_sectors = 0;
}
if (offset == 0 && length == GRUB_DISK_SECTOR_SIZE)
if (offset)
{
ctx->start_sector = sector;
ctx->num_sectors++;
unsigned l = length + offset;
l &= (GRUB_DISK_SECTOR_SIZE - 1);
l -= offset;
print_blocklist (sector, 0, offset, l, ctx);
length -= l;
sector++;
offset = 0;
}
if (!length)
return;
if (length & (GRUB_DISK_SECTOR_SIZE - 1))
{
if (length >> GRUB_DISK_SECTOR_BITS)
{
print_blocklist (sector, length >> GRUB_DISK_SECTOR_BITS, 0, 0, ctx);
sector += length >> GRUB_DISK_SECTOR_BITS;
}
print_blocklist (sector, 0, 0, length & (GRUB_DISK_SECTOR_SIZE - 1), ctx);
}
else
print_blocklist (sector, 0, offset, length, ctx);
{
ctx->start_sector = sector;
ctx->num_sectors = length >> GRUB_DISK_SECTOR_BITS;
}
}
static grub_err_t

View file

@ -259,10 +259,28 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
for (p = blocklists; p; p = p->next)
{
struct blocklist *q;
/* Check if any pair of blocks overlap. */
for (q = p->next; q; q = q->next)
{
/* Check if any pair of blocks overlap. */
if (p->sector == q->sector)
grub_disk_addr_t s1, s2;
grub_disk_addr_t e1, e2, t;
s1 = p->sector;
e1 = s1 + ((p->length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
s2 = q->sector;
e2 = s2 + ((q->length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
if (s2 > s1)
{
t = s2;
s2 = s1;
s1 = t;
t = e2;
e2 = e1;
e1 = t;
}
if (e1 > s2)
{
/* This might be actually valid, but it is unbelievable that
any filesystem makes such a silly allocation. */
@ -286,9 +304,18 @@ check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
part_start = grub_partition_get_start (disk->partition);
buf = grub_envblk_buffer (envblk);
char *blockbuf = NULL;
grub_size_t blockbuf_len = 0;
for (p = blocklists, index = 0; p; index += p->length, p = p->next)
{
char blockbuf[GRUB_DISK_SECTOR_SIZE];
if (p->length > blockbuf_len)
{
grub_free (blockbuf);
blockbuf_len = 2 * p->length;
blockbuf = grub_malloc (blockbuf_len);
if (!blockbuf)
return grub_errno;
}
if (grub_disk_read (disk, p->sector - part_start,
p->offset, p->length, blockbuf))
@ -340,10 +367,6 @@ save_env_read_hook (grub_disk_addr_t sector, unsigned offset, unsigned length,
struct grub_cmd_save_env_ctx *ctx = data;
struct blocklist *block;
if (offset + length > GRUB_DISK_SECTOR_SIZE)
/* Seemingly a bug. */
return;
block = grub_malloc (sizeof (*block));
if (! block)
return;

View file

@ -35,10 +35,13 @@ GRUB_MOD_LICENSE ("GPLv3+");
static void
read_progress (grub_disk_addr_t sector __attribute__ ((unused)),
unsigned offset __attribute__ ((unused)),
unsigned len __attribute__ ((unused)),
unsigned len,
void *data __attribute__ ((unused)))
{
grub_xputs (".");
for (; len >= GRUB_DISK_SECTOR_SIZE; len -= GRUB_DISK_SECTOR_SIZE)
grub_xputs (".");
if (len)
grub_xputs (".");
grub_refresh ();
}