diff options
Diffstat (limited to 'mm/readahead.c')
-rw-r--r-- | mm/readahead.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/mm/readahead.c b/mm/readahead.c index 8d6eeaaa6296..57557e294987 100644 --- a/mm/readahead.c +++ b/mm/readahead.c | |||
@@ -52,13 +52,24 @@ static inline unsigned long get_min_readahead(struct file_ra_state *ra) | |||
52 | return (VM_MIN_READAHEAD * 1024) / PAGE_CACHE_SIZE; | 52 | return (VM_MIN_READAHEAD * 1024) / PAGE_CACHE_SIZE; |
53 | } | 53 | } |
54 | 54 | ||
55 | static inline void reset_ahead_window(struct file_ra_state *ra) | ||
56 | { | ||
57 | /* | ||
58 | * ... but preserve ahead_start + ahead_size value, | ||
59 | * see 'recheck:' label in page_cache_readahead(). | ||
60 | * Note: We never use ->ahead_size as rvalue without | ||
61 | * checking ->ahead_start != 0 first. | ||
62 | */ | ||
63 | ra->ahead_size += ra->ahead_start; | ||
64 | ra->ahead_start = 0; | ||
65 | } | ||
66 | |||
55 | static inline void ra_off(struct file_ra_state *ra) | 67 | static inline void ra_off(struct file_ra_state *ra) |
56 | { | 68 | { |
57 | ra->start = 0; | 69 | ra->start = 0; |
58 | ra->flags = 0; | 70 | ra->flags = 0; |
59 | ra->size = 0; | 71 | ra->size = 0; |
60 | ra->ahead_start = 0; | 72 | reset_ahead_window(ra); |
61 | ra->ahead_size = 0; | ||
62 | return; | 73 | return; |
63 | } | 74 | } |
64 | 75 | ||
@@ -426,8 +437,7 @@ static int make_ahead_window(struct address_space *mapping, struct file *filp, | |||
426 | * congestion. The ahead window will any way be closed | 437 | * congestion. The ahead window will any way be closed |
427 | * in case we failed due to excessive page cache hits. | 438 | * in case we failed due to excessive page cache hits. |
428 | */ | 439 | */ |
429 | ra->ahead_start = 0; | 440 | reset_ahead_window(ra); |
430 | ra->ahead_size = 0; | ||
431 | } | 441 | } |
432 | 442 | ||
433 | return ret; | 443 | return ret; |
@@ -520,11 +530,11 @@ page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra, | |||
520 | * If we get here we are doing sequential IO and this was not the first | 530 | * If we get here we are doing sequential IO and this was not the first |
521 | * occurence (ie we have an existing window) | 531 | * occurence (ie we have an existing window) |
522 | */ | 532 | */ |
523 | |||
524 | if (ra->ahead_start == 0) { /* no ahead window yet */ | 533 | if (ra->ahead_start == 0) { /* no ahead window yet */ |
525 | if (!make_ahead_window(mapping, filp, ra, 0)) | 534 | if (!make_ahead_window(mapping, filp, ra, 0)) |
526 | goto out; | 535 | goto recheck; |
527 | } | 536 | } |
537 | |||
528 | /* | 538 | /* |
529 | * Already have an ahead window, check if we crossed into it. | 539 | * Already have an ahead window, check if we crossed into it. |
530 | * If so, shift windows and issue a new ahead window. | 540 | * If so, shift windows and issue a new ahead window. |
@@ -536,6 +546,10 @@ page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra, | |||
536 | ra->start = ra->ahead_start; | 546 | ra->start = ra->ahead_start; |
537 | ra->size = ra->ahead_size; | 547 | ra->size = ra->ahead_size; |
538 | make_ahead_window(mapping, filp, ra, 0); | 548 | make_ahead_window(mapping, filp, ra, 0); |
549 | recheck: | ||
550 | /* prev_page shouldn't overrun the ahead window */ | ||
551 | ra->prev_page = min(ra->prev_page, | ||
552 | ra->ahead_start + ra->ahead_size - 1); | ||
539 | } | 553 | } |
540 | 554 | ||
541 | out: | 555 | out: |