FILESYSTEM: dynamic read-ahead

file:35ae52df6b6d851ed0fbd1d84c6d76ec226573c8 -> file:8d881b0922b23f8758f80d16de2dc0e597e9437f
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -413,8 +413,7 @@ struct request_queue *blk_alloc_queue_no
if (!q)
return NULL;
- q->backing_dev_info.ra_pages =
- (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+ q->backing_dev_info.ra_pages = max_readahead_pages;
q->backing_dev_info.state = 0;
q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
q->backing_dev_info.name = "block";
file:61b99c3f5c4b545eb5ae9cfe1f88a2d137b3c209 -> file:766b43e12a97c1b6bcf5170da8f02216694adbd5
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -624,6 +624,26 @@ void add_disk(struct gendisk *disk)
"bdi");
WARN_ON(retval);
+ /*
+ * Limit default readahead size for small devices.
+ * disk size readahead size
+ * 1M 8k
+ * 4M 16k
+ * 16M 32k
+ * 64M 64k
+ * 256M 128k
+ * 1G 256k
+ * 4G 512k
+ * 16G 1024k
+ * 64G 2048k
+ * 256G 4096k
+ */
+ if (get_capacity(disk)) {
+ unsigned long size = get_capacity(disk) >> 9;
+ size = 1UL << (ilog2(size) / 2);
+ bdi->ra_pages = min(bdi->ra_pages, size);
+ }
+
disk_add_events(disk);
}
EXPORT_SYMBOL(add_disk);
file:f23806ba4e1145d6312f0a7df4533a53f0e337ee -> file:97a1f09274c1d0044a913d57f917bafcc968a918
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -879,7 +879,7 @@ static int fuse_bdi_init(struct fuse_con
int err;
fc->bdi.name = "fuse";
- fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+ fc->bdi.ra_pages = max_readahead_pages;
/* fuse does it's own writeback accounting */
fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
file:2009b318d604531a81dbccae95b4edd123fb5f38 -> file:af7741a2adda61ab3f0d5c4ee14a7bdfbf4be4b3
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1472,8 +1472,10 @@ int write_one_page(struct page *page, in
void task_dirty_inc(struct task_struct *tsk);
/* readahead.c */
-#define VM_MAX_READAHEAD 128 /* kbytes */
-#define VM_MIN_READAHEAD 16 /* kbytes (includes current page) */
+#define VM_MAX_READAHEAD 2048 /* kbytes */
+#define VM_MIN_READAHEAD 64 /* kbytes (includes current page) */
+
+extern unsigned long max_readahead_pages;
int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
pgoff_t offset, unsigned long nr_to_read);
file:867f9dd82dcde9d5c11f49bde159c3c6a0276c4e -> file:286251a4d091da15b8f993b9214bacf4783738e5
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -18,6 +18,32 @@
#include <linux/pagevec.h>
#include <linux/pagemap.h>
+unsigned long max_readahead_pages = VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE;
+
+static int __init readahead(char *str)
+{
+ unsigned long bytes;
+
+ if (!str)
+ return -EINVAL;
+ bytes = memparse(str, &str);
+ if (*str != '\0')
+ return -EINVAL;
+
+ if (bytes) {
+ if (bytes < PAGE_CACHE_SIZE) /* missed 'k'/'m' suffixes? */
+ return -EINVAL;
+ if (bytes > 256 << 20) /* limit to 256MB */
+ bytes = 256 << 20;
+ }
+
+ max_readahead_pages = bytes / PAGE_CACHE_SIZE;
+ default_backing_dev_info.ra_pages = max_readahead_pages;
+ return 0;
+}
+
+early_param("readahead", readahead);
+
/*
* Initialise a struct file's readahead state. Assumes that the caller has
* memset *ra to zero.