SOURCES: linux-2.6-prefetch.patch (NEW) - http://code.google.com/p...

baggins baggins at pld-linux.org
Thu Oct 11 18:58:38 CEST 2007


Author: baggins                      Date: Thu Oct 11 16:58:38 2007 GMT
Module: SOURCES                       Tag: HEAD
---- Log message:
- http://code.google.com/p/prefetch/
- Linux solution for prefetching necessary data during application and system startup

---- Files affected:
SOURCES:
   linux-2.6-prefetch.patch (NONE -> 1.1)  (NEW)

---- Diffs:

================================================================
Index: SOURCES/linux-2.6-prefetch.patch
diff -u /dev/null SOURCES/linux-2.6-prefetch.patch:1.1
--- /dev/null	Thu Oct 11 18:58:38 2007
+++ SOURCES/linux-2.6-prefetch.patch	Thu Oct 11 18:58:33 2007
@@ -0,0 +1,3248 @@
+diff --git a/fs/exec.c b/fs/exec.c
+index f9e8f6f..b060dce 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -51,6 +51,7 @@
+ #include <linux/syscalls.h>
+ #include <linux/rmap.h>
+ #include <linux/tsacct_kern.h>
++#include <linux/prefetch_core.h>
+ #include <linux/cn_proc.h>
+ #include <linux/audit.h>
+ #include <linux/signalfd.h>
+@@ -1167,6 +1168,8 @@ int do_execve(char * filename,
+ 	if (IS_ERR(file))
+ 		goto out_kfree;
+ 
++	prefetch_exec_hook(filename);
++
+ 	sched_exec();
+ 
+ 	bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+diff --git a/include/linux/prefetch_core.h b/include/linux/prefetch_core.h
+new file mode 100644
+index 0000000..a5fbd56
+--- /dev/null
++++ b/include/linux/prefetch_core.h
+@@ -0,0 +1,110 @@
++/*
++ * Copyright (C) 2007 Krzysztof Lichota <lichota at mimuw.edu.pl>
++ *
++ * This is prefetch core - common code used for tracing and saving trace files.
++ * It is used by prefetching modules, such as boot and app.
++ */
++
++#ifndef _LINUX_PREFETCH_CORE_H
++#define _LINUX_PREFETCH_CORE_H
++
++#include <linux/types.h>
++#include <linux/mm_types.h>
++
++/**
++ * Trace record, records one range of pages for inode put into trace.
++*/
++struct prefetch_trace_record {
++	dev_t device;
++	unsigned long inode_no;
++	pgoff_t range_start;
++	pgoff_t range_length;
++};
++
++extern char trace_file_magic[4];
++
++enum {
++	PREFETCH_FORMAT_VERSION_MAJOR = 1,
++	PREFETCH_FORMAT_VERSION_MINOR = 0
++};
++
++/**
++ * Trace on-disk header.
++ * Major version is increased with major changes of format.
++ * If you do not support this format explicitely, do not read other fields.
++ * Minor version is increased with backward compatible changes and
++ * you can read other fields and raw data, provided that you read
++ * trace data from @data_start offset in file.
++*/
++struct prefetch_trace_header {
++	char magic[4];		/*Trace file signature - should contain trace_file_magic */
++	u16 version_major;	/*Major version of trace file format */
++	u16 version_minor;	/*Minor version of trace file format */
++	u16 data_start;		/*Trace raw data start */
++};
++
++struct trace_marker {
++	unsigned position;
++	unsigned generation;
++};
++
++int prefetch_start_trace(struct trace_marker *marker);
++int prefetch_continue_trace(struct trace_marker *marker);
++int prefetch_stop_trace(struct trace_marker *marker);
++int prefetch_release_trace(struct trace_marker end_marker);
++
++int prefetch_trace_fragment_size(struct trace_marker start_marker,
++				 struct trace_marker end_marker);
++
++int get_prefetch_trace_fragment(struct trace_marker start_marker,
++				struct trace_marker end_marker,
++				void **fragment_result,
++				int *fragment_size_result);
++
++void *alloc_trace_buffer(int len);
++void free_trace_buffer(void *buffer, int len);
++void sort_trace_fragment(void *trace, int trace_size);
++
++int prefetch_save_trace_between_markers(char *filename,
++					struct trace_marker start_marker,
++					struct trace_marker end_marker);
++int prefetch_save_trace_fragment(char *filename,
++				 void *trace_buffer, int trace_size);
++int prefetch_load_trace_fragment(char *filename,
++				 void **trace_buffer, int *trace_size);
++
++int prefetch_start_prefetch(void *trace, int trace_size, int async);
++int do_prefetch_from_file(char *filename);
++
++void print_marker(char *msg, struct trace_marker marker);
++
++/* Hook for mm page release code */
++#ifdef CONFIG_PREFETCH_CORE
++void prefetch_page_release_hook(struct page *page);
++#else
++#define prefetch_page_release_hook(param) do {} while (0)
++#endif
++
++struct proc_dir_entry;
++extern struct proc_dir_entry *prefetch_proc_dir;
++
++int param_match(char *line, char *param_name);
++int param_match_prefix(char *line, char *param_name);
++
++/*Auxiliary functions for reading and writing in kernel*/
++struct file *kernel_open(char const *file_name, int flags, int mode);
++int kernel_write(struct file *file, unsigned long offset, const char *addr,
++		 unsigned long count);
++/*NOTE: kernel_read is already available in kernel*/
++int kernel_close(struct file *file);
++
++/* App prefetching hooks */
++#ifdef CONFIG_PREFETCH_APP
++void prefetch_exec_hook(char *filename);
++void prefetch_exit_hook(pid_t pid);
++#else
++#define prefetch_exec_hook(param) do {} while (0)
++#define prefetch_exit_hook(param) do {} while (0)
++#endif
++
++#endif /*_LINUX_PREFETCH_CORE_H*/
+diff --git a/init/Kconfig b/init/Kconfig
+index a9e99f8..df3d532 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -104,6 +104,38 @@ config SWAP
+ 	  for so called swap devices or swap files in your kernel that are
+ 	  used to provide more virtual memory than the actual RAM present
+ 	  in your computer.  If unsure say Y.
++config PREFETCH_CORE
++       bool "Prefetching support (core)"
++       default n
++       depends on MMU && BLOCK && EXPERIMENTAL
++       select TASK_DELAY_ACCT
++       help
++         This option enables core of tracing and prefetching facility
++         The core provides functions used by real prefetching modules,
++         so you have to enable one of them as well.
++config PREFETCH_BOOT
++       tristate "Boot prefetching support"
++       default n
++       depends on PREFETCH_CORE && PROC_FS && EXPERIMENTAL
++       help
++         This option enables facility for tracing and prefetching during system boot.
++         In order to use it you have to install appropriate prefetch init scripts.
++config PREFETCH_APP
++       bool "Application prefetching support"
++       default n
++       depends on PREFETCH_CORE && PROC_FS && EXPERIMENTAL
++       help
++         This option enables facility for tracing and prefetching during application start.
++         Upon application start tracing is started and after some, configurable time,
++         tracing is stopped and written to file. Upon next start the files in saved
++         file are prefetched.
++config PREFETCH_DEBUG
++       bool "Prefetching debug interface and debugging facilities"
++       default n
++       depends on PREFETCH_CORE && PROC_FS
++       help
++         This option enables facilities for testing and debugging tracing and prefetching.
++         Do not enable on production systems.
+ 
+ config SYSVIPC
+ 	bool "System V IPC"
+diff --git a/kernel/exit.c b/kernel/exit.c
+index 5b888c2..c136765 100644
+--- a/kernel/exit.c
++++ b/kernel/exit.c
+@@ -44,6 +44,7 @@
+ #include <linux/compat.h>
+ #include <linux/pipe_fs_i.h>
+ #include <linux/audit.h> /* for audit_free() */
++#include <linux/prefetch_core.h>
+ #include <linux/resource.h>
+ #include <linux/blkdev.h>
+ #include <linux/task_io_accounting_ops.h>
+@@ -864,6 +865,8 @@ fastcall NORET_TYPE void do_exit(long co
+ 	struct task_struct *tsk = current;
+ 	int group_dead;
+ 
++	prefetch_exit_hook(tsk->pid);
++
+ 	profile_task_exit(tsk);
+ 
+ 	WARN_ON(atomic_read(&tsk->fs_excl));
+diff --git a/mm/Makefile b/mm/Makefile
+index a9148ea..5433e6e 100644
+--- a/mm/Makefile
++++ b/mm/Makefile
+@@ -31,4 +31,7 @@ obj-$(CONFIG_FS_XIP) += filemap_xip.o
+ obj-$(CONFIG_MIGRATION) += migrate.o
+ obj-$(CONFIG_SMP) += allocpercpu.o
+ obj-$(CONFIG_QUICKLIST) += quicklist.o
++obj-$(CONFIG_PREFETCH_CORE)	+= prefetch_core.o
++obj-$(CONFIG_PREFETCH_BOOT)	+= prefetch_boot.o
++obj-$(CONFIG_PREFETCH_APP)	+= prefetch_app.o
+ 
+diff --git a/mm/filemap.c b/mm/filemap.c
+index edb1b0b..405487c 100644
+--- a/mm/filemap.c
++++ b/mm/filemap.c
+@@ -30,6 +30,7 @@
+ #include <linux/security.h>
+ #include <linux/syscalls.h>
+ #include <linux/cpuset.h>
++#include <linux/prefetch_core.h>
+ #include "filemap.h"
+ #include "internal.h"
+ 
+@@ -115,7 +116,9 @@ generic_file_direct_IO(int rw, struct ki
+ void __remove_from_page_cache(struct page *page)
+ {
+ 	struct address_space *mapping = page->mapping;
+-
++
++	prefetch_page_release_hook(page);
++
+ 	radix_tree_delete(&mapping->page_tree, page->index);
+ 	page->mapping = NULL;
+ 	mapping->nrpages--;
+diff --git a/mm/prefetch_app.c b/mm/prefetch_app.c
+new file mode 100644
+index 0000000..b7f3d43
+--- /dev/null
++++ b/mm/prefetch_app.c
+@@ -0,0 +1,1071 @@
++/*
++ * linux/mm/prefetch_app.c
++ *
++ * Copyright (C) 2007 Krzysztof Lichota <lichota at mimuw.edu.pl>
++ *
++ * This is application tracing and prefetching module. It traces application start
++ * for specified time, then upon next start it prefetches these files.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/prefetch_core.h>
++#include <asm/uaccess.h>
++#include <linux/proc_fs.h>
++#include <linux/workqueue.h>
++#include <asm/current.h>
++#include <linux/sched.h>
++#include <linux/module.h>
++#include <linux/crc32.h>
++#include <linux/sched.h>
++#include <linux/delayacct.h>
++#include <linux/seq_file.h>
++
++/*Enables/disables whole functionality of the module*/
++static int enabled = 1;
++module_param(enabled, bool, 0);
++MODULE_PARM_DESC(enabled,
++		 "Enables or disables whole app prefetching module functionality (tracing and prefetching)");
++
++static int initialized = 0;
++
++/*Controls whether prefetching should be done along with tracing.*/
++static int prefetch_enabled = 1;
++module_param(prefetch_enabled, bool, 0);
++MODULE_PARM_DESC(prefetch_enabled,
++		 "Enables or disables prefetching during app start. If disabled, only tracing will be done");
++
++/*Size of shortened name, together with hash it should be <=DNAME_INLINE_LEN_MIN*/
++static int short_name_len = 10;
++module_param(short_name_len, bool, 0);
++MODULE_PARM_DESC(short_name_len,
++		 "Length of shortened file name, used to name prefetch file together with hash of whole name");
++
++#define DEFAULT_APP_TRACE_FILENAME_TEMPLATE "/.prefetch/%s"
++static char *filename_template = DEFAULT_APP_TRACE_FILENAME_TEMPLATE;
++module_param(filename_template, charp, 0);
++MODULE_PARM_DESC(filename_template,
++		 "Template for application trace name, where trace will be saved and read from. %s will be replaced with name of application and hash. The default is: "
++		 DEFAULT_APP_TRACE_FILENAME_TEMPLATE);
++
++/*Size of hashtable for filenames*/
++static int filename_hashtable_size = 128;
++module_param(filename_hashtable_size, uint, 0);
++MODULE_PARM_DESC(filename_hashtable_size, "Size of hashtable for filenames");
++
++/**
++ * Time (in seconds) after which app tracing is stopped.
++*/
++static int tracing_timeout = 10;
++module_param(tracing_timeout, uint, 0);
++MODULE_PARM_DESC(tracing_timeout,
++		 "Time (in seconds) after which app tracing is stopped");
++
++/**
++ * IO ticks (in centisecs) threshold above which application will be traced and prefetching done.
++*/
++static int tracing_ticks_threshold = 200;
++module_param(tracing_ticks_threshold, uint, 0);
++MODULE_PARM_DESC(tracing_ticks_threshold,
++		 "IO ticks (in centisecs) threshold above which application will be traced and prefetching done");
++
++/**
++ * Hashtable of apps names blacklisted from tracing/prefetching.
++ * If filename is on this list, it will not be traced.
++ * Protected by prefetch_apps_blacklist_mutex.
++*/
++struct hlist_head *prefetch_apps_blacklist;
++DEFINE_MUTEX(prefetch_apps_blacklist_mutex);
++
++/**
++ * Hashtable of apps names which should be traced/prefetched.
++ * If filename is on this list, it means it has been decided that tracing/prefetching
++ * should be done for it.
++ * This list is protected by prefetch_apps_list_mutex.
++*/
++struct hlist_head *prefetch_apps_list;
++DEFINE_MUTEX(prefetch_apps_list_mutex);
++
++/**
++ * Entry in filename hashtable list.
++*/
++struct filename_entry {
++	struct hlist_node entries_list;
++	char *filename;
++};
++
++struct trace_job;
++
++/**
++ * Entry in traced pids hashtable list.
++*/
++struct traced_pid_entry {
++	struct hlist_node entries_list;
++	pid_t pid;
++	struct trace_job *trace_job;
++};
++
++#define TRACED_HASH_SIZE 16
++/**
++ * Hashtable of concurrently traced applications.
++ * The key is pid.
++ * Protected by traced_pids_mutex.
++*/
++struct hlist_head *traced_pids;
++
++DEFINE_MUTEX(traced_pids_mutex);
++
++/**
++ * Frees filename entry contents and entry itself.
++*/
++void free_filename_entry(struct filename_entry *entry)
++{
++	kfree(entry->filename);
++	kfree(entry);
++}
++
++void __clear_hashtable(struct hlist_head *list, int hashtable_size)
++{
++	struct filename_entry *entry;
++	struct hlist_node *cursor;
++	struct hlist_node *tmp;
++	int i;
++
++	for (i = 0; i < hashtable_size; ++i) {
++		hlist_for_each_entry_safe(entry, cursor, tmp, &list[i],
++					  entries_list) {
++			free_filename_entry(entry);
++		}
++		/* clear whole list at once */
++		INIT_HLIST_HEAD(&list[i]);
++	}
++}
++
++void clear_hashtable(struct hlist_head *list, int hashtable_size,
++		     struct mutex *mutex)
++{
++	mutex_lock(mutex);
++	__clear_hashtable(list, hashtable_size);
++	mutex_unlock(mutex);
++}
++
++int initialize_hashtable(struct hlist_head **list, int hashtable_size)
++{
++	struct hlist_head *h;
++	int i;
++
++	h = kmalloc(sizeof(struct hlist_head) * hashtable_size, GFP_KERNEL);
++	if (h == NULL)
++		return -ENOMEM;
++
++	for (i = 0; i < hashtable_size; ++i) {
++		INIT_HLIST_HEAD(&h[i]);
++	}
++
++	*list = h;
++	return 0;
++}
++
++u32 filename_hash(char *s)
++{
++	return crc32_le(0, s, strlen(s));
++}
++
++static inline unsigned filename_hashtable_index(char *filename)
++{
++	return filename_hash(filename) % filename_hashtable_size;
++}
++
++/**
++ * Checks if filename @filename is in hashtable @list
++ */
++int filename_on_list(char *filename, struct hlist_head *list)
++{
++	struct filename_entry *entry;
++	struct hlist_node *cursor;
++	unsigned hashtable_index = filename_hashtable_index(filename);
++
++	hlist_for_each_entry(entry, cursor, &list[hashtable_index],
++			     entries_list) {
++		if (strcmp(entry->filename, filename) == 0)
++			return 1;
++	}
++	return 0;
++}
++
++/**
++ * Adds filename @filename to hashtable @list
++ * Filename contents is copied.
++ * Proper mutex must be held.
++ */
++static int __add_filename_to_list(char *filename, struct hlist_head *list)
++{
++	int ret = 0;
++	struct filename_entry *entry = NULL;
++	unsigned hashtable_index = filename_hashtable_index(filename);
++
++	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
++	if (entry == NULL) {
++		ret = -ENOMEM;
++		goto out_error;
++	}
++	INIT_HLIST_NODE(&entry->entries_list);
++
++	entry->filename = kstrdup(filename, GFP_KERNEL);
++	if (entry->filename == NULL) {
++		ret = -ENOMEM;
++		goto out_error;
++	}
++
++	hlist_add_head(&entry->entries_list, &list[hashtable_index]);
++
++	return ret;
++
++      out_error:
++	if (entry != NULL) {
++		if (entry->filename != NULL)
++			kfree(entry->filename);
++		kfree(entry);
++	}
++	return ret;
++}
++
++static int add_filename_to_list_unique(char *filename, struct hlist_head *list,
++				       struct mutex *mutex)
++{
++	int ret = 0;
++
++	mutex_lock(mutex);
++	if (!filename_on_list(filename, list))
++		ret = __add_filename_to_list(filename, list);
++	mutex_unlock(mutex);
++
++	return ret;
++}
++
++/**
++ * Removes filename @filename from hashtable @list
++ * Frees filename entry and its contents.
++ * Returns true (non-zero) if entry was found and removed.
++ */
++int remove_filename_from_list(char *filename, struct hlist_head *list)
++{
++	struct filename_entry *entry;
++	struct hlist_node *cursor;
++	unsigned hashtable_index = filename_hashtable_index(filename);
++
++	hlist_for_each_entry(entry, cursor, &list[hashtable_index],
++			     entries_list) {
++		if (strcmp(entry->filename, filename) == 0) {
++			hlist_del(&entry->entries_list);
++			free_filename_entry(entry);
++			return 1;
++		}
++	}
++	return 0;
++}
++
++static inline unsigned traced_pid_hash(pid_t pid)
++{
++	return pid % TRACED_HASH_SIZE;
++}
++
++/**
++ * Adds pid @pid to traced pids with trace job @job.
++ */
++int add_traced_pid(pid_t pid, struct trace_job *job,
++		   struct hlist_head *hashtable)
++{
++	int ret = 0;
++	struct traced_pid_entry *entry = NULL;
++	unsigned hashtable_index = traced_pid_hash(pid);
++
++	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
++	if (entry == NULL) {
++		ret = -ENOMEM;
++		goto out_error;
++	}
++	INIT_HLIST_NODE(&entry->entries_list);
++	entry->trace_job = job;
++	entry->pid = pid;
++
++	hlist_add_head(&entry->entries_list, &hashtable[hashtable_index]);
++
++	return ret;
++
++      out_error:
++	kfree(entry);
++	return ret;
++}
++
++/**
++ * Removes trace job for pid @pid.
++ * Frees entry and its contents.
++ * Does not free job.
++ */
++int remove_traced_pid(pid_t pid, struct hlist_head *hashtable)
++{
++	struct traced_pid_entry *entry = NULL;
++	unsigned hashtable_index = traced_pid_hash(pid);
++	struct hlist_node *cursor;
++
++	hlist_for_each_entry(entry, cursor, &hashtable[hashtable_index],
++			     entries_list) {
++		if (entry->pid == pid) {
++			hlist_del(&entry->entries_list);
++			kfree(entry);
++			return 1;
++		}
++	}
++	return 0;
++}
++
++struct traced_pid_entry *find_traced_pid(pid_t pid,
++					 struct hlist_head *hashtable)
++{
++	struct traced_pid_entry *entry = NULL;
++	unsigned hashtable_index = traced_pid_hash(pid);
++	struct hlist_node *cursor;
++
++	hlist_for_each_entry(entry, cursor, &hashtable[hashtable_index],
++			     entries_list) {
++		if (entry->pid == pid)
++			return entry;
++	}
++	return NULL;
++}
++
++/**
++	Structure describing tracing or monitoring job.
++*/
++struct trace_job {
++	struct delayed_work work;
++	char *filename;
++	pid_t pid;
++	struct trace_marker start_marker;
++};
++
<<Diff was trimmed, longer than 597 lines>>


More information about the pld-cvs-commit mailing list