=== modified file 'ChangeLog'
--- ChangeLog 2008-07-21 09:40:01 +0000
+++ ChangeLog 2008-07-22 15:42:00 +0000
@@ -1,3 +1,17 @@
+2008-07-22 Colin D Bennett
+
+ * include/grub/file.h (grub_file_buffering_enabled): New global
+ variable.
+
+ * kern/file.c (BUFFER_SIZE): New constant.
+ (grub_file_buffering_enabled): New global variable.
+ (grub_file_open): Allocate file readahead buffer.
+ (grub_file_close): Free file readahead buffer.
+ (grub_file_read): Use file readahead buffer.
+
+ * kern/main.c (grub_main): Enable file readahead buffering when it is
+ safe to do so.
+
2008-07-21 Bean
* kern/i386/pc/startup.S (gate_a20_try_bios): Change test order for
=== modified file 'include/grub/file.h'
--- include/grub/file.h 2007-08-02 17:40:37 +0000
+++ include/grub/file.h 2008-07-22 15:23:31 +0000
@@ -1,6 +1,6 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2002,2007 Free Software Foundation, Inc.
+ * Copyright (C) 2002,2007,2008 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,6 +39,19 @@
/* The file size. */
grub_off_t size;
+ /* The file offset when `buffer' starts, or -1 to indicate that
+ buffer has no data. */
+ grub_off_t buffer_offset;
+
+ /* The number of bytes in `buffer'. */
+ grub_size_t buffer_length;
+
+ /* The number of bytes allocated for `buffer'. */
+ grub_size_t buffer_capacity;
+
+ /* Readahead buffer. */
+ char *buffer;
+
/* Filesystem-specific data. */
void *data;
@@ -48,6 +61,11 @@
};
typedef struct grub_file *grub_file_t;
+/* Enable file readahead buffering if nonzero. Buffering is disabled by
+ default, since it seems to cause problems during the early GRUB boot
+ process. The grub_main function enables it. */
+extern int grub_file_buffering_enabled;
+
/* Get a device name from NAME. */
char *EXPORT_FUNC(grub_file_get_device_name) (const char *name);
=== modified file 'kern/file.c'
--- kern/file.c 2008-01-25 20:57:40 +0000
+++ kern/file.c 2008-07-22 15:23:31 +0000
@@ -1,7 +1,7 @@
/* file.c - file I/O functions */
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2002,2006,2007 Free Software Foundation, Inc.
+ * Copyright (C) 2002,2006,2007,2008 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,12 @@
#include
#include
+/* File readahead buffer size in bytes. */
+#define BUFFER_SIZE 1024
+
+/* Use readahead buffering for file reads? */
+int grub_file_buffering_enabled = 0;
+
/* Get the device part of the filename NAME. It is enclosed by parentheses. */
char *
grub_file_get_device_name (const char *name)
@@ -81,6 +87,10 @@
file->device = device;
file->offset = 0;
+ file->buffer_offset = -1;
+ file->buffer_length = 0;
+ file->buffer_capacity = 0;
+ file->buffer = 0;
file->data = 0;
file->read_hook = 0;
@@ -97,6 +107,13 @@
if ((file->fs->open) (file, file_name) != GRUB_ERR_NONE)
goto fail;
+ if (grub_file_buffering_enabled)
+ {
+ file->buffer = grub_malloc (BUFFER_SIZE);
+ if (file->buffer)
+ file->buffer_capacity = BUFFER_SIZE;
+ }
+
return file;
fail:
@@ -110,6 +127,15 @@
return 0;
}
+static inline grub_size_t
+grub_min (grub_size_t a, grub_size_t b)
+{
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+
grub_ssize_t
grub_file_read (grub_file_t file, char *buf, grub_size_t len)
{
@@ -124,10 +150,52 @@
if (len == 0)
return 0;
-
- res = (file->fs->read) (file, buf, len);
- if (res > 0)
- file->offset += res;
+
+ if (grub_file_buffering_enabled && file->buffer)
+ {
+ res = 0; /* The while loop uses res to accumulate the # bytes read. */
+ while (len)
+ {
+ /* If the start of the chunk requested is not in the buffer,
+ then fill the buffer starting at the requested offset. */
+ if (file->buffer_offset == -1
+ || file->offset < file->buffer_offset
+ || file->offset >= file->buffer_offset + file->buffer_length)
+ {
+ grub_ssize_t res2;
+
+ /* Read into the buffer, and then use that data. */
+ file->buffer_offset = -1;
+ file->buffer_length = grub_min (file->buffer_capacity,
+ file->size - file->offset);
+ res2 = (file->fs->read) (file, file->buffer, file->buffer_length);
+ if (res2 > 0)
+ {
+ file->buffer_length = res2;
+ file->buffer_offset = file->offset;
+ }
+ else
+ return res;
+ }
+
+ /* Use as much buffered data as possible. */
+ grub_size_t bufstart = file->offset - file->buffer_offset;
+ grub_size_t buflen = len;
+ if (bufstart + len > file->buffer_length)
+ buflen = file->buffer_length - bufstart;
+ grub_memcpy (buf, file->buffer + bufstart, buflen);
+ buf += buflen;
+ res += buflen;
+ len -= buflen;
+ file->offset += buflen;
+ }
+ }
+ else
+ {
+ res = (file->fs->read) (file, buf, len);
+ if (res > 0)
+ file->offset += res;
+ }
return res;
}
@@ -135,6 +203,9 @@
grub_err_t
grub_file_close (grub_file_t file)
{
+ grub_free (file->buffer);
+ file->buffer = 0;
+
if (file->fs->close)
(file->fs->close) (file);
=== modified file 'kern/main.c'
--- kern/main.c 2008-06-19 19:08:57 +0000
+++ kern/main.c 2008-07-22 15:23:31 +0000
@@ -128,6 +128,9 @@
grub_env_export ("prefix");
grub_set_root_dev ();
+ /* Enable file readahead buffering, now that it is safe to do so. */
+ grub_file_buffering_enabled = 1;
+
/* Load the normal mode module. */
grub_load_normal_mode ();