=== 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 ();