Skip to content

Instantly share code, notes, and snippets.

@SaveTheRbtz
Last active October 10, 2015 18:48
Show Gist options
  • Save SaveTheRbtz/3734932 to your computer and use it in GitHub Desktop.
Save SaveTheRbtz/3734932 to your computer and use it in GitHub Desktop.
Added "fade" readahead type
commit e95636528228a11ed22e5d17e160d69325e8572f
Author: Alexey Ivanov <rbtz@yandex-team.ru>
Date: Tue Jul 31 01:48:45 2012 +0400
YANDEX: Added "fade" readahead type
This replaces comlicated logic with simple one:
* If we've already read more than file size -- read 8 pages
* Else if we read more than file size / 2 -- read (ra_pages / 4) pages
* Otherwise read 8 pages
Turned on by vm.readahead_fade sysctl
Submitted by: ironpeter@
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c4f307a..52c4d74 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -953,6 +953,7 @@ struct file_ra_state {
unsigned int ra_pages; /* Maximum readahead window */
unsigned int mmap_miss; /* Cache miss stat for mmap accesses */
loff_t prev_pos; /* Cache last read() position */
+ unsigned long pages_read; /* Pages read by readahead */
};
/*
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 670f041..3c29190 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -28,6 +28,7 @@ struct writeback_control;
extern unsigned long max_mapnr;
#endif
+extern int mm_readahead_fade;
extern unsigned long num_physpages;
extern unsigned long totalram_pages;
extern void * high_memory;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 7b5e9eb..e51ae49 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1120,6 +1120,14 @@ static struct ctl_table vm_table[] = {
.extra1 = &zero,
.extra2 = &one_hundred,
},
+ {
+ .procname = "readahead_fade",
+ .data = &mm_readahead_fade,
+ .maxlen = sizeof(mm_readahead_fade),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ },
#ifdef CONFIG_HUGETLB_PAGE
{
.procname = "nr_hugepages",
diff --git a/mm/filemap.c b/mm/filemap.c
index 7fe956c..8478e78 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1607,6 +1607,57 @@ static void do_sync_mmap_readahead(struct vm_area_struct *vma,
ra_submit(ra, mapping, file);
}
+static void do_fade_readahead(struct vm_area_struct *vma,
+ struct file_ra_state *ra,
+ struct file *file,
+ pgoff_t offset,
+ int readback)
+{
+ unsigned long ra_pages;
+ unsigned long pages_read;
+ unsigned long vma_num_pages;
+ unsigned long ra_pages_read;
+ unsigned long ra_pages_back;
+ struct address_space *mapping = file->f_mapping;
+ struct file_ra_state local_ra;
+ /* If we don't want any read-ahead, don't bother */
+ if (VM_RandomReadHint(vma))
+ return;
+ if (!ra->ra_pages)
+ return;
+ if (!vma)
+ return;
+ /*
+ * fade logic. Do max(ra_pages, 8), max(ra_pages / 4, 8), 8 pages read
+ */
+ memset(&local_ra, 0, sizeof(local_ra));
+ ra_pages = max_sane_readahead(ra->ra_pages);
+ vma_num_pages = (vma->vm_end - vma->vm_start) >> PAGE_CACHE_SHIFT;
+ ra_pages_read = ra->pages_read;
+ if (ra_pages_read >= vma_num_pages)
+ ra_pages = 8;
+ else if (ra_pages_read >= vma_num_pages / 2)
+ ra_pages = ra_pages / 4;
+ if (ra_pages < 8)
+ ra_pages = 8;
+ ra_pages_back = readback * ra_pages / 4;
+ if (offset > ra_pages_back)
+ local_ra.start = offset - ra_pages_back;
+ local_ra.size = ra_pages;
+ local_ra.async_size = ra_pages / 4;
+ pages_read = ra_submit(&local_ra, mapping, file);
+ /*
+ * work with overflow
+ */
+ if (pages_read + ra_pages_read > ra_pages_read)
+ ra_pages_read += pages_read;
+ else
+ ra_pages_read = (unsigned long)-1;
+ ra->pages_read = ra_pages_read;
+}
+
+
+
/*
* Asynchronous readahead happens when we find the page and PG_readahead,
* so we want to possibly extend the readahead further..
@@ -1666,10 +1717,18 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
* We found the page, so try async readahead before
* waiting for the lock.
*/
- do_async_mmap_readahead(vma, ra, file, page, offset);
+ if (mm_readahead_fade == 0)
+ do_async_mmap_readahead(vma, ra, file, page, offset);
+ else if (PageReadahead(page) && !PageWriteback(page)) {
+ ClearPageReadahead(page);
+ do_fade_readahead(vma, ra, file, offset, 0);
+ }
} else {
/* No page in the page cache at all */
- do_sync_mmap_readahead(vma, ra, file, offset);
+ if (mm_readahead_fade == 0)
+ do_sync_mmap_readahead(vma, ra, file, offset);
+ else
+ do_fade_readahead(vma, ra, file, offset, 1);
count_vm_event(PGMAJFAULT);
mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
ret = VM_FAULT_MAJOR;
@@ -2663,3 +2722,4 @@ int try_to_release_page(struct page *page, gfp_t gfp_mask)
}
EXPORT_SYMBOL(try_to_release_page);
+int mm_readahead_fade = 0;
\ No newline at end of file
diff --git a/mm/readahead.c b/mm/readahead.c
index 2acb815..7548a22 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -27,6 +27,7 @@ file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping)
{
ra->ra_pages = mapping->backing_dev_info->ra_pages;
ra->prev_pos = -1;
+ ra->pages_read = 0;
}
EXPORT_SYMBOL_GPL(file_ra_state_init);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment