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

@ -1,3 +1,8 @@
2013-11-01 Vladimir Serbinenko <phcoder@gmail.com>
Rewrite blocklist functions in order to get progress when
reading large extents and decrease amount of blocklist hook calls.
2013-11-01 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/term/serial.c (options), (grub_cmd_serial): Fix handling

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 ();
}

View file

@ -285,7 +285,6 @@ grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
if (addressing == GRUB_ATA_LBA48 && ((sector + size) >> 28) != 0)
{
batch = 65536;
if (ata->dma)
{
cmd = GRUB_ATA_CMD_READ_SECTORS_DMA_EXT;
@ -301,10 +300,6 @@ grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
{
if (addressing == GRUB_ATA_LBA48)
addressing = GRUB_ATA_LBA;
if (addressing != GRUB_ATA_CHS)
batch = 256;
else
batch = 1;
if (ata->dma)
{
cmd = GRUB_ATA_CMD_READ_SECTORS_DMA;
@ -317,8 +312,10 @@ grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
}
}
if (batch > (ata->maxbuffer >> ata->log_sector_size))
batch = (ata->maxbuffer >> ata->log_sector_size);
if (addressing != GRUB_ATA_CHS)
batch = 256;
else
batch = 1;
while (nsectors < size)
{
@ -464,6 +461,10 @@ grub_ata_open (const char *name, grub_disk_t disk)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
disk->total_sectors = ata->size;
disk->max_agglomerate = (ata->maxbuffer >> (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS));
if (disk->max_agglomerate > (256U >> (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS - ata->log_sector_size)))
disk->max_agglomerate = (256U >> (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS - ata->log_sector_size));
disk->log_sector_size = ata->log_sector_size;
disk->id = grub_make_scsi_id (id, bus, 0);

View file

@ -517,6 +517,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk)
disk->data = dev;
disk->total_sectors = dev->total_length;
disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
disk->id = dev->id;
dev->ref++;
return GRUB_ERR_NONE;

View file

@ -445,6 +445,7 @@ grub_diskfilter_open (const char *name, grub_disk_t disk)
disk->data = lv;
disk->total_sectors = lv->size;
disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
return 0;
}

View file

@ -518,6 +518,8 @@ grub_efidisk_open (const char *name, struct grub_disk *disk)
grub_dprintf ("efidisk", "m = %p, last block = %llx, block size = %x\n",
m, (unsigned long long) m->last_block, m->block_size);
disk->total_sectors = m->last_block + 1;
/* Don't increase this value due to bug in some EFI. */
disk->max_agglomerate = 0xa0000 >> (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS);
if (m->block_size & (m->block_size - 1) || !m->block_size)
return grub_error (GRUB_ERR_IO, "invalid sector size %d",
m->block_size);
@ -550,24 +552,11 @@ grub_efidisk_readwrite (struct grub_disk *disk, grub_disk_addr_t sector,
d = disk->data;
bio = d->block_io;
while (size > 0)
{
grub_size_t len;
len = 0x500;
if (len > size)
len = size;
status = efi_call_5 ((wr ? bio->write_blocks : bio->read_blocks), bio,
bio->media->media_id,
(grub_efi_uint64_t) sector,
(grub_efi_uintn_t) len << disk->log_sector_size,
buf);
size -= len;
buf += len << disk->log_sector_size;
sector += len;
if (status != GRUB_EFI_SUCCESS)
return status;
}
return GRUB_EFI_SUCCESS;
return efi_call_5 ((wr ? bio->write_blocks : bio->read_blocks), bio,
bio->media->media_id,
(grub_efi_uint64_t) sector,
(grub_efi_uintn_t) size << disk->log_sector_size,
buf);
}
static grub_err_t

View file

@ -424,6 +424,9 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
}
disk->total_sectors = total_sectors;
/* Limit the max to 0x7f because of Phoenix EDD. */
disk->max_agglomerate = 0x7f >> GRUB_DISK_CACHE_BITS;
disk->data = data;
return GRUB_ERR_NONE;
@ -548,10 +551,6 @@ get_safe_sectors (grub_disk_t disk, grub_disk_addr_t sector)
size = sectors - offset;
/* Limit the max to 0x7f because of Phoenix EDD. */
if (size > ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size))
size = ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size);
return size;
}

View file

@ -167,6 +167,10 @@ grub_loopback_open (const char *name, grub_disk_t disk)
/ GRUB_DISK_SECTOR_SIZE);
else
disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN;
/* Avoid reading more than 512M. */
disk->max_agglomerate = 1 << (29 - GRUB_DISK_SECTOR_BITS
- GRUB_DISK_CACHE_BITS);
disk->id = (unsigned long) dev;
disk->data = dev;

View file

@ -46,6 +46,7 @@ grub_memdisk_open (const char *name, grub_disk_t disk)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a memdisk");
disk->total_sectors = memdisk_size / GRUB_DISK_SECTOR_SIZE;
disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
disk->id = (unsigned long) "mdsk";
return GRUB_ERR_NONE;

View file

@ -606,6 +606,13 @@ grub_scsi_open (const char *name, grub_disk_t disk)
}
disk->total_sectors = scsi->last_block + 1;
/* PATA doesn't support more than 32K reads.
Not sure about AHCI and USB. If it's confirmed that either of
them can do bigger reads reliably this value can be moved to 'scsi'
structure. */
disk->max_agglomerate = 32768 >> (GRUB_DISK_SECTOR_BITS
+ GRUB_DISK_CACHE_BITS);
if (scsi->blocksize & (scsi->blocksize - 1) || !scsi->blocksize)
{
grub_free (scsi);
@ -647,40 +654,27 @@ grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector,
scsi = disk->data;
while (size)
grub_err_t err;
/* Depending on the type, select a read function. */
switch (scsi->devtype)
{
/* PATA doesn't support more than 32K reads.
Not sure about AHCI and USB. If it's confirmed that either of
them can do bigger reads reliably this value can be moved to 'scsi'
structure. */
grub_size_t len = 32768 >> disk->log_sector_size;
grub_err_t err;
if (len > size)
len = size;
/* Depending on the type, select a read function. */
switch (scsi->devtype)
{
case grub_scsi_devtype_direct:
if (sector >> 32)
err = grub_scsi_read16 (disk, sector, len, buf);
else
err = grub_scsi_read10 (disk, sector, len, buf);
if (err)
return err;
break;
case grub_scsi_devtype_direct:
if (sector >> 32)
err = grub_scsi_read16 (disk, sector, size, buf);
else
err = grub_scsi_read10 (disk, sector, size, buf);
if (err)
return err;
break;
case grub_scsi_devtype_cdrom:
if (sector >> 32)
err = grub_scsi_read16 (disk, sector, len, buf);
else
err = grub_scsi_read12 (disk, sector, len, buf);
if (err)
return err;
break;
}
size -= len;
sector += len;
buf += len << disk->log_sector_size;
case grub_scsi_devtype_cdrom:
if (sector >> 32)
err = grub_scsi_read16 (disk, sector, size, buf);
else
err = grub_scsi_read12 (disk, sector, size, buf);
if (err)
return err;
break;
}
return GRUB_ERR_NONE;
@ -718,10 +712,10 @@ grub_scsi_read (grub_disk_t disk, grub_disk_addr_t sector,
}
static grub_err_t
grub_scsi_write (grub_disk_t disk __attribute((unused)),
grub_disk_addr_t sector __attribute((unused)),
grub_size_t size __attribute((unused)),
const char *buf __attribute((unused)))
grub_scsi_write (grub_disk_t disk,
grub_disk_addr_t sector,
grub_size_t size,
const char *buf)
{
grub_scsi_t scsi;
@ -730,31 +724,18 @@ grub_scsi_write (grub_disk_t disk __attribute((unused)),
if (scsi->devtype == grub_scsi_devtype_cdrom)
return grub_error (GRUB_ERR_IO, N_("cannot write to CD-ROM"));
while (size)
grub_err_t err;
/* Depending on the type, select a read function. */
switch (scsi->devtype)
{
/* PATA doesn't support more than 32K reads.
Not sure about AHCI and USB. If it's confirmed that either of
them can do bigger reads reliably this value can be moved to 'scsi'
structure. */
grub_size_t len = 32768 >> disk->log_sector_size;
grub_err_t err;
if (len > size)
len = size;
/* Depending on the type, select a read function. */
switch (scsi->devtype)
{
case grub_scsi_devtype_direct:
if (sector >> 32)
err = grub_scsi_write16 (disk, sector, len, buf);
else
err = grub_scsi_write10 (disk, sector, len, buf);
if (err)
return err;
break;
}
size -= len;
sector += len;
buf += len << disk->log_sector_size;
case grub_scsi_devtype_direct:
if (sector >> 32)
err = grub_scsi_write16 (disk, sector, size, buf);
else
err = grub_scsi_write10 (disk, sector, size, buf);
if (err)
return err;
break;
}
return GRUB_ERR_NONE;

View file

@ -289,6 +289,7 @@ grub_cbfsdisk_open (const char *name, grub_disk_t disk)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a cbfsdisk");
disk->total_sectors = cbfsdisk_size / GRUB_DISK_SECTOR_SIZE;
disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
disk->id = (unsigned long) "cbfs";
return GRUB_ERR_NONE;

View file

@ -199,6 +199,9 @@ grub_disk_open (const char *name)
if (! disk)
return 0;
disk->log_sector_size = GRUB_DISK_SECTOR_BITS;
/* Default 1MiB of maximum agglomerate. */
disk->max_agglomerate = 1048576 >> (GRUB_DISK_SECTOR_BITS
+ GRUB_DISK_CACHE_BITS);
p = find_part_sep (name);
if (p)
@ -311,8 +314,8 @@ grub_disk_close (grub_disk_t disk)
sector is already adjusted and is divisible by cache unit size.
*/
static grub_err_t
grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, void *buf)
grub_disk_read_small_real (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, void *buf)
{
char *data;
char *tmp_buf;
@ -389,15 +392,27 @@ grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector,
}
}
static grub_err_t
grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, void *buf)
{
grub_err_t err;
err = grub_disk_read_small_real (disk, sector, offset, size, buf);
if (err)
return err;
if (disk->read_hook)
(disk->read_hook) (sector + (offset >> GRUB_DISK_SECTOR_BITS),
offset & (GRUB_DISK_SECTOR_SIZE - 1),
size, disk->read_hook_data);
return GRUB_ERR_NONE;
}
/* Read data from the disk. */
grub_err_t
grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, void *buf)
{
grub_off_t real_offset;
grub_disk_addr_t real_sector;
grub_size_t real_size;
/* First of all, check if the region is within the disk. */
if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
{
@ -408,10 +423,6 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
return grub_errno;
}
real_sector = sector;
real_offset = offset;
real_size = size;
/* First read until first cache boundary. */
if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1)))
{
@ -446,7 +457,8 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
/* agglomerate read until we find a first cached entry. */
for (agglomerate = 0; agglomerate
< (size >> (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS));
< (size >> (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS))
&& agglomerate < disk->max_agglomerate;
agglomerate++)
{
data = grub_disk_cache_fetch (disk->dev->id, disk->id,
@ -486,6 +498,11 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
+ (i << (GRUB_DISK_CACHE_BITS
+ GRUB_DISK_SECTOR_BITS)));
if (disk->read_hook)
(disk->read_hook) (sector, 0, agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS),
disk->read_hook_data);
sector += agglomerate << GRUB_DISK_CACHE_BITS;
size -= agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS);
buf = (char *) buf
@ -494,6 +511,9 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
if (data)
{
if (disk->read_hook)
(disk->read_hook) (sector, 0, (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS),
disk->read_hook_data);
sector += GRUB_DISK_CACHE_SIZE;
buf = (char *) buf + (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
size -= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS);
@ -509,26 +529,6 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
return err;
}
/* Call the read hook, if any. */
if (disk->read_hook)
{
grub_disk_addr_t s = real_sector;
grub_size_t l = real_size;
grub_off_t o = real_offset;
while (l)
{
grub_size_t cl;
cl = GRUB_DISK_SECTOR_SIZE - o;
if (cl > l)
cl = l;
(disk->read_hook) (s, o, cl, disk->read_hook_data);
s++;
l -= cl;
o = 0;
}
}
return grub_errno;
}

View file

@ -155,6 +155,7 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
disk->total_sectors = grub_util_get_fd_size (fd, map[drive].device,
&disk->log_sector_size);
disk->total_sectors >>= disk->log_sector_size;
disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
#if GRUB_UTIL_FD_STAT_IS_FUNCTIONAL
{

View file

@ -123,6 +123,13 @@ grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
len = size & ~((1 << disk->log_sector_size) - 1);
n = size >> disk->log_sector_size;
if (n > (disk->max_agglomerate
<< (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS
- disk->log_sector_size)))
n = (disk->max_agglomerate
<< (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS
- disk->log_sector_size));
if ((disk->dev->write) (disk, transform_sector (disk, sector),
n, buf) != GRUB_ERR_NONE)
goto finish;

View file

@ -70,7 +70,7 @@ grub_install_get_blocklist (grub_device_t root_dev,
if (ioctl (fd, FS_IOC_FIEMAP, &fie1) < 0)
{
int nblocks, i, j;
int nblocks, i;
int bsize;
int mul;
@ -88,27 +88,25 @@ grub_install_get_blocklist (grub_device_t root_dev,
for (i = 0; i < nblocks; i++)
{
unsigned blk = i;
int rest;
if (ioctl (fd, FIBMAP, &blk) < 0)
grub_util_error (_("can't retrieve blocklists: %s"),
strerror (errno));
for (j = 0; j < mul; j++)
{
int rest = core_size - ((i * mul + j) << GRUB_DISK_SECTOR_BITS);
if (rest <= 0)
break;
if (rest > GRUB_DISK_SECTOR_SIZE)
rest = GRUB_DISK_SECTOR_SIZE;
callback (((grub_uint64_t) blk) * mul + j
+ container_start,
0, rest, hook_data);
}
rest = core_size - ((i * mul) << GRUB_DISK_SECTOR_BITS);
if (rest <= 0)
break;
if (rest > GRUB_DISK_SECTOR_SIZE * mul)
rest = GRUB_DISK_SECTOR_SIZE * mul;
callback (((grub_uint64_t) blk) * mul
+ container_start,
0, rest, hook_data);
}
}
else
{
struct fiemap *fie2;
int i, j;
int i;
fie2 = xmalloc (sizeof (*fie2)
+ fie1.fm_mapped_extents
* sizeof (fie1.fm_extents[1]));
@ -122,22 +120,12 @@ grub_install_get_blocklist (grub_device_t root_dev,
strerror (errno));
for (i = 0; i < fie2->fm_mapped_extents; i++)
{
for (j = 0;
j < ((fie2->fm_extents[i].fe_length
+ GRUB_DISK_SECTOR_SIZE - 1)
>> GRUB_DISK_SECTOR_BITS);
j++)
{
size_t len = (fie2->fm_extents[i].fe_length
- j * GRUB_DISK_SECTOR_SIZE);
if (len > GRUB_DISK_SECTOR_SIZE)
len = GRUB_DISK_SECTOR_SIZE;
callback ((fie2->fm_extents[i].fe_physical
>> GRUB_DISK_SECTOR_BITS)
+ j + container_start,
fie2->fm_extents[i].fe_physical
& (GRUB_DISK_SECTOR_SIZE - 1), len, hook_data);
}
callback ((fie2->fm_extents[i].fe_physical
>> GRUB_DISK_SECTOR_BITS)
+ container_start,
fie2->fm_extents[i].fe_physical
& (GRUB_DISK_SECTOR_SIZE - 1),
fie2->fm_extents[i].fe_length, hook_data);
}
}
close (fd);

View file

@ -49,7 +49,7 @@ grub_install_get_blocklist (grub_device_t root_dev,
DWORD rets;
RETRIEVAL_POINTERS_BUFFER *extbuf;
size_t extbuf_size;
DWORD i, j, k;
DWORD i;
grub_uint64_t sec_per_lcn;
grub_uint64_t curvcn = 0;
STARTING_VCN_INPUT_BUFFER start_vcn;
@ -108,12 +108,8 @@ grub_install_get_blocklist (grub_device_t root_dev,
CloseHandle (filehd);
for (i = 0; i < extbuf->ExtentCount; i++)
{
for (j = 0; j < extbuf->Extents[i].NextVcn.QuadPart - curvcn; j++)
for (k = 0; k < sec_per_lcn; k++)
callback ((extbuf->Extents[i].Lcn.QuadPart + j)
* sec_per_lcn + first_lcn
+ k, 0, 512, hook_data);
}
callback (extbuf->Extents[i].Lcn.QuadPart
* sec_per_lcn + first_lcn,
0, 512 * sec_per_lcn * (extbuf->Extents[i].NextVcn.QuadPart - curvcn), hook_data);
free (extbuf);
}

View file

@ -125,6 +125,9 @@ struct grub_disk
/* Logarithm of sector size. */
unsigned int log_sector_size;
/* Maximum number of sectors read divided by GRUB_DISK_CACHE_SIZE. */
unsigned int max_agglomerate;
/* The id used by the disk cache manager. */
unsigned long id;
@ -164,6 +167,8 @@ typedef struct grub_disk_memberlist *grub_disk_memberlist_t;
#define GRUB_DISK_CACHE_BITS 6
#define GRUB_DISK_CACHE_SIZE (1 << GRUB_DISK_CACHE_BITS)
#define GRUB_DISK_MAX_MAX_AGGLOMERATE ((1 << (30 - GRUB_DISK_CACHE_BITS - GRUB_DISK_SECTOR_BITS)) - 1)
/* Return value of grub_disk_get_size() in case disk size is unknown. */
#define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL

View file

@ -149,33 +149,40 @@ save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length,
{
struct blocklists *bl = data;
struct grub_boot_blocklist *prev = bl->block + 1;
grub_uint64_t seclen;
grub_util_info ("saving <%" PRIuGRUB_UINT64_T ",%u,%u>",
sector, offset, length);
if (bl->first_sector == (grub_disk_addr_t) -1)
{
if (offset != 0 || length != GRUB_DISK_SECTOR_SIZE)
if (offset != 0 || length < GRUB_DISK_SECTOR_SIZE)
grub_util_error ("%s", _("the first sector of the core file is not sector-aligned"));
bl->first_sector = sector;
return;
sector++;
length -= GRUB_DISK_SECTOR_SIZE;
if (!length)
return;
}
if (offset != 0 || bl->last_length != GRUB_DISK_SECTOR_SIZE)
if (offset != 0 || bl->last_length != 0)
grub_util_error ("%s", _("non-sector-aligned data is found in the core file"));
seclen = (length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS;
if (bl->block != bl->first_block
&& (grub_target_to_host64 (prev->start)
+ grub_target_to_host16 (prev->len)) == sector)
{
grub_uint16_t t = grub_target_to_host16 (prev->len) + 1;
grub_uint16_t t = grub_target_to_host16 (prev->len);
t += seclen;
prev->len = grub_host_to_target16 (t);
}
else
{
bl->block->start = grub_host_to_target64 (sector);
bl->block->len = grub_host_to_target16 (1);
bl->block->len = grub_host_to_target16 (seclen);
#ifdef GRUB_SETUP_BIOS
bl->block->segment = grub_host_to_target16 (bl->current_segment);
#endif
@ -185,9 +192,9 @@ save_blocklists (grub_disk_addr_t sector, unsigned offset, unsigned length,
grub_util_error ("%s", _("the sectors of the core file are too fragmented"));
}
bl->last_length = length;
bl->last_length = length & (GRUB_DISK_SECTOR_SIZE - 1);
#ifdef GRUB_SETUP_BIOS
bl->current_segment += GRUB_DISK_SECTOR_SIZE >> 4;
bl->current_segment += seclen << (GRUB_DISK_SECTOR_BITS - 4);
#endif
}
@ -260,7 +267,7 @@ SETUP (const char *dir,
bl.current_segment =
GRUB_BOOT_I386_PC_KERNEL_SEG + (GRUB_DISK_SECTOR_SIZE >> 4);
#endif
bl.last_length = GRUB_DISK_SECTOR_SIZE;
bl.last_length = 0;
/* Read the boot image by the OS service. */
boot_path = grub_util_get_path (dir, boot_file);
@ -731,6 +738,8 @@ unable_to_embed:
if ((char *) bl.block <= core_img)
grub_util_error ("%s", _("no terminator in the core image"));
}
if (len)
grub_util_error ("%s", _("blocklists are incomplete"));
core_dev->disk->partition = container;
free (buf);
}