patch-1.3.89 linux/mm/filemap.c
Next file: linux/mm/memory.c
Previous file: linux/include/linux/sdla.h
Back to the patch index
Back to the overall index
- Lines: 289
- Date:
Sun Apr 14 09:55:50 1996
- Orig file:
v1.3.88/linux/mm/filemap.c
- Orig date:
Sat Apr 13 18:22:07 1996
diff -u --recursive --new-file v1.3.88/linux/mm/filemap.c linux/mm/filemap.c
@@ -27,6 +27,10 @@
#include <asm/system.h>
#include <asm/pgtable.h>
+#if 0
+#define DEBUG_ASYNC_AHEAD
+#endif
+
/*
* Shared mappings implemented 30.11.1994. It's not fully working yet,
* though.
@@ -322,6 +326,8 @@
unsigned long rapos, ppos;
ppos = pos & PAGE_MASK;
+ rapos = filp->f_rapos & PAGE_MASK;
+ max_ahead = 0;
/*
* If the current page is locked, try some synchronous read-ahead in order
* to avoid too small IO requests.
@@ -329,56 +335,47 @@
if (PageLocked(page)) {
max_ahead = filp->f_ramax;
rapos = ppos;
-/* try_async = 1 */ /* Seems questionable */
+ filp->f_rawin = 0;
+ filp->f_ralen = PAGE_SIZE;
}
/*
* The current page is not locked
* It may be the moment to try asynchronous read-ahead.
- */
- else {
-/*
- * Compute the position of the last page we have tried to read
- */
- rapos = filp->f_rapos & PAGE_MASK;
- if (rapos) rapos -= PAGE_SIZE;
-/*
- * If asynchronous is the good tactics and if the current position is
- * inside the previous read-ahead window,
- * check the last red page:
- * - if locked, previous IO request is probably not complete, and we will
- * not try to do another IO request.
- * - if not locked, previous IO request is probably complete, and it is the
- * good moment to try a new asynchronous read-ahead request.
+ * If asynchronous is the suggested tactics and if the current position is
+ * inside the previous read-ahead window, check the last read page:
+ * - if locked, the previous IO request is probably not complete, and
+ * we will not try to do another IO request.
+ * - if not locked, the previous IO request is probably complete, and
+ * this is a good moment to try a new asynchronous read-ahead request.
* try_async = 2 means that we have to force unplug of the device in
* order to force call to the strategy routine of the disk driver and
* start IO asynchronously.
*/
- if (try_async == 1 && pos <= filp->f_rapos &&
- pos + filp->f_ralen >= filp->f_rapos) {
- struct page *a_page;
+ else if (try_async == 1 && rapos >= PAGE_SIZE &&
+ ppos <= rapos && ppos + filp->f_ralen >= rapos) {
+ struct page *a_page;
/*
* Add ONE page to max_ahead in order to try to have the same IO max size as
* synchronous read-ahead (MAX_READAHEAD + 1)*PAGE_SIZE.
+ * Compute the position of the last page we have tried to read.
*/
- max_ahead = filp->f_ramax + PAGE_SIZE;
+ max_ahead = filp->f_ramax + PAGE_SIZE;
+ rapos -= PAGE_SIZE;
- if (rapos < inode->i_size) {
- a_page = find_page(inode, rapos);
- if (a_page) {
- if (PageLocked(a_page))
- max_ahead = 0;
- a_page->count--;
- }
+ if (rapos < inode->i_size) {
+ a_page = find_page(inode, rapos);
+ if (a_page) {
+ if (PageLocked(a_page))
+ max_ahead = 0;
+ a_page->count--;
}
- else
- max_ahead = 0;
- try_async = 2;
}
- else {
- max_ahead = 0;
+ if (max_ahead) {
+ filp->f_rawin = filp->f_ralen;
+ filp->f_ralen = 0;
+ try_async = 2;
}
}
-
/*
* Try to read pages.
* We hope that ll_rw_blk() plug/unplug, coalescence and sort will work fine
@@ -391,27 +388,22 @@
}
/*
* If we tried to read some pages,
+ * Compute the new read-ahead position.
+ * It is the position of the next byte.
* Store the length of the current read-ahead window.
* If necessary,
* Try to force unplug of the device in order to start an asynchronous
* read IO.
*/
- if (ahead > 0) {
- filp->f_ralen = ahead;
+ if (ahead) {
+ filp->f_ralen += ahead;
+ filp->f_rawin += filp->f_ralen;
+ filp->f_rapos = rapos + ahead + PAGE_SIZE;
if (try_async == 2) {
-/*
- * Schedule() should be changed to run_task_queue(...)
- */
run_task_queue(&tq_disk);
- try_async = 1;
}
}
/*
- * Compute the new read-ahead position.
- * It is the position of the next byte.
- */
- filp->f_rapos = rapos + ahead + PAGE_SIZE;
-/*
* Wait on the page if necessary
*/
if (PageLocked(page)) {
@@ -424,78 +416,87 @@
int generic_file_read(struct inode * inode, struct file * filp, char * buf, int count)
{
int error, read;
- unsigned long pos, page_cache;
+ unsigned long pos, ppos, page_cache;
int try_async;
+
+#ifdef DEBUG_ASYNC_AHEAD
+static long ccount = 0;
+if (count > 0) ccount += count;
+#endif
if (count <= 0)
return 0;
+
error = 0;
read = 0;
page_cache = 0;
pos = filp->f_pos;
+ ppos = pos & PAGE_MASK;
/*
- * Dont believe f_reada
- * --------------------
- * f_reada is set to 0 by seek operations.
- * If we believe f_reada, small seek ops break asynchronous read-ahead.
- * That may be quite bad for small seeks or rewrites operations.
- * I prefer to check if the current position is inside the previous read-ahead
- * window.
+ * Check if the current position is inside the previous read-ahead window.
* If that's true, I assume that the file accesses are sequential enough to
* continue asynchronous read-ahead.
+ * Do minimum read-ahead at the beginning of the file since some tools
+ * only read the beginning of files.
+ * Break read-ahead if the file position is outside the previous read ahead
+ * window or if read-ahead position is 0.
*/
- if (pos <= filp->f_rapos && pos + filp->f_ralen >= filp->f_rapos) {
- filp->f_reada = 1;
- }
/*
- * Do minimum read-ahead at the beginning of the file.
- * Some tools only read the start of the file only.
- * Break read-ahead if the file position is after the previous read ahead
- * position or if read-ahead position is 0.
+ * Will not try asynchronous read-ahead.
+ * Reset to zero, read-ahead context.
*/
- else if (pos+count < MIN_READAHEAD || !filp->f_rapos ||
- pos > filp->f_rapos) {
- filp->f_reada = 0;
- }
-
+ if (pos+count < MIN_READAHEAD || !filp->f_rapos ||
+ ppos > filp->f_rapos || ppos + filp->f_rawin < filp->f_rapos) {
+ try_async = 0;
+#ifdef DEBUG_ASYNC_AHEAD
+ if (ccount > 10000000) {
+ ccount = 0;
+ printk("XXXXXXXX ppos=%ld rapos=%ld ralen=%ld ramax=%ld rawin=%ld\n",
+ ppos, filp->f_rapos, filp->f_ralen, filp->f_ramax, filp->f_rawin);
+ }
+#endif
+ filp->f_rapos = 0;
+ filp->f_ralen = 0;
+ filp->f_ramax = 0;
+ filp->f_rawin = 0;
/*
- * Now f_reada = 1 means that asynchronous read-ahead is the good tactics.
- * Will try asynchronous read-ahead as soon as possible.
+ * Will try asynchronous read-ahead.
* Double the max read ahead size each time.
* That heuristic avoid to do some large IO for files that are not really
- * accessed sequentially.
+ * accessed sequentialy.
*/
- if (filp->f_reada) {
+ } else {
try_async = 1;
+#ifdef DEBUG_ASYNC_AHEAD
+ if (ccount > 10000000) {
+ ccount = 0;
+ printk("XXXXXXXX ppos=%ld rapos=%ld ralen=%ld ramax=%ld rawin=%ld\n",
+ ppos, filp->f_rapos, filp->f_ralen, filp->f_ramax, filp->f_rawin);
+ }
+#endif
filp->f_ramax += filp->f_ramax;
}
/*
- * f_reada = 0 means that asynchronous read_ahead is quite bad.
- * Will not try asynchronous read-ahead first.
- * Reset to zero, read-ahead context.
+ * Compute a good value for read-ahead max
+ * If the read operation stay in the first half page, force no readahead.
+ * Else try first some value near count.
+ * do at least MIN_READAHEAD and at most MAX_READAHEAD.
+ * (Should be a little reworked)
*/
- else {
+ if (pos + count <= (PAGE_SIZE >> 1)) {
try_async = 0;
- filp->f_rapos = 0;
- filp->f_ralen = 0;
filp->f_ramax = 0;
+ } else {
+ if (filp->f_ramax < count)
+ filp->f_ramax = count & PAGE_MASK;
+
+ if (filp->f_ramax < MIN_READAHEAD)
+ filp->f_ramax = MIN_READAHEAD;
+ else if (filp->f_ramax > MAX_READAHEAD)
+ filp->f_ramax = MAX_READAHEAD;
}
-/*
- * Compute a good value for read-ahead max
- * Try first some value near count.
- * Do at least MIN_READAHEAD and at most MAX_READAHEAD.
- * (Should be a little reworked)
- */
- if (filp->f_ramax < count)
- filp->f_ramax = count & PAGE_MASK;
-
- if (filp->f_ramax < MIN_READAHEAD)
- filp->f_ramax = MIN_READAHEAD;
- else if (filp->f_ramax > MAX_READAHEAD)
- filp->f_ramax = MAX_READAHEAD;
-
for (;;) {
struct page *page;
unsigned long offset, addr, nr;
@@ -537,8 +538,19 @@
addr = page_address(page);
if (nr > count)
nr = count;
-
- page_cache = generic_file_readahead(filp, inode, try_async, pos, page, page_cache);
+/*
+ * Do not try to readahead if the current page is not filled or being filled.
+ * If our goal was to try asynchronous read-ahead, we were quite wrong.
+ * Set max readahead to some shorter value in order to fix a little
+ * this mistake.
+ */
+ if (PageUptodate(page) || PageLocked(page))
+ page_cache = generic_file_readahead(filp, inode, try_async, pos, page, page_cache);
+ else if (try_async) {
+ filp->f_ramax = (filp->f_ramax / 2) & PAGE_MASK;
+ if (filp->f_ramax < MIN_READAHEAD)
+ filp->f_ramax = MIN_READAHEAD;
+ }
if (!PageUptodate(page))
goto read_page;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this