#define GRUB_CACHE_TIMEOUT 2
+/* Disk reads may trigger other disk reads. So, limit recursion depth. */
+#define MAX_READ_RECURSION_DEPTH 16
+static unsigned int read_recursion_depth = 0;
+
/* The last time the disk was used. */
static grub_uint64_t grub_last_time = 0;
grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_off_t offset, grub_size_t size, void *buf)
{
+ grub_err_t err = GRUB_ERR_NONE;
+
/* First of all, check if the region is within the disk. */
if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
{
return grub_errno;
}
+ if (++read_recursion_depth >= MAX_READ_RECURSION_DEPTH)
+ {
+ grub_error (GRUB_ERR_RECURSION_DEPTH, "grub_disk_read(): Maximum recursion depth exceeded");
+ goto error;
+ }
+
/* First read until first cache boundary. */
if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1)))
{
grub_disk_addr_t start_sector;
grub_size_t pos;
- grub_err_t err;
grub_size_t len;
start_sector = sector & ~((grub_disk_addr_t) GRUB_DISK_CACHE_SIZE - 1);
err = grub_disk_read_small (disk, start_sector,
offset + pos, len, buf);
if (err)
- return err;
+ goto error;
buf = (char *) buf + len;
size -= len;
offset += len;
{
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
- disk->log_sector_size),
buf);
if (err)
- return err;
+ goto error;
for (i = 0; i < agglomerate; i ++)
grub_disk_cache_store (disk->dev->id, disk->id,
/* 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;
+ goto error;
}
- return grub_errno;
+ err = grub_errno;
+
+ error:
+ read_recursion_depth--;
+ return err;
}
grub_uint64_t