[PATCH v1 hot_track 03/18] vfs: add I/O frequency update function

2012-11-08 Thread zwu . kernel
From: Zhi Yong Wu 

  Add some util helpers to update access frequencies
for one file or its range.

Signed-off-by: Zhi Yong Wu 
---
 fs/hot_tracking.c|  174 ++
 fs/hot_tracking.h|5 +
 include/linux/hot_tracking.h |4 +
 3 files changed, 183 insertions(+), 0 deletions(-)

diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c
index 3118c0b..1142ef1 100644
--- a/fs/hot_tracking.c
+++ b/fs/hot_tracking.c
@@ -173,6 +173,131 @@ static void hot_inode_tree_exit(struct hot_info *root)
}
 }
 
+struct hot_inode_item
+*hot_inode_item_lookup(struct hot_info *root, unsigned long ino)
+{
+   struct hot_inode_item *he;
+   int ret;
+
+again:
+   spin_lock(>lock);
+   he = radix_tree_lookup(>hot_inode_tree, ino);
+   if (he) {
+   kref_get(>hot_inode.refs);
+   spin_unlock(>lock);
+   return he;
+   }
+   spin_unlock(>lock);
+
+   he = kmem_cache_zalloc(hot_inode_item_cachep, GFP_NOFS);
+   if (!he)
+   return ERR_PTR(-ENOMEM);
+
+   hot_inode_item_init(he, ino, >hot_inode_tree);
+
+   ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
+   if (ret) {
+   kmem_cache_free(hot_inode_item_cachep, he);
+   return ERR_PTR(ret);
+   }
+
+   spin_lock(>lock);
+   ret = radix_tree_insert(>hot_inode_tree, ino, he);
+   if (ret == -EEXIST) {
+   kmem_cache_free(hot_inode_item_cachep, he);
+   spin_unlock(>lock);
+   radix_tree_preload_end();
+   goto again;
+   }
+   spin_unlock(>lock);
+   radix_tree_preload_end();
+
+   kref_get(>hot_inode.refs);
+   return he;
+}
+EXPORT_SYMBOL_GPL(hot_inode_item_lookup);
+
+static struct hot_range_item
+*hot_range_item_lookup(struct hot_inode_item *he,
+   loff_t start)
+{
+   struct hot_range_item *hr;
+   int ret;
+
+again:
+   spin_lock(>lock);
+   hr = radix_tree_lookup(>hot_range_tree, start);
+   if (hr) {
+   kref_get(>hot_range.refs);
+   spin_unlock(>lock);
+   return hr;
+   }
+   spin_unlock(>lock);
+
+   hr = kmem_cache_zalloc(hot_range_item_cachep, GFP_NOFS);
+   if (!hr)
+   return ERR_PTR(-ENOMEM);
+
+   hot_range_item_init(hr, start, he);
+
+   ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
+   if (ret) {
+   kmem_cache_free(hot_range_item_cachep, hr);
+   return ERR_PTR(ret);
+   }
+
+   spin_lock(>lock);
+   ret = radix_tree_insert(>hot_range_tree, start, hr);
+   if (ret == -EEXIST) {
+   kmem_cache_free(hot_range_item_cachep, hr);
+   spin_unlock(>lock);
+   radix_tree_preload_end();
+   goto again;
+   }
+   spin_unlock(>lock);
+   radix_tree_preload_end();
+
+   kref_get(>hot_range.refs);
+   return hr;
+}
+
+/*
+ * This function does the actual work of updating
+ * the frequency numbers, whatever they turn out to be.
+ */
+static void hot_rw_freq_calc(struct timespec old_atime,
+   struct timespec cur_time, u64 *avg)
+{
+   struct timespec delta_ts;
+   u64 new_delta;
+
+   delta_ts = timespec_sub(cur_time, old_atime);
+   new_delta = timespec_to_ns(_ts) >> FREQ_POWER;
+
+   *avg = (*avg << FREQ_POWER) - *avg + new_delta;
+   *avg = *avg >> FREQ_POWER;
+}
+
+static void hot_freq_data_update(struct hot_freq_data *freq_data, bool write)
+{
+   struct timespec cur_time = current_kernel_time();
+
+   if (write) {
+   freq_data->nr_writes += 1;
+   hot_rw_freq_calc(freq_data->last_write_time,
+   cur_time,
+   _data->avg_delta_writes);
+   freq_data->last_write_time = cur_time;
+   } else {
+   freq_data->nr_reads += 1;
+   hot_rw_freq_calc(freq_data->last_read_time,
+   freq_data->last_read_time,
+   cur_time,
+   _data->avg_delta_reads);
+   freq_data->last_read_time = cur_time;
+   }
+}
+
 /*
  * Initialize kmem cache for hot_inode_item and hot_range_item.
  */
@@ -200,6 +325,55 @@ err:
 EXPORT_SYMBOL_GPL(hot_cache_init);
 
 /*
+ * Main function to update access frequency from read/writepage(s) hooks
+ */
+void hot_update_freqs(struct inode *inode, loff_t start,
+   size_t len, int rw)
+{
+   struct hot_info *root = inode->i_sb->s_hot_root;
+   struct hot_inode_item *he;
+   struct hot_range_item *hr;
+   loff_t cur, end;
+
+   if (!root || (len == 0))
+   return;
+
+   he = hot_inode_item_lookup(root, inode->i_ino);
+   if (IS_ERR(he)) {
+   WARN_ON(1);
+   return;
+   }
+
+   spin_lock(>hot_inode.lock);
+   

[PATCH v1 hot_track 03/18] vfs: add I/O frequency update function

2012-11-08 Thread zwu . kernel
From: Zhi Yong Wu wu...@linux.vnet.ibm.com

  Add some util helpers to update access frequencies
for one file or its range.

Signed-off-by: Zhi Yong Wu wu...@linux.vnet.ibm.com
---
 fs/hot_tracking.c|  174 ++
 fs/hot_tracking.h|5 +
 include/linux/hot_tracking.h |4 +
 3 files changed, 183 insertions(+), 0 deletions(-)

diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c
index 3118c0b..1142ef1 100644
--- a/fs/hot_tracking.c
+++ b/fs/hot_tracking.c
@@ -173,6 +173,131 @@ static void hot_inode_tree_exit(struct hot_info *root)
}
 }
 
+struct hot_inode_item
+*hot_inode_item_lookup(struct hot_info *root, unsigned long ino)
+{
+   struct hot_inode_item *he;
+   int ret;
+
+again:
+   spin_lock(root-lock);
+   he = radix_tree_lookup(root-hot_inode_tree, ino);
+   if (he) {
+   kref_get(he-hot_inode.refs);
+   spin_unlock(root-lock);
+   return he;
+   }
+   spin_unlock(root-lock);
+
+   he = kmem_cache_zalloc(hot_inode_item_cachep, GFP_NOFS);
+   if (!he)
+   return ERR_PTR(-ENOMEM);
+
+   hot_inode_item_init(he, ino, root-hot_inode_tree);
+
+   ret = radix_tree_preload(GFP_NOFS  ~__GFP_HIGHMEM);
+   if (ret) {
+   kmem_cache_free(hot_inode_item_cachep, he);
+   return ERR_PTR(ret);
+   }
+
+   spin_lock(root-lock);
+   ret = radix_tree_insert(root-hot_inode_tree, ino, he);
+   if (ret == -EEXIST) {
+   kmem_cache_free(hot_inode_item_cachep, he);
+   spin_unlock(root-lock);
+   radix_tree_preload_end();
+   goto again;
+   }
+   spin_unlock(root-lock);
+   radix_tree_preload_end();
+
+   kref_get(he-hot_inode.refs);
+   return he;
+}
+EXPORT_SYMBOL_GPL(hot_inode_item_lookup);
+
+static struct hot_range_item
+*hot_range_item_lookup(struct hot_inode_item *he,
+   loff_t start)
+{
+   struct hot_range_item *hr;
+   int ret;
+
+again:
+   spin_lock(he-lock);
+   hr = radix_tree_lookup(he-hot_range_tree, start);
+   if (hr) {
+   kref_get(hr-hot_range.refs);
+   spin_unlock(he-lock);
+   return hr;
+   }
+   spin_unlock(he-lock);
+
+   hr = kmem_cache_zalloc(hot_range_item_cachep, GFP_NOFS);
+   if (!hr)
+   return ERR_PTR(-ENOMEM);
+
+   hot_range_item_init(hr, start, he);
+
+   ret = radix_tree_preload(GFP_NOFS  ~__GFP_HIGHMEM);
+   if (ret) {
+   kmem_cache_free(hot_range_item_cachep, hr);
+   return ERR_PTR(ret);
+   }
+
+   spin_lock(he-lock);
+   ret = radix_tree_insert(he-hot_range_tree, start, hr);
+   if (ret == -EEXIST) {
+   kmem_cache_free(hot_range_item_cachep, hr);
+   spin_unlock(he-lock);
+   radix_tree_preload_end();
+   goto again;
+   }
+   spin_unlock(he-lock);
+   radix_tree_preload_end();
+
+   kref_get(hr-hot_range.refs);
+   return hr;
+}
+
+/*
+ * This function does the actual work of updating
+ * the frequency numbers, whatever they turn out to be.
+ */
+static void hot_rw_freq_calc(struct timespec old_atime,
+   struct timespec cur_time, u64 *avg)
+{
+   struct timespec delta_ts;
+   u64 new_delta;
+
+   delta_ts = timespec_sub(cur_time, old_atime);
+   new_delta = timespec_to_ns(delta_ts)  FREQ_POWER;
+
+   *avg = (*avg  FREQ_POWER) - *avg + new_delta;
+   *avg = *avg  FREQ_POWER;
+}
+
+static void hot_freq_data_update(struct hot_freq_data *freq_data, bool write)
+{
+   struct timespec cur_time = current_kernel_time();
+
+   if (write) {
+   freq_data-nr_writes += 1;
+   hot_rw_freq_calc(freq_data-last_write_time,
+   cur_time,
+   freq_data-avg_delta_writes);
+   freq_data-last_write_time = cur_time;
+   } else {
+   freq_data-nr_reads += 1;
+   hot_rw_freq_calc(freq_data-last_read_time,
+   freq_data-last_read_time,
+   cur_time,
+   freq_data-avg_delta_reads);
+   freq_data-last_read_time = cur_time;
+   }
+}
+
 /*
  * Initialize kmem cache for hot_inode_item and hot_range_item.
  */
@@ -200,6 +325,55 @@ err:
 EXPORT_SYMBOL_GPL(hot_cache_init);
 
 /*
+ * Main function to update access frequency from read/writepage(s) hooks
+ */
+void hot_update_freqs(struct inode *inode, loff_t start,
+   size_t len, int rw)
+{
+   struct hot_info *root = inode-i_sb-s_hot_root;
+   struct hot_inode_item *he;
+   struct hot_range_item *hr;
+   loff_t cur, end;
+
+   if (!root || (len == 0))
+   return;
+
+   he = hot_inode_item_lookup(root, inode-i_ino);
+   if (IS_ERR(he)) {
+