From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1QAp6W-0000ZR-V2 for mharc-grub-devel@gnu.org; Fri, 15 Apr 2011 15:54:56 -0400 Received: from eggs.gnu.org ([140.186.70.92]:47066) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QAp6T-0000ZI-T9 for grub-devel@gnu.org; Fri, 15 Apr 2011 15:54:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QAp6R-0000CN-E4 for grub-devel@gnu.org; Fri, 15 Apr 2011 15:54:53 -0400 Received: from mail-ww0-f49.google.com ([74.125.82.49]:39636) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QAp6Q-0000C7-VE for grub-devel@gnu.org; Fri, 15 Apr 2011 15:54:51 -0400 Received: by wwb39 with SMTP id 39so3100724wwb.30 for ; Fri, 15 Apr 2011 12:54:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:message-id:date:from:user-agent:mime-version:to :subject:references:in-reply-to:x-enigmail-version:content-type; bh=OVWg4g/ko40PjIybDF5nX7mWAxaCyNQQpoS6ZbMFH9g=; b=H9h2ISY08LX3cltP7yfq4Lfna+bu2Rey1WOCxCen7obSfljFJDROJ2kwnKe6IJs8Xr IMvIkgW5u6//1u6+MP1NNSvtsbd/wGZHe10flS9wQuhqysOQbxt6tGraFY/8E3kJFclt 8h2NSVuI4+7lyRPRfUC2CHbxLi7PmvIncc8wQ= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:x-enigmail-version:content-type; b=cVWvbQIrZp/wRS8tWfkNXta/AONOWMUg1IgGU0NlSdbjm4E8IOaSvQ9RYEQoP7IrHw 4NkvU9VPFiGXF8+BcYn0u7mY9YRXrLhm55hzbiec/ZogbJBrsY0dQAgoLPsbxGyX32HV 5poxdouhUyJ1VntemSY0xDdllIM7mCp7IzQ4Q= Received: by 10.216.244.71 with SMTP id l49mr8164669wer.13.1302897289943; Fri, 15 Apr 2011 12:54:49 -0700 (PDT) Received: from debian.x201.phnet (gprs09.swisscom-mobile.ch [193.247.250.9]) by mx.google.com with ESMTPS id n2sm1471637wej.46.2011.04.15.12.54.46 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 15 Apr 2011 12:54:47 -0700 (PDT) Message-ID: <4DA8A285.4060900@gmail.com> Date: Fri, 15 Apr 2011 21:54:45 +0200 From: =?UTF-8?B?VmxhZGltaXIgJ8+GLWNvZGVyL3BoY29kZXInIFNlcmJpbmVua28=?= User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.15) Gecko/20110402 Iceowl/1.0b2 Icedove/3.1.9 MIME-Version: 1.0 To: grub-devel@gnu.org Subject: Re: Grub2 EFI: Image loading from USB takes too long References: <775884.3554.qm@web120005.mail.ne1.yahoo.com> <4D9F38C9.3090203@gmail.com> <4DA7EBF3.8090007@gmail.com> <403ECF28-B18C-48DC-855A-DB28FD81AE41@oracle.com> In-Reply-To: <403ECF28-B18C-48DC-855A-DB28FD81AE41@oracle.com> X-Enigmail-Version: 1.1.2 Content-Type: multipart/mixed; boundary="------------080203040305020801090609" X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 74.125.82.49 X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 15 Apr 2011 19:54:56 -0000 This is a multi-part message in MIME format. --------------080203040305020801090609 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable On 15.04.2011 10:18, Seth Goldberg wrote: > This problem is present, at least, on ZFS. Could you test the attached patch then? --=20 Regards Vladimir '=CF=86-coder/phcoder' Serbinenko --------------080203040305020801090609 Content-Type: text/x-diff; name="4096.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="4096.diff" =3D=3D=3D 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; }; =20 -/* GUIDs. */ -static grub_efi_guid_t disk_io_guid =3D GRUB_EFI_DISK_IO_GUID; +/* GUID. */ static grub_efi_guid_t block_io_guid =3D GRUB_EFI_BLOCK_IO_GUID; =20 static struct grub_efidisk_data *fd_devices; @@ -143,7 +141,7 @@ struct grub_efidisk_data *devices =3D 0; =20 /* Find handles which support the disk io interface. */ - handles =3D grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &disk_io_gui= d, + handles =3D grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &block_io_gu= id, 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; =20 dp =3D grub_efi_get_device_path (*handle); if (! dp) @@ -168,9 +165,7 @@ =20 bio =3D grub_efi_open_protocol (*handle, &block_io_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); - dio =3D 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; =20 @@ -186,7 +181,6 @@ d->device_path =3D dp; d->last_device_path =3D ldp; d->block_io =3D bio; - d->disk_io =3D dio; d->next =3D devices; devices =3D d; } @@ -536,8 +530,13 @@ and total sectors should be replaced with total blocks. */ grub_dprintf ("efidisk", "m =3D %p, last block =3D %llx, block size =3D= %x\n", m, (unsigned long long) m->last_block, m->block_size); - disk->total_sectors =3D (m->last_block - * (m->block_size >> GRUB_DISK_SECTOR_BITS)); + disk->total_sectors =3D 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 =3D 0; + (1U << disk->log_sector_size) < m->block_size; + disk->log_sector_size++); disk->data =3D d; =20 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; =20 d =3D disk->data; - dio =3D d->disk_io; bio =3D d->block_io; =20 grub_dprintf ("efidisk", "reading 0x%lx sectors at the sector 0x%llx from %s\n", (unsigned long) size, (unsigned long long) sector, disk->name); =20 - status =3D 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 =3D 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 !=3D GRUB_EFI_SUCCESS) return grub_error (GRUB_ERR_READ_ERROR, "efidisk read error"); =20 @@ -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; =20 d =3D disk->data; - dio =3D d->disk_io; bio =3D d->block_io; =20 grub_dprintf ("efidisk", "writing 0x%lx sectors at the sector 0x%llx to %s\n", (unsigned long) size, (unsigned long long) sector, disk->name); =20 - status =3D 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 =3D 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 !=3D GRUB_EFI_SUCCESS) return grub_error (GRUB_ERR_WRITE_ERROR, "efidisk write error"); =3D=3D=3D 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 =3D=3D cd_drive)) { data->flags =3D GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM;= - data->sectors =3D 32; + data->sectors =3D 8; + disk->log_sector_size =3D 11; /* TODO: get the correct size. */ total_sectors =3D GRUB_DISK_SIZE_UNKNOWN; } @@ -347,6 +348,8 @@ /* HDD */ int version; =20 + disk->log_sector_size =3D 9; + version =3D 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 =3D drp->cylinders * drp->heads * drp->sec= tors; + if (drp->bytes_per_sector + && !(drp->bytes_per_sector & (drp->bytes_per_sector - 1)) + && drp->bytes_per_sector >=3D 512 + && drp->bytes_per_sector <=3D 16384) + { + for (disk->log_sector_size =3D 0; + (1 << disk->log_sector_size) < drp->bytes_per_sector; + disk->log_sector_size++); + } } } } @@ -429,7 +441,7 @@ =20 dap =3D (struct grub_biosdisk_dap *) (GRUB_MEMORY_MACHINE_SCRATCH_= ADDR + (data->sectors - << GRUB_DISK_SECTOR_BITS)); + << disk->log_sector_size)); dap->length =3D sizeof (*dap); dap->reserved =3D 0; dap->blocks =3D size; @@ -443,9 +455,6 @@ if (cmd) return grub_error (GRUB_ERR_WRITE_ERROR, "can\'t write to cdrom"); =20 - dap->blocks =3D ALIGN_UP (dap->blocks, 4) >> 2; - dap->block >>=3D 2; - for (i =3D 0; i < GRUB_BIOSDISK_CDROM_RETRY_COUNT; i++) if (! grub_biosdisk_rw_int13_extensions (0x42, data->drive, = dap)) break; @@ -501,10 +510,12 @@ =20 /* 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 =3D disk->data; + grub_uint32_t sectors =3D data->sectors; =20 /* OFFSET =3D SECTOR % SECTORS */ grub_divmod64 (sector, sectors, &offset); @@ -512,8 +523,8 @@ size =3D sectors - offset; =20 /* Limit the max to 0x7f because of Phoenix EDD. */ - if (size > 0x7f) - size =3D 0x7f; + if (size > ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size)= ) + size =3D ((0x7fU << GRUB_DISK_SECTOR_BITS) >> disk->log_sector_size)= ; =20 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 =3D disk->data; - while (size) { grub_size_t len; - grub_size_t cdoff =3D 0; - - len =3D get_safe_sectors (sector, data->sectors); - - if (data->flags & GRUB_BIOSDISK_FLAG_CDROM) - { - cdoff =3D (sector & 3) << GRUB_DISK_SECTOR_BITS; - len =3D ALIGN_UP (sector + len, 4) - (sector & ~3); - sector &=3D ~3; - } + + len =3D get_safe_sectors (disk, sector); =20 if (len > size) len =3D size; @@ -545,9 +546,10 @@ GRUB_MEMORY_MACHINE_SCRATCH_SEG)) return grub_errno; =20 - grub_memcpy (buf, (void *) (GRUB_MEMORY_MACHINE_SCRATCH_ADDR + cdo= ff), - len << GRUB_DISK_SECTOR_BITS); - buf +=3D len << GRUB_DISK_SECTOR_BITS; + grub_memcpy (buf, (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, + len << disk->log_sector_size); + + buf +=3D len << disk->log_sector_size; sector +=3D len; size -=3D len; } @@ -568,18 +570,18 @@ { grub_size_t len; =20 - len =3D get_safe_sectors (sector, data->sectors); + len =3D get_safe_sectors (disk, sector); if (len > size) len =3D size; =20 grub_memcpy ((void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR, buf, - len << GRUB_DISK_SECTOR_BITS); + len << disk->log_sector_size); =20 if (grub_biosdisk_rw (GRUB_BIOSDISK_WRITE, disk, sector, len, GRUB_MEMORY_MACHINE_SCRATCH_SEG)) return grub_errno; =20 - buf +=3D len << GRUB_DISK_SECTOR_BITS; + buf +=3D len << disk->log_sector_size; sector +=3D len; size -=3D len; } =3D=3D=3D 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; } =20 - /* SCSI blocks can be something else than 512, although GRUB - wants 512 byte blocks. */ - disk->total_sectors =3D ((grub_uint64_t)scsi->size - * (grub_uint64_t)scsi->blocksize) - >> GRUB_DISK_SECTOR_BITS; + disk->total_sectors =3D 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 =3D 0; + (1 << disk->log_sector_size) < scsi->blocksize; + disk->log_sector_size++); =20 grub_dprintf ("scsi", "blocks=3D%u, blocksize=3D%u\n", scsi->size, scsi->blocksize); - grub_dprintf ("scsi", "Disk total 512 sectors =3D %llu\n", + grub_dprintf ("scsi", "Disk total sectors =3D %llu\n", (unsigned long long) disk->total_sectors); =20 return GRUB_ERR_NONE; @@ -501,25 +506,6 @@ =20 scsi =3D disk->data; =20 - /* SCSI sectors are variable in size. GRUB uses 512 byte - sectors. */ - if (scsi->blocksize !=3D GRUB_DISK_SECTOR_SIZE) - { - unsigned spb =3D scsi->blocksize >> GRUB_DISK_SECTOR_BITS; - if (spb =3D=3D 0 || (scsi->blocksize & (GRUB_DISK_SECTOR_SIZE - 1)= ) !=3D 0) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unsupported SCSI block size"); - - grub_uint32_t sector_mod =3D 0; - sector =3D grub_divmod64 (sector, spb, §or_mod); - - if (! (sector_mod =3D=3D 0 && size % spb =3D=3D 0)) - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "unaligned SCSI read not supported"); - - size /=3D spb; - } - /* Depending on the type, select a read function. */ switch (scsi->devtype) { =3D=3D=3D 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 =3D (grub_disk_t) grub_zalloc (sizeof (*disk)); if (! disk) return 0; + disk->log_sector_size =3D GRUB_DISK_SECTOR_BITS; =20 p =3D find_part_sep (name); if (p) @@ -266,7 +267,6 @@ if (! disk->name) goto fail; =20 - for (dev =3D grub_disk_dev_list; dev; dev =3D dev->next) { if ((dev->open) (raw, disk) =3D=3D 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_BI= TS + || 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; + } =20 disk->dev =3D dev; =20 @@ -373,21 +381,110 @@ *sector +=3D start; } =20 - if (disk->total_sectors <=3D *sector - || ((*offset + size + GRUB_DISK_SECTOR_SIZE - 1) - >> GRUB_DISK_SECTOR_BITS) > disk->total_sectors - *sector) + if (disk->total_sectors !=3D GRUB_DISK_SIZE_UNKNOWN + && ((disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SEC= TOR_BITS)) <=3D *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"); =20 return GRUB_ERR_NONE; } =20 +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 bound= aries). + 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 =3D 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 =3D 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 =3D=3D GRUB_DISK_SIZE_UNKNOWN + || sector + GRUB_DISK_CACHE_SIZE + < (disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTO= R_BITS))) + { + grub_err_t err; + err =3D (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 =3D GRUB_ERR_NONE; + + { + /* Uggh... Failed. Instead, just read necessary data. */ + unsigned num; + grub_disk_addr_t aligned_sector; + + sector +=3D (offset >> GRUB_DISK_SECTOR_BITS); + offset &=3D ((1 << GRUB_DISK_SECTOR_BITS) - 1); + aligned_sector =3D (sector & ~((1 << (disk->log_sector_size + - GRUB_DISK_SECTOR_BITS)) + - 1)); + offset +=3D ((sector - aligned_sector) << GRUB_DISK_SECTOR_BITS); + num =3D ((size + offset + (1 << (disk->log_sector_size)) + - 1) >> (disk->log_sector_size)); + + tmp_buf =3D grub_malloc (num << disk->log_sector_size); + if (!tmp_buf) + return grub_errno; + =20 + 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; =20 /* First of all, check if the region is within the disk. */ if (grub_disk_adjust_range (disk, §or, &offset, size) !=3D GRUB_ER= R_NONE) @@ -399,126 +496,118 @@ return grub_errno; } =20 + real_sector =3D sector; real_offset =3D offset; - - /* Allocate a temporary buffer. */ - tmp_buf =3D grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS= ); - if (! tmp_buf) - return grub_errno; - - /* Until SIZE is zero... */ - while (size) + real_size =3D 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; =20 - /* For reading bulk data. */ start_sector =3D sector & ~(GRUB_DISK_CACHE_SIZE - 1); pos =3D (sector - start_sector) << GRUB_DISK_SECTOR_BITS; len =3D ((GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS) - - pos - real_offset); + - pos - offset); if (len > size) len =3D size; - - /* Fetch the cache. */ - data =3D grub_disk_cache_fetch (disk->dev->id, disk->id, start_sec= tor); - 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) - !=3D GRUB_ERR_NONE) - { - /* Uggh... Failed. Instead, just read necessary data. */ - unsigned num; - char *p; - - grub_errno =3D GRUB_ERR_NONE; - - num =3D ((size + real_offset + GRUB_DISK_SECTOR_SIZE - 1) - >> GRUB_DISK_SECTOR_BITS); - - p =3D grub_realloc (tmp_buf, num << GRUB_DISK_SECTOR_BITS); - if (!p) - goto finish; - - tmp_buf =3D 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 =3D (size > GRUB_DISK_SECTOR_SIZE) ? GRUB_DISK= _SECTOR_SIZE : size; - (disk->read_hook) (sector, real_offset, - to_read); - if (grub_errno !=3D GRUB_ERR_NONE) - goto finish; - - sector++; - size -=3D to_read - real_offset; - real_offset =3D 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 =3D sector; - grub_size_t l =3D 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 -=3D GRUB_DISK_SECTOR_SIZE - real_offset; - real_offset =3D 0; - } - } - - sector =3D start_sector + GRUB_DISK_CACHE_SIZE; + err =3D grub_disk_read_small (disk, start_sector, + offset + pos, len, buf); + if (err) + return err; buf =3D (char *) buf + len; size -=3D len; - real_offset =3D 0; - } - - finish: - - grub_free (tmp_buf); + offset +=3D len; + sector +=3D (offset >> GRUB_DISK_SECTOR_BITS); + offset &=3D ((1 << GRUB_DISK_SECTOR_BITS) - 1); + } + + /* Until SIZE is zero... */ + while (size >=3D (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS)) + { + char *data =3D NULL; + grub_disk_addr_t agglomerate; + grub_err_t err; + + /* agglomerate read until we find a first cached entry. */ + for (agglomerate =3D 0; agglomerate + < (size >> (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS)); + agglomerate++) + { + data =3D 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 =3D (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; + =20 + for (i =3D 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 +=3D agglomerate << GRUB_DISK_CACHE_BITS; + size -=3D agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BIT= S); + buf =3D (char *) buf=20 + + (agglomerate << (GRUB_DISK_CACHE_BITS + GRUB_DISK_SECTOR_BITS)); + } +=09 + if (data) + { + grub_memcpy (buf, data, GRUB_DISK_CACHE_SIZE); + sector +=3D GRUB_DISK_CACHE_SIZE; + buf =3D (char *) buf + (GRUB_DISK_CACHE_SIZE << GRUB_DISK_SECTOR_BITS= ); + size -=3D (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 =3D 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 =3D real_sector; + grub_size_t l =3D real_size; + grub_off_t o =3D real_offset; + + while (l) + { + (disk->read_hook) (s, o, + ((l > GRUB_DISK_SECTOR_SIZE) + ? GRUB_DISK_SECTOR_SIZE + : l)); + s++; + l -=3D GRUB_DISK_SECTOR_SIZE - o; + o =3D 0; + } + } =20 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; =20 grub_dprintf ("disk", "Writing `%s'...\n", disk->name); =20 if (grub_disk_adjust_range (disk, §or, &offset, size) !=3D GRUB_ER= R_NONE) return -1; =20 - real_offset =3D offset; + aligned_sector =3D (sector & ~((1 << (disk->log_sector_size + - GRUB_DISK_SECTOR_BITS)) - 1)); + real_offset =3D offset + ((sector - aligned_sector) << GRUB_DISK_SECTO= R_BITS); + sector =3D aligned_sector; =20 while (size) { - if (real_offset !=3D 0 || (size < GRUB_DISK_SECTOR_SIZE && size !=3D= 0)) + if (real_offset !=3D 0 || (size < (1U << disk->log_sector_size) + && size !=3D 0)) { - char tmp_buf[GRUB_DISK_SECTOR_SIZE]; + char tmp_buf[1 << disk->log_sector_size]; grub_size_t len; grub_partition_t part; =20 part =3D disk->partition; disk->partition =3D 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) !=3D GRUB_ERR_NONE) { disk->partition =3D part; @@ -554,7 +649,7 @@ } disk->partition =3D part; =20 - len =3D GRUB_DISK_SECTOR_SIZE - real_offset; + len =3D (1 << disk->log_sector_size) - real_offset; if (len > size) len =3D size; =20 @@ -565,7 +660,7 @@ if ((disk->dev->write) (disk, sector, 1, tmp_buf) !=3D GRUB_ERR_NONE)= goto finish; =20 - sector++; + sector +=3D (1 << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); buf =3D (char *) buf + len; size -=3D len; real_offset =3D 0; @@ -575,8 +670,8 @@ grub_size_t len; grub_size_t n; =20 - len =3D size & ~(GRUB_DISK_SECTOR_SIZE - 1); - n =3D size >> GRUB_DISK_SECTOR_BITS; + len =3D size & ~((1 << disk->log_sector_size) - 1); + n =3D size >> disk->log_sector_size; =20 if ((disk->dev->write) (disk, sector, n, buf) !=3D GRUB_ERR_NONE) goto finish; @@ -599,6 +694,8 @@ { if (disk->partition) return grub_partition_get_len (disk->partition); + else if (disk->total_sectors !=3D GRUB_DISK_SIZE_UNKNOWN) + return disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SEC= TOR_BITS); else - return disk->total_sectors; + return GRUB_DISK_SIZE_UNKNOWN; } =3D=3D=3D 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 @@ =20 #ifdef __linux__ # include /* ioctl */ +# include # if !defined(__GLIBC__) || \ ((__GLIBC__ < 2) || ((__GLIBC__ =3D=3D 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; =20 fd =3D open (map[drive].device, O_RDONLY); @@ -295,16 +297,28 @@ goto fail; } =20 + if (ioctl (fd, BLKSSZGET, §or_size)) + { + close (fd); + goto fail; + } + close (fd); =20 + if (sector_size & (sector_size - 1) || !sector_size) + goto fail; + for (disk->log_sector_size =3D 0; + (1 << disk->log_sector_size) < sector_size; + disk->log_sector_size++); + # if defined (__APPLE__) disk->total_sectors =3D nr; # elif defined(__NetBSD__) disk->total_sectors =3D label.d_secperunit; # else - disk->total_sectors =3D nr / 512; + disk->total_sectors =3D nr >> disk->log_sector_size; =20 - if (nr % 512) + if (nr & ((1 << disk->log_sector_size) - 1)) grub_util_error ("unaligned device size"); # endif =20 @@ -321,7 +335,7 @@ if (stat (map[drive].device, &st) < 0) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "cannot stat `%s'", map[= drive].device); =20 - disk->total_sectors =3D st.st_size >> GRUB_DISK_SECTOR_BITS; + disk->total_sectors =3D st.st_size >> disk->log_sector_size; =20 grub_util_info ("the size of %s is %lu", name, disk->total_sectors); =20 @@ -760,7 +774,7 @@ _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo, loff_t *, res, uint, wh); =20 - offset =3D (loff_t) sector << GRUB_DISK_SECTOR_BITS; + offset =3D (loff_t) sector << disk->log_sector_size; if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SE= T)) { grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].devi= ce); @@ -770,7 +784,7 @@ } #else { - off_t offset =3D (off_t) sector << GRUB_DISK_SECTOR_BITS; + off_t offset =3D (off_t) sector << disk->log_sector_size; =20 if (lseek (fd, offset, SEEK_SET) !=3D 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) !=3D GRUB_DISK_SECTOR_S= IZE) + if (nread (fd, buf, (1 << disk->log_sector_size)) + !=3D (1 << disk->log_sector_size)) { grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].de= vice); close (fd); return grub_errno; } =20 - buf +=3D GRUB_DISK_SECTOR_SIZE; + buf +=3D (1 << disk->log_sector_size); size--; } #endif /* __linux__ */ =20 - if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS) - !=3D (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) + if (nread (fd, buf, size << disk->log_sector_size) + !=3D (ssize_t) (size << disk->log_sector_size)) grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->= id].device); =20 return grub_errno; @@ -916,8 +931,8 @@ if (fd < 0) return grub_errno; =20 - if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS) - !=3D (ssize_t) (size << GRUB_DISK_SECTOR_BITS)) + if (nwrite (fd, buf, size << disk->log_sector_size) + !=3D (ssize_t) (size << disk->log_sector_size)) grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->= id].device); =20 return grub_errno; =3D=3D=3D 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 =3D mbr.entries + p.index; =20 - p.start =3D p.offset + grub_le_to_cpu32 (e->start) - delta; - p.len =3D grub_le_to_cpu32 (e->length); + p.start =3D p.offset + + (grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)) - delta; + p.len =3D grub_le_to_cpu32 (e->length) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); p.msdostype =3D e->type; =20 grub_dprintf ("partition", @@ -126,7 +129,9 @@ =20 if (grub_msdos_partition_is_extended (e->type)) { - p.offset =3D ext_offset + grub_le_to_cpu32 (e->start); + p.offset =3D ext_offset + + (grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); if (! ext_offset) ext_offset =3D p.offset; =20 @@ -204,8 +209,11 @@ e =3D mbr.entries + i; =20 if (!grub_msdos_partition_is_empty (e->type) - && end > offset + grub_le_to_cpu32 (e->start)) - end =3D offset + grub_le_to_cpu32 (e->start); + && end > offset + + (grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS))) + end =3D offset + (grub_le_to_cpu32 (e->start) + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); =20 /* If this is a GPT partition, this MBR is just a dummy. */ if (e->type =3D=3D GRUB_PC_PARTITION_TYPE_GPT_DISK && i =3D=3D 0) @@ -219,7 +227,9 @@ =20 if (grub_msdos_partition_is_extended (e->type)) { - offset =3D ext_offset + grub_le_to_cpu32 (e->start); + offset =3D ext_offset=20 + + (grub_le_to_cpu32 (e->start)=20 + << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS)); if (! ext_offset) ext_offset =3D offset; =20 =3D=3D=3D 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; =20 + /* Logarithm of sector size. */ + unsigned int log_sector_size; + /* The id used by the disk cache manager. */ unsigned long id; =20 @@ -132,9 +135,10 @@ /* The maximum number of disk caches. */ #define GRUB_DISK_CACHE_NUM 1021 =20 -/* 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 th= e + largest supported sector size, currently 16K. */ +#define GRUB_DISK_CACHE_BITS 6 +#define GRUB_DISK_CACHE_SIZE (1 << GRUB_DISK_CACHE_BITS) =20 /* Return value of grub_disk_get_size() in case disk size is unknown. */= #define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL --------------080203040305020801090609--