From: "Vladimir 'φ-coder/phcoder' Serbinenko" <phcoder@gmail.com>
To: grub-devel@gnu.org
Subject: Re: Grub2 EFI: Image loading from USB takes too long
Date: Fri, 15 Apr 2011 21:54:45 +0200 [thread overview]
Message-ID: <4DA8A285.4060900@gmail.com> (raw)
In-Reply-To: <403ECF28-B18C-48DC-855A-DB28FD81AE41@oracle.com>
[-- Attachment #1: Type: text/plain, Size: 188 bytes --]
On 15.04.2011 10:18, Seth Goldberg wrote:
> This problem is present, at least, on ZFS.
Could you test the attached patch then?
--
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 4096.diff --]
[-- Type: text/x-diff; name="4096.diff", Size: 30578 bytes --]
=== modified file 'grub-core/disk/efi/efidisk.c'
--- grub-core/disk/efi/efidisk.c 2010-09-21 12:41:23 +0000
+++ grub-core/disk/efi/efidisk.c 2011-04-15 16:15:06 +0000
@@ -33,12 +33,10 @@
grub_efi_device_path_t *device_path;
grub_efi_device_path_t *last_device_path;
grub_efi_block_io_t *block_io;
- grub_efi_disk_io_t *disk_io;
struct grub_efidisk_data *next;
};
-/* GUIDs. */
-static grub_efi_guid_t disk_io_guid = GRUB_EFI_DISK_IO_GUID;
+/* GUID. */
static grub_efi_guid_t block_io_guid = GRUB_EFI_BLOCK_IO_GUID;
static struct grub_efidisk_data *fd_devices;
@@ -143,7 +141,7 @@
struct grub_efidisk_data *devices = 0;
/* Find handles which support the disk io interface. */
- handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &disk_io_guid,
+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &block_io_guid,
0, &num_handles);
if (! handles)
return 0;
@@ -155,7 +153,6 @@
grub_efi_device_path_t *ldp;
struct grub_efidisk_data *d;
grub_efi_block_io_t *bio;
- grub_efi_disk_io_t *dio;
dp = grub_efi_get_device_path (*handle);
if (! dp)
@@ -168,9 +165,7 @@
bio = grub_efi_open_protocol (*handle, &block_io_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- dio = grub_efi_open_protocol (*handle, &disk_io_guid,
- GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- if (! bio || ! dio)
+ if (! bio)
/* This should not happen... Why? */
continue;
@@ -186,7 +181,6 @@
d->device_path = dp;
d->last_device_path = ldp;
d->block_io = bio;
- d->disk_io = dio;
d->next = devices;
devices = d;
}
@@ -536,8 +530,13 @@
and total sectors should be replaced with total blocks. */
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
- * (m->block_size >> GRUB_DISK_SECTOR_BITS));
+ disk->total_sectors = m->last_block;
+ if (m->block_size & (m->block_size - 1) || !m->block_size)
+ return grub_error (GRUB_ERR_IO, "invalid sector size %d",
+ m->block_size);
+ for (disk->log_sector_size = 0;
+ (1U << disk->log_sector_size) < m->block_size;
+ disk->log_sector_size++);
disk->data = d;
grub_dprintf ("efidisk", "opening %s succeeded\n", name);
@@ -558,22 +557,20 @@
{
/* For now, use the disk io interface rather than the block io's. */
struct grub_efidisk_data *d;
- grub_efi_disk_io_t *dio;
grub_efi_block_io_t *bio;
grub_efi_status_t status;
d = disk->data;
- dio = d->disk_io;
bio = d->block_io;
grub_dprintf ("efidisk",
"reading 0x%lx sectors at the sector 0x%llx from %s\n",
(unsigned long) size, (unsigned long long) sector, disk->name);
- status = efi_call_5 (dio->read, dio, bio->media->media_id,
- (grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS,
- (grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS,
- buf);
+ status = efi_call_5 (bio->read_blocks, bio, bio->media->media_id,
+ (grub_efi_uint64_t) sector,
+ (grub_efi_uintn_t) size << disk->log_sector_size,
+ buf);
if (status != GRUB_EFI_SUCCESS)
return grub_error (GRUB_ERR_READ_ERROR, "efidisk read error");
@@ -586,21 +583,19 @@
{
/* For now, use the disk io interface rather than the block io's. */
struct grub_efidisk_data *d;
- grub_efi_disk_io_t *dio;
grub_efi_block_io_t *bio;
grub_efi_status_t status;
d = disk->data;
- dio = d->disk_io;
bio = d->block_io;
grub_dprintf ("efidisk",
"writing 0x%lx sectors at the sector 0x%llx to %s\n",
(unsigned long) size, (unsigned long long) sector, disk->name);
- status = efi_call_5 (dio->write, dio, bio->media->media_id,
- (grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS,
- (grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS,
+ status = efi_call_5 (bio->write_blocks, bio, bio->media->media_id,
+ (grub_efi_uint64_t) sector,
+ (grub_efi_uintn_t) size << disk->log_sector_size,
(void *) buf);
if (status != GRUB_EFI_SUCCESS)
return grub_error (GRUB_ERR_WRITE_ERROR, "efidisk write error");
=== modified file 'grub-core/disk/i386/pc/biosdisk.c'
--- grub-core/disk/i386/pc/biosdisk.c 2011-01-04 14:42:47 +0000
+++ grub-core/disk/i386/pc/biosdisk.c 2011-03-29 00:02:55 +0000
@@ -338,7 +338,8 @@
if ((cd_drive) && (drive == cd_drive))
{
data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM;
- data->sectors = 32;
+ data->sectors = 8;
+ disk->log_sector_size = 11;
/* TODO: get the correct size. */
total_sectors = GRUB_DISK_SIZE_UNKNOWN;
}
@@ -347,6 +348,8 @@
/* HDD */
int version;
+ disk->log_sector_size = 9;
+
version = grub_biosdisk_check_int13_extensions (drive);
if (version)
{
@@ -367,6 +370,15 @@
correctly but returns zero. So if it is zero, compute
it by C/H/S returned by the LBA BIOS call. */
total_sectors = drp->cylinders * drp->heads * drp->sectors;
+ if (drp->bytes_per_sector
+ && !(drp->bytes_per_sector & (drp->bytes_per_sector - 1))
+ && drp->bytes_per_sector >= 512
+ && drp->bytes_per_sector <= 16384)
+ {
+ for (disk->log_sector_size = 0;
+ (1 << disk->log_sector_size) < drp->bytes_per_sector;
+ disk->log_sector_size++);
+ }
}
}
}
@@ -429,7 +441,7 @@
dap = (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR
+ (data->sectors
- << GRUB_DISK_SECTOR_BITS));
+ << disk->log_sector_size));
dap->length = sizeof (*dap);
dap->reserved = 0;
dap->blocks = size;
@@ -443,9 +455,6 @@
if (cmd)
return grub_error (GRUB_ERR_WRITE_ERROR, "can\'t write to cdrom");
- dap->blocks = ALIGN_UP (dap->blocks, 4) >> 2;
- dap->block >>= 2;
-
for (i = 0; i < GRUB_BIOSDISK_CDROM_RETRY_COUNT; i++)
if (! grub_biosdisk_rw_int13_extensions (0x42, data->drive, dap))
break;
@@ -501,10 +510,12 @@
/* Return the number of sectors which can be read safely at a time. */
static grub_size_t
-get_safe_sectors (grub_disk_addr_t sector, grub_uint32_t sectors)
+get_safe_sectors (grub_disk_t disk, grub_disk_addr_t sector)
{
grub_size_t size;
grub_uint32_t offset;
+ struct grub_biosdisk_data *data = disk->data;
+ grub_uint32_t sectors = data->sectors;
/* OFFSET = SECTOR % SECTORS */
grub_divmod64 (sector, sectors, &offset);
@@ -512,8 +523,8 @@
size = sectors - offset;
/* Limit the max to 0x7f because of Phoenix EDD. */
- if (size > 0x7f)
- size = 0x7f;
+ if (size > ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size))
+ size = ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size);
return size;
}
@@ -522,21 +533,11 @@
grub_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_size_t size, char *buf)
{
- struct grub_biosdisk_data *data = disk->data;
-
while (size)
{
grub_size_t len;
- grub_size_t cdoff = 0;
-
- len = get_safe_sectors (sector, data->sectors);
-
- if (data->flags & GRUB_BIOSDISK_FLAG_CDROM)
- {
- cdoff = (sector & 3) << GRUB_DISK_SECTOR_BITS;
- len = ALIGN_UP (sector + len, 4) - (sector & ~3);
- sector &= ~3;
- }
+
+ len = get_safe_sectors (disk, sector);
if (len > size)
len = size;
@@ -545,9 +546,10 @@
GRUB_MEMORY_MACHINE_SCRATCH_SEG))
return grub_errno;
- grub_memcpy (buf, (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + cdoff),
- len << GRUB_DISK_SECTOR_BITS);
- buf += len << GRUB_DISK_SECTOR_BITS;
+ grub_memcpy (buf, (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR,
+ len << disk->log_sector_size);
+
+ buf += len << disk->log_sector_size;
sector += len;
size -= len;
}
@@ -568,18 +570,18 @@
{
grub_size_t len;
- len = get_safe_sectors (sector, data->sectors);
+ len = get_safe_sectors (disk, sector);
if (len > size)
len = size;
grub_memcpy ((void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, buf,
- len << GRUB_DISK_SECTOR_BITS);
+ len << disk->log_sector_size);
if (grub_biosdisk_rw (GRUB_BIOSDISK_WRITE, disk, sector, len,
GRUB_MEMORY_MACHINE_SCRATCH_SEG))
return grub_errno;
- buf += len << GRUB_DISK_SECTOR_BITS;
+ buf += len << disk->log_sector_size;
sector += len;
size -= len;
}
=== modified file 'grub-core/disk/scsi.c'
--- grub-core/disk/scsi.c 2011-01-22 12:22:46 +0000
+++ grub-core/disk/scsi.c 2011-03-29 00:02:55 +0000
@@ -463,15 +463,20 @@
return err;
}
- /* SCSI blocks can be something else than 512, although GRUB
- wants 512 byte blocks. */
- disk->total_sectors = ((grub_uint64_t)scsi->size
- * (grub_uint64_t)scsi->blocksize)
- >> GRUB_DISK_SECTOR_BITS;
+ disk->total_sectors = scsi->size;
+ if (scsi->blocksize & (scsi->blocksize - 1) || !scsi->blocksize)
+ {
+ grub_free (scsi);
+ return grub_error (GRUB_ERR_IO, "invalid sector size %d",
+ scsi->blocksize);
+ }
+ for (disk->log_sector_size = 0;
+ (1 << disk->log_sector_size) < scsi->blocksize;
+ disk->log_sector_size++);
grub_dprintf ("scsi", "blocks=%u, blocksize=%u\n",
scsi->size, scsi->blocksize);
- grub_dprintf ("scsi", "Disk total 512 sectors = %llu\n",
+ grub_dprintf ("scsi", "Disk total sectors = %llu\n",
(unsigned long long) disk->total_sectors);
return GRUB_ERR_NONE;
@@ -501,25 +506,6 @@
scsi = disk->data;
- /* SCSI sectors are variable in size. GRUB uses 512 byte
- sectors. */
- if (scsi->blocksize != GRUB_DISK_SECTOR_SIZE)
- {
- unsigned spb = scsi->blocksize >> GRUB_DISK_SECTOR_BITS;
- if (spb == 0 || (scsi->blocksize & (GRUB_DISK_SECTOR_SIZE - 1)) != 0)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unsupported SCSI block size");
-
- grub_uint32_t sector_mod = 0;
- sector = grub_divmod64 (sector, spb, §or_mod);
-
- if (! (sector_mod == 0 && size % spb == 0))
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unaligned SCSI read not supported");
-
- size /= spb;
- }
-
/* Depending on the type, select a read function. */
switch (scsi->devtype)
{
=== modified file 'grub-core/kern/disk.c'
--- grub-core/kern/disk.c 2010-09-20 19:45:06 +0000
+++ grub-core/kern/disk.c 2011-04-15 19:42:29 +0000
@@ -247,6 +247,7 @@
disk = (grub_disk_t) grub_zalloc (sizeof (*disk));
if (! disk)
return 0;
+ disk->log_sector_size = GRUB_DISK_SECTOR_BITS;
p = find_part_sep (name);
if (p)
@@ -266,7 +267,6 @@
if (! disk->name)
goto fail;
-
for (dev = grub_disk_dev_list; dev; dev = dev->next)
{
if ((dev->open) (raw, disk) == GRUB_ERR_NONE)
@@ -282,6 +282,14 @@
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such disk");
goto fail;
}
+ if (disk->log_sector_size > GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS
+ || disk->log_sector_size < GRUB_DISK_SECTOR_BITS)
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "sector sizes of %d bytes aren't supported yet",
+ (1 << disk->log_sector_size));
+ goto fail;
+ }
disk->dev = dev;
@@ -373,21 +381,110 @@
*sector += start;
}
- if (disk->total_sectors <= *sector
- || ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
- >> GRUB_DISK_SECTOR_BITS) > disk->total_sectors - *sector)
+ if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN
+ && ((disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) <= *sector
+ || ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1)
+ >> GRUB_DISK_SECTOR_BITS) > (disk->total_sectors
+ << (disk->log_sector_size
+ - GRUB_DISK_SECTOR_BITS)) - *sector))
return grub_error (GRUB_ERR_OUT_OF_RANGE, "out of disk");
return GRUB_ERR_NONE;
}
+static inline grub_disk_addr_t
+transform_sector (grub_disk_t disk, grub_disk_addr_t sector)
+{
+ return sector >> (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
+}
+
+/* Small read (less than cache size and not pass across cache unit boundaries).
+ 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)
+{
+ char *data;
+ char *tmp_buf;
+
+ /* Fetch the cache. */
+ data = grub_disk_cache_fetch (disk->dev->id, disk->id, sector);
+ if (data)
+ {
+ /* Just copy it! */
+ grub_memcpy (buf, data + offset, size);
+ grub_disk_cache_unlock (disk->dev->id, disk->id, sector);
+ return GRUB_ERR_NONE;
+ }
+
+ /* Allocate a temporary buffer. */
+ tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
+ if (! tmp_buf)
+ return grub_errno;
+
+ /* Otherwise read data from the disk actually. */
+ if (disk->total_sectors == GRUB_DISK_SIZE_UNKNOWN
+ || sector + GRUB_DISK_CACHE_SIZE
+ < (disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)))
+ {
+ grub_err_t err;
+ err = (disk->dev->read) (disk, transform_sector (disk, sector),
+ 1 << (GRUB_DISK_CACHE_BITS
+ + GRUB_DISK_SECTOR_BITS
+ - disk->log_sector_size), tmp_buf);
+ if (!err)
+ {
+ /* Copy it and store it in the disk cache. */
+ grub_memcpy (buf, tmp_buf + offset, size);
+ grub_disk_cache_store (disk->dev->id, disk->id,
+ sector, tmp_buf);
+ grub_free (tmp_buf);
+ return GRUB_ERR_NONE;
+ }
+ }
+
+ grub_errno = GRUB_ERR_NONE;
+
+ {
+ /* Uggh... Failed. Instead, just read necessary data. */
+ unsigned num;
+ grub_disk_addr_t aligned_sector;
+
+ sector += (offset >> GRUB_DISK_SECTOR_BITS);
+ offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1);
+ aligned_sector = (sector & ~((1 << (disk->log_sector_size
+ - GRUB_DISK_SECTOR_BITS))
+ - 1));
+ offset += ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS);
+ num = ((size + offset + (1 << (disk->log_sector_size))
+ - 1) >> (disk->log_sector_size));
+
+ tmp_buf = grub_malloc (num << disk->log_sector_size);
+ if (!tmp_buf)
+ return grub_errno;
+
+ if ((disk->dev->read) (disk, transform_sector (disk, aligned_sector),
+ num, tmp_buf))
+ {
+ grub_error_push ();
+ grub_dprintf ("disk", "%s read failed\n", disk->name);
+ grub_error_pop ();
+ return grub_errno;
+ }
+ grub_memcpy (buf, tmp_buf + offset, size);
+ 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)
{
- char *tmp_buf;
- unsigned real_offset;
+ 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)
@@ -399,126 +496,118 @@
return grub_errno;
}
+ real_sector = sector;
real_offset = offset;
-
- /* Allocate a temporary buffer. */
- tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
- if (! tmp_buf)
- return grub_errno;
-
- /* Until SIZE is zero... */
- while (size)
+ real_size = size;
+
+ /* First read until first cache boundary. */
+ if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1)))
{
- char *data;
grub_disk_addr_t start_sector;
+ grub_size_t pos;
+ grub_err_t err;
grub_size_t len;
- grub_size_t pos;
- /* For reading bulk data. */
start_sector = sector & ~(GRUB_DISK_CACHE_SIZE - 1);
pos = (sector - start_sector) << GRUB_DISK_SECTOR_BITS;
len = ((GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS)
- - pos - real_offset);
+ - pos - offset);
if (len > size)
len = size;
-
- /* Fetch the cache. */
- data = grub_disk_cache_fetch (disk->dev->id, disk->id, start_sector);
- if (data)
- {
- /* Just copy it! */
- grub_memcpy (buf, data + pos + real_offset, len);
- grub_disk_cache_unlock (disk->dev->id, disk->id, start_sector);
- }
- else
- {
- /* Otherwise read data from the disk actually. */
- if (start_sector + GRUB_DISK_CACHE_SIZE > disk->total_sectors
- || (disk->dev->read) (disk, start_sector,
- GRUB_DISK_CACHE_SIZE, tmp_buf)
- != GRUB_ERR_NONE)
- {
- /* Uggh... Failed. Instead, just read necessary data. */
- unsigned num;
- char *p;
-
- grub_errno = GRUB_ERR_NONE;
-
- num = ((size + real_offset + GRUB_DISK_SECTOR_SIZE - 1)
- >> GRUB_DISK_SECTOR_BITS);
-
- p = grub_realloc (tmp_buf, num << GRUB_DISK_SECTOR_BITS);
- if (!p)
- goto finish;
-
- tmp_buf = p;
-
- if ((disk->dev->read) (disk, sector, num, tmp_buf))
- {
- grub_error_push ();
- grub_dprintf ("disk", "%s read failed\n", disk->name);
- grub_error_pop ();
- goto finish;
- }
-
- grub_memcpy (buf, tmp_buf + real_offset, size);
-
- /* Call the read hook, if any. */
- if (disk->read_hook)
- while (size)
- {
- grub_size_t to_read = (size > GRUB_DISK_SECTOR_SIZE) ? GRUB_DISK_SECTOR_SIZE : size;
- (disk->read_hook) (sector, real_offset,
- to_read);
- if (grub_errno != GRUB_ERR_NONE)
- goto finish;
-
- sector++;
- size -= to_read - real_offset;
- real_offset = 0;
- }
-
- /* This must be the end. */
- goto finish;
- }
-
- /* Copy it and store it in the disk cache. */
- grub_memcpy (buf, tmp_buf + pos + real_offset, len);
- grub_disk_cache_store (disk->dev->id, disk->id,
- start_sector, tmp_buf);
- }
-
- /* Call the read hook, if any. */
- if (disk->read_hook)
- {
- grub_disk_addr_t s = sector;
- grub_size_t l = len;
-
- while (l)
- {
- (disk->read_hook) (s, real_offset,
- ((l > GRUB_DISK_SECTOR_SIZE)
- ? GRUB_DISK_SECTOR_SIZE
- : l));
-
- if (l < GRUB_DISK_SECTOR_SIZE - real_offset)
- break;
-
- s++;
- l -= GRUB_DISK_SECTOR_SIZE - real_offset;
- real_offset = 0;
- }
- }
-
- sector = start_sector + GRUB_DISK_CACHE_SIZE;
+ err = grub_disk_read_small (disk, start_sector,
+ offset + pos, len, buf);
+ if (err)
+ return err;
buf = (char *) buf + len;
size -= len;
- real_offset = 0;
- }
-
- finish:
-
- grub_free (tmp_buf);
+ offset += len;
+ sector += (offset >> GRUB_DISK_SECTOR_BITS);
+ offset &= ((1 << GRUB_DISK_SECTOR_BITS) - 1);
+ }
+
+ /* Until SIZE is zero... */
+ while (size >= (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS))
+ {
+ char *data = NULL;
+ grub_disk_addr_t agglomerate;
+ grub_err_t err;
+
+ /* agglomerate read until we find a first cached entry. */
+ for (agglomerate = 0; agglomerate
+ < (size >> (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS));
+ agglomerate++)
+ {
+ data = grub_disk_cache_fetch (disk->dev->id, disk->id,
+ sector + (agglomerate
+ << GRUB_DISK_CACHE_BITS));
+ if (data)
+ break;
+ }
+
+ if (agglomerate)
+ {
+ grub_disk_addr_t i;
+
+ err = (disk->dev->read) (disk, transform_sector (disk, sector),
+ agglomerate << (GRUB_DISK_CACHE_BITS
+ + GRUB_DISK_SECTOR_BITS
+ - disk->log_sector_size),
+ buf);
+ if (err)
+ return err;
+
+ for (i = 0; i < agglomerate; i ++)
+ grub_disk_cache_store (disk->dev->id, disk->id,
+ sector + (i << GRUB_DISK_CACHE_BITS),
+ (char *) buf
+ + (i << (GRUB_DISK_CACHE_BITS
+ + GRUB_DISK_SECTOR_BITS)));
+
+ sector += agglomerate << GRUB_DISK_CACHE_BITS;
+ size -= agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS);
+ buf = (char *) buf
+ + (agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS));
+ }
+
+ if (data)
+ {
+ grub_memcpy (buf, data, GRUB_DISK_CACHE_SIZE);
+ 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);
+ grub_disk_cache_unlock (disk->dev->id, disk->id,
+ sector + (agglomerate
+ << GRUB_DISK_CACHE_BITS));
+ }
+ }
+
+ /* And now read the last part. */
+ if (size)
+ {
+ grub_err_t err;
+ err = grub_disk_read_small (disk, sector, 0, size, buf);
+ if (err)
+ 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)
+ {
+ (disk->read_hook) (s, o,
+ ((l > GRUB_DISK_SECTOR_SIZE)
+ ? GRUB_DISK_SECTOR_SIZE
+ : l));
+ s++;
+ l -= GRUB_DISK_SECTOR_SIZE - o;
+ o = 0;
+ }
+ }
return grub_errno;
}
@@ -528,25 +617,31 @@
grub_off_t offset, grub_size_t size, const void *buf)
{
unsigned real_offset;
+ grub_disk_addr_t aligned_sector;
grub_dprintf ("disk", "Writing `%s'...\n", disk->name);
if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
return -1;
- real_offset = offset;
+ aligned_sector = (sector & ~((1 << (disk->log_sector_size
+ - GRUB_DISK_SECTOR_BITS)) - 1));
+ real_offset = offset + ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS);
+ sector = aligned_sector;
while (size)
{
- if (real_offset != 0 || (size < GRUB_DISK_SECTOR_SIZE && size != 0))
+ if (real_offset != 0 || (size < (1U << disk->log_sector_size)
+ && size != 0))
{
- char tmp_buf[GRUB_DISK_SECTOR_SIZE];
+ char tmp_buf[1 << disk->log_sector_size];
grub_size_t len;
grub_partition_t part;
part = disk->partition;
disk->partition = 0;
- if (grub_disk_read (disk, sector, 0, GRUB_DISK_SECTOR_SIZE, tmp_buf)
+ if (grub_disk_read (disk, sector,
+ 0, (1 << disk->log_sector_size), tmp_buf)
!= GRUB_ERR_NONE)
{
disk->partition = part;
@@ -554,7 +649,7 @@
}
disk->partition = part;
- len = GRUB_DISK_SECTOR_SIZE - real_offset;
+ len = (1 << disk->log_sector_size) - real_offset;
if (len > size)
len = size;
@@ -565,7 +660,7 @@
if ((disk->dev->write) (disk, sector, 1, tmp_buf) != GRUB_ERR_NONE)
goto finish;
- sector++;
+ sector += (1 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
buf = (char *) buf + len;
size -= len;
real_offset = 0;
@@ -575,8 +670,8 @@
grub_size_t len;
grub_size_t n;
- len = size & ~(GRUB_DISK_SECTOR_SIZE - 1);
- n = size >> GRUB_DISK_SECTOR_BITS;
+ len = size & ~((1 << disk->log_sector_size) - 1);
+ n = size >> disk->log_sector_size;
if ((disk->dev->write) (disk, sector, n, buf) != GRUB_ERR_NONE)
goto finish;
@@ -599,6 +694,8 @@
{
if (disk->partition)
return grub_partition_get_len (disk->partition);
+ else if (disk->total_sectors != GRUB_DISK_SIZE_UNKNOWN)
+ return disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
else
- return disk->total_sectors;
+ return GRUB_DISK_SIZE_UNKNOWN;
}
=== modified file 'grub-core/kern/emu/hostdisk.c'
--- grub-core/kern/emu/hostdisk.c 2011-03-26 11:59:02 +0000
+++ grub-core/kern/emu/hostdisk.c 2011-03-29 00:02:55 +0000
@@ -42,6 +42,7 @@
#ifdef __linux__
# include <sys/ioctl.h> /* ioctl */
+# include <sys/mount.h>
# if !defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
/* Maybe libc doesn't have large file support. */
@@ -264,6 +265,7 @@
# else
unsigned long long nr;
# endif
+ int sector_size;
int fd;
fd = open (map[drive].device, O_RDONLY);
@@ -295,16 +297,28 @@
goto fail;
}
+ if (ioctl (fd, BLKSSZGET, §or_size))
+ {
+ close (fd);
+ goto fail;
+ }
+
close (fd);
+ if (sector_size & (sector_size - 1) || !sector_size)
+ goto fail;
+ for (disk->log_sector_size = 0;
+ (1 << disk->log_sector_size) < sector_size;
+ disk->log_sector_size++);
+
# if defined (__APPLE__)
disk->total_sectors = nr;
# elif defined(__NetBSD__)
disk->total_sectors = label.d_secperunit;
# else
- disk->total_sectors = nr / 512;
+ disk->total_sectors = nr >> disk->log_sector_size;
- if (nr % 512)
+ if (nr & ((1 << disk->log_sector_size) - 1))
grub_util_error ("unaligned device size");
# endif
@@ -321,7 +335,7 @@
if (stat (map[drive].device, &st) < 0)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot stat `%s'", map[drive].device);
- disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS;
+ disk->total_sectors = st.st_size >> disk->log_sector_size;
grub_util_info ("the size of %s is %lu", name, disk->total_sectors);
@@ -760,7 +774,7 @@
_syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
- offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;
+ offset = (loff_t) sector << disk->log_sector_size;
if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
{
grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
@@ -770,7 +784,7 @@
}
#else
{
- off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS;
+ off_t offset = (off_t) sector << disk->log_sector_size;
if (lseek (fd, offset, SEEK_SET) != offset)
{
@@ -870,20 +884,21 @@
sectors that are read together with the MBR in one read. It
should only remap the MBR, so we split the read in two
parts. -jochen */
- if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE)
+ if (nread (fd, buf, (1 << disk->log_sector_size))
+ != (1 << disk->log_sector_size))
{
grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
close (fd);
return grub_errno;
}
- buf += GRUB_DISK_SECTOR_SIZE;
+ buf += (1 << disk->log_sector_size);
size--;
}
#endif /* __linux__ */
- if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS)
- != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
+ if (nread (fd, buf, size << disk->log_sector_size)
+ != (ssize_t) (size << disk->log_sector_size))
grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device);
return grub_errno;
@@ -916,8 +931,8 @@
if (fd < 0)
return grub_errno;
- if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS)
- != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
+ if (nwrite (fd, buf, size << disk->log_sector_size)
+ != (ssize_t) (size << disk->log_sector_size))
grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device);
return grub_errno;
=== modified file 'grub-core/partmap/msdos.c'
--- grub-core/partmap/msdos.c 2011-02-12 06:59:04 +0000
+++ grub-core/partmap/msdos.c 2011-03-29 00:02:55 +0000
@@ -90,8 +90,11 @@
{
e = mbr.entries + p.index;
- p.start = p.offset + grub_le_to_cpu32 (e->start) - delta;
- p.len = grub_le_to_cpu32 (e->length);
+ p.start = p.offset
+ + (grub_le_to_cpu32 (e->start)
+ << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) - delta;
+ p.len = grub_le_to_cpu32 (e->length)
+ << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
p.msdostype = e->type;
grub_dprintf ("partition",
@@ -126,7 +129,9 @@
if (grub_msdos_partition_is_extended (e->type))
{
- p.offset = ext_offset + grub_le_to_cpu32 (e->start);
+ p.offset = ext_offset
+ + (grub_le_to_cpu32 (e->start)
+ << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
if (! ext_offset)
ext_offset = p.offset;
@@ -204,8 +209,11 @@
e = mbr.entries + i;
if (!grub_msdos_partition_is_empty (e->type)
- && end > offset + grub_le_to_cpu32 (e->start))
- end = offset + grub_le_to_cpu32 (e->start);
+ && end > offset
+ + (grub_le_to_cpu32 (e->start)
+ << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)))
+ end = offset + (grub_le_to_cpu32 (e->start)
+ << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
/* If this is a GPT partition, this MBR is just a dummy. */
if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && i == 0)
@@ -219,7 +227,9 @@
if (grub_msdos_partition_is_extended (e->type))
{
- offset = ext_offset + grub_le_to_cpu32 (e->start);
+ offset = ext_offset
+ + (grub_le_to_cpu32 (e->start)
+ << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS));
if (! ext_offset)
ext_offset = offset;
=== modified file 'include/grub/disk.h'
--- include/grub/disk.h 2010-10-08 21:27:27 +0000
+++ include/grub/disk.h 2011-03-29 00:02:55 +0000
@@ -100,6 +100,9 @@
/* The total number of sectors. */
grub_uint64_t total_sectors;
+ /* Logarithm of sector size. */
+ unsigned int log_sector_size;
+
/* The id used by the disk cache manager. */
unsigned long id;
@@ -132,9 +135,10 @@
/* The maximum number of disk caches. */
#define GRUB_DISK_CACHE_NUM 1021
-/* The size of a disk cache in sector units. */
-#define GRUB_DISK_CACHE_SIZE 8
-#define GRUB_DISK_CACHE_BITS 3
+/* The size of a disk cache in 512B units. Must be at least as big as the
+ largest supported sector size, currently 16K. */
+#define GRUB_DISK_CACHE_BITS 6
+#define GRUB_DISK_CACHE_SIZE (1 << GRUB_DISK_CACHE_BITS)
/* Return value of grub_disk_get_size() in case disk size is unknown. */
#define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL
next prev parent reply other threads:[~2011-04-15 19:54 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-04-06 16:12 Grub2 EFI: Image loading from USB takes too long Aravind Srinivasan
2011-04-07 9:24 ` KESHAV P.R.
2011-04-08 16:33 ` Vladimir 'φ-coder/phcoder' Serbinenko
2011-04-15 2:45 ` Bean
2011-04-15 6:55 ` Vladimir 'φ-coder/phcoder' Serbinenko
2011-04-15 8:18 ` Seth Goldberg
2011-04-15 19:54 ` Vladimir 'φ-coder/phcoder' Serbinenko [this message]
2011-06-23 16:02 ` Vladimir 'φ-coder/phcoder' Serbinenko
2011-04-25 4:14 ` Bean
2011-04-25 10:58 ` Vladimir 'φ-coder/phcoder' Serbinenko
2011-04-26 3:03 ` Bean
2011-04-26 10:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
-- strict thread matches above, loose matches on Subject: below --
2011-04-15 16:07 Finnbarr P. Murphy
2011-04-05 5:33 Aravind Srinivasan
2011-04-05 6:32 ` Vladimir 'φ-coder/phcoder' Serbinenko
2011-04-05 7:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
2011-04-05 16:36 ` Aravind Srinivasan
2011-04-05 6:32 ` Seth Goldberg
2011-04-05 7:17 ` KESHAV P.R.
2011-04-05 7:43 ` Vladimir 'φ-coder/phcoder' Serbinenko
2011-04-05 8:06 ` KESHAV P.R.
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4DA8A285.4060900@gmail.com \
--to=phcoder@gmail.com \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.