Rewrite blocklist functions in order to get progress when
reading large extents and decrease amount of blocklist hook calls.
This commit is contained in:
parent
896f913571
commit
cb72aa1809
20 changed files with 220 additions and 181 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, §or, &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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
25
util/setup.c
25
util/setup.c
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue