Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Thu, Nov 8, 2012 at 2:49 AM, Darrick J. Wong wrote: > On Wed, Nov 07, 2012 at 04:27:05PM +0800, Zhi Yong Wu wrote: >> On Wed, Nov 7, 2012 at 6:45 AM, Darrick J. Wong >> wrote: >> > On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: >> >> 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| 179 >> >> ++ >> >> fs/hot_tracking.h|7 ++ >> >> include/linux/hot_tracking.h |2 + >> >> 3 files changed, 188 insertions(+), 0 deletions(-) >> >> >> >> diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c >> >> index 68591f0..0a7d9a3 100644 >> >> --- a/fs/hot_tracking.c >> >> +++ b/fs/hot_tracking.c >> >> @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info >> >> *root) >> >> } >> >> } >> >> >> >> +struct hot_inode_item >> >> +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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_find); >> >> + >> >> +static struct hot_range_item >> >> +*hot_range_item_find(struct hot_inode_item *he, >> >> + u32 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_KERNEL | 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 u64 hot_average_update(struct timespec old_atime, >> >> + struct timespec cur_time, u64 old_avg) >> >> +{ >> >> + struct timespec delta_ts; >> >> + u64 new_avg; >> >> + u64 new_delta; >> >> + >> >> + delta_ts = timespec_sub(cur_time, old_atime); >> >> + new_delta = timespec_to_ns(_ts) >> FREQ_POWER; >> >> + >> >> + new_avg = (old_avg << FREQ_POWER) - old_avg + new_delta; >> >> + new_avg = new_avg >> FREQ_POWER; >> >> + >> >> + return new_avg; >> >> +} >> >> + >> >> +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; >> >> + freq_data->avg_delta_writes = hot_average_update( >> >> + freq_data->last_write_time, >> >> + cur_time, >> >> +
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Wed, Nov 07, 2012 at 04:27:05PM +0800, Zhi Yong Wu wrote: > On Wed, Nov 7, 2012 at 6:45 AM, Darrick J. Wong > wrote: > > On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: > >> 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| 179 > >> ++ > >> fs/hot_tracking.h|7 ++ > >> include/linux/hot_tracking.h |2 + > >> 3 files changed, 188 insertions(+), 0 deletions(-) > >> > >> diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c > >> index 68591f0..0a7d9a3 100644 > >> --- a/fs/hot_tracking.c > >> +++ b/fs/hot_tracking.c > >> @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info > >> *root) > >> } > >> } > >> > >> +struct hot_inode_item > >> +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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_find); > >> + > >> +static struct hot_range_item > >> +*hot_range_item_find(struct hot_inode_item *he, > >> + u32 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_KERNEL | 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 u64 hot_average_update(struct timespec old_atime, > >> + struct timespec cur_time, u64 old_avg) > >> +{ > >> + struct timespec delta_ts; > >> + u64 new_avg; > >> + u64 new_delta; > >> + > >> + delta_ts = timespec_sub(cur_time, old_atime); > >> + new_delta = timespec_to_ns(_ts) >> FREQ_POWER; > >> + > >> + new_avg = (old_avg << FREQ_POWER) - old_avg + new_delta; > >> + new_avg = new_avg >> FREQ_POWER; > >> + > >> + return new_avg; > >> +} > >> + > >> +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; > >> + freq_data->avg_delta_writes = hot_average_update( > >> + 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; > >> + freq_data->avg_delta_reads =
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Wed, Nov 7, 2012 at 6:45 AM, Darrick J. Wong wrote: > On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: >> 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| 179 >> ++ >> fs/hot_tracking.h|7 ++ >> include/linux/hot_tracking.h |2 + >> 3 files changed, 188 insertions(+), 0 deletions(-) >> >> diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c >> index 68591f0..0a7d9a3 100644 >> --- a/fs/hot_tracking.c >> +++ b/fs/hot_tracking.c >> @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) >> } >> } >> >> +struct hot_inode_item >> +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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_find); >> + >> +static struct hot_range_item >> +*hot_range_item_find(struct hot_inode_item *he, >> + u32 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_KERNEL | 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 u64 hot_average_update(struct timespec old_atime, >> + struct timespec cur_time, u64 old_avg) >> +{ >> + struct timespec delta_ts; >> + u64 new_avg; >> + u64 new_delta; >> + >> + delta_ts = timespec_sub(cur_time, old_atime); >> + new_delta = timespec_to_ns(_ts) >> FREQ_POWER; >> + >> + new_avg = (old_avg << FREQ_POWER) - old_avg + new_delta; >> + new_avg = new_avg >> FREQ_POWER; >> + >> + return new_avg; >> +} >> + >> +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; >> + freq_data->avg_delta_writes = hot_average_update( >> + 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; >> + freq_data->avg_delta_reads = hot_average_update( >> + freq_data->last_read_time, >> + cur_time, >> + freq_data->avg_delta_reads); > > I think you could just pass in a pointer to > freq_data->avg_delta_{writes,reads} here... why? > >> + freq_data->last_read_time = cur_time; >> + } >> +} >> + >> /* >> *
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Wed, Nov 7, 2012 at 6:45 AM, Darrick J. Wong darrick.w...@oracle.com wrote: On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: 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| 179 ++ fs/hot_tracking.h|7 ++ include/linux/hot_tracking.h |2 + 3 files changed, 188 insertions(+), 0 deletions(-) diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c index 68591f0..0a7d9a3 100644 --- a/fs/hot_tracking.c +++ b/fs/hot_tracking.c @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) } } +struct hot_inode_item +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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_find); + +static struct hot_range_item +*hot_range_item_find(struct hot_inode_item *he, + u32 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_KERNEL | 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 u64 hot_average_update(struct timespec old_atime, + struct timespec cur_time, u64 old_avg) +{ + struct timespec delta_ts; + u64 new_avg; + u64 new_delta; + + delta_ts = timespec_sub(cur_time, old_atime); + new_delta = timespec_to_ns(delta_ts) FREQ_POWER; + + new_avg = (old_avg FREQ_POWER) - old_avg + new_delta; + new_avg = new_avg FREQ_POWER; + + return new_avg; +} + +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; + freq_data-avg_delta_writes = hot_average_update( + 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; + freq_data-avg_delta_reads = hot_average_update( + freq_data-last_read_time, + cur_time, + freq_data-avg_delta_reads); I think you could just pass in a pointer to freq_data-avg_delta_{writes,reads} here... why? + freq_data-last_read_time = cur_time; + } +} + /* * Initialize kmem cache for hot_inode_item and hot_range_item. */ @@ -199,6 +330,54 @@ err: EXPORT_SYMBOL_GPL(hot_cache_init); /* + * Main function to update access frequency from
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Wed, Nov 07, 2012 at 04:27:05PM +0800, Zhi Yong Wu wrote: On Wed, Nov 7, 2012 at 6:45 AM, Darrick J. Wong darrick.w...@oracle.com wrote: On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: 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| 179 ++ fs/hot_tracking.h|7 ++ include/linux/hot_tracking.h |2 + 3 files changed, 188 insertions(+), 0 deletions(-) diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c index 68591f0..0a7d9a3 100644 --- a/fs/hot_tracking.c +++ b/fs/hot_tracking.c @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) } } +struct hot_inode_item +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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_find); + +static struct hot_range_item +*hot_range_item_find(struct hot_inode_item *he, + u32 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_KERNEL | 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 u64 hot_average_update(struct timespec old_atime, + struct timespec cur_time, u64 old_avg) +{ + struct timespec delta_ts; + u64 new_avg; + u64 new_delta; + + delta_ts = timespec_sub(cur_time, old_atime); + new_delta = timespec_to_ns(delta_ts) FREQ_POWER; + + new_avg = (old_avg FREQ_POWER) - old_avg + new_delta; + new_avg = new_avg FREQ_POWER; + + return new_avg; +} + +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; + freq_data-avg_delta_writes = hot_average_update( + 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; + freq_data-avg_delta_reads = hot_average_update( + freq_data-last_read_time, + cur_time, + freq_data-avg_delta_reads); I think you could just pass in a pointer to freq_data-avg_delta_{writes,reads} here... why? freq_data-avg_delta_{reads,writes} seems to be an in/out
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Thu, Nov 8, 2012 at 2:49 AM, Darrick J. Wong darrick.w...@oracle.com wrote: On Wed, Nov 07, 2012 at 04:27:05PM +0800, Zhi Yong Wu wrote: On Wed, Nov 7, 2012 at 6:45 AM, Darrick J. Wong darrick.w...@oracle.com wrote: On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: 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| 179 ++ fs/hot_tracking.h|7 ++ include/linux/hot_tracking.h |2 + 3 files changed, 188 insertions(+), 0 deletions(-) diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c index 68591f0..0a7d9a3 100644 --- a/fs/hot_tracking.c +++ b/fs/hot_tracking.c @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) } } +struct hot_inode_item +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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_find); + +static struct hot_range_item +*hot_range_item_find(struct hot_inode_item *he, + u32 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_KERNEL | 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 u64 hot_average_update(struct timespec old_atime, + struct timespec cur_time, u64 old_avg) +{ + struct timespec delta_ts; + u64 new_avg; + u64 new_delta; + + delta_ts = timespec_sub(cur_time, old_atime); + new_delta = timespec_to_ns(delta_ts) FREQ_POWER; + + new_avg = (old_avg FREQ_POWER) - old_avg + new_delta; + new_avg = new_avg FREQ_POWER; + + return new_avg; +} + +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; + freq_data-avg_delta_writes = hot_average_update( + 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; + freq_data-avg_delta_reads = hot_average_update( + freq_data-last_read_time, + cur_time, + freq_data-avg_delta_reads); I think you could just pass in a pointer to
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Wed, Nov 7, 2012 at 6:37 AM, David Sterba wrote: > On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: >> --- a/fs/hot_tracking.c >> +++ b/fs/hot_tracking.c >> +struct hot_inode_item >> +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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); > > radix_tree_preload_end() > >> + 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_find); >> + >> +static struct hot_range_item >> +*hot_range_item_find(struct hot_inode_item *he, >> + u32 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_KERNEL | 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); > > radix_tree_preload_end() I checked some kernel existing cases about the usage of radix_tree_preload(), it seems that when radix_tree_preload() fail, its error handling doesn't need call radix_tree_preload_end() any more. > >> + 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(); ditto. >> + goto again; >> + } >> + spin_unlock(>lock); >> + radix_tree_preload_end(); >> + >> + kref_get(>hot_range.refs); >> + return hr; >> +} > > david -- Regards, Zhi Yong Wu -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: > 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| 179 > ++ > fs/hot_tracking.h|7 ++ > include/linux/hot_tracking.h |2 + > 3 files changed, 188 insertions(+), 0 deletions(-) > > diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c > index 68591f0..0a7d9a3 100644 > --- a/fs/hot_tracking.c > +++ b/fs/hot_tracking.c > @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) > } > } > > +struct hot_inode_item > +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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_find); > + > +static struct hot_range_item > +*hot_range_item_find(struct hot_inode_item *he, > + u32 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_KERNEL | 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 u64 hot_average_update(struct timespec old_atime, > + struct timespec cur_time, u64 old_avg) > +{ > + struct timespec delta_ts; > + u64 new_avg; > + u64 new_delta; > + > + delta_ts = timespec_sub(cur_time, old_atime); > + new_delta = timespec_to_ns(_ts) >> FREQ_POWER; > + > + new_avg = (old_avg << FREQ_POWER) - old_avg + new_delta; > + new_avg = new_avg >> FREQ_POWER; > + > + return new_avg; > +} > + > +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; > + freq_data->avg_delta_writes = hot_average_update( > + 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; > + freq_data->avg_delta_reads = hot_average_update( > + freq_data->last_read_time, > + cur_time, > + freq_data->avg_delta_reads); I think you could just pass in a pointer to freq_data->avg_delta_{writes,reads} here... > + freq_data->last_read_time = cur_time; > + } > +} > + > /* > * Initialize kmem cache for hot_inode_item and hot_range_item. > */ > @@ -199,6 +330,54 @@ err: > EXPORT_SYMBOL_GPL(hot_cache_init); > > /* > + * Main function to update access frequency from read/writepage(s) hooks > + */
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: > --- a/fs/hot_tracking.c > +++ b/fs/hot_tracking.c > +struct hot_inode_item > +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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); radix_tree_preload_end() > + 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_find); > + > +static struct hot_range_item > +*hot_range_item_find(struct hot_inode_item *he, > + u32 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_KERNEL | 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); radix_tree_preload_end() > + 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; > +} david -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: --- a/fs/hot_tracking.c +++ b/fs/hot_tracking.c +struct hot_inode_item +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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); radix_tree_preload_end() + 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_find); + +static struct hot_range_item +*hot_range_item_find(struct hot_inode_item *he, + u32 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_KERNEL | 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); radix_tree_preload_end() + 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; +} david -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: 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| 179 ++ fs/hot_tracking.h|7 ++ include/linux/hot_tracking.h |2 + 3 files changed, 188 insertions(+), 0 deletions(-) diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c index 68591f0..0a7d9a3 100644 --- a/fs/hot_tracking.c +++ b/fs/hot_tracking.c @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) } } +struct hot_inode_item +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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_find); + +static struct hot_range_item +*hot_range_item_find(struct hot_inode_item *he, + u32 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_KERNEL | 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 u64 hot_average_update(struct timespec old_atime, + struct timespec cur_time, u64 old_avg) +{ + struct timespec delta_ts; + u64 new_avg; + u64 new_delta; + + delta_ts = timespec_sub(cur_time, old_atime); + new_delta = timespec_to_ns(delta_ts) FREQ_POWER; + + new_avg = (old_avg FREQ_POWER) - old_avg + new_delta; + new_avg = new_avg FREQ_POWER; + + return new_avg; +} + +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; + freq_data-avg_delta_writes = hot_average_update( + 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; + freq_data-avg_delta_reads = hot_average_update( + freq_data-last_read_time, + cur_time, + freq_data-avg_delta_reads); I think you could just pass in a pointer to freq_data-avg_delta_{writes,reads} here... + freq_data-last_read_time = cur_time; + } +} + /* * Initialize kmem cache for hot_inode_item and hot_range_item. */ @@ -199,6 +330,54 @@ 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, u64 start, +
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Wed, Nov 7, 2012 at 6:37 AM, David Sterba d...@jikos.cz wrote: On Mon, Oct 29, 2012 at 12:30:45PM +0800, zwu.ker...@gmail.com wrote: --- a/fs/hot_tracking.c +++ b/fs/hot_tracking.c +struct hot_inode_item +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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); radix_tree_preload_end() + 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_find); + +static struct hot_range_item +*hot_range_item_find(struct hot_inode_item *he, + u32 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_KERNEL | 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); radix_tree_preload_end() I checked some kernel existing cases about the usage of radix_tree_preload(), it seems that when radix_tree_preload() fail, its error handling doesn't need call radix_tree_preload_end() any more. + 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(); ditto. + goto again; + } + spin_unlock(he-lock); + radix_tree_preload_end(); + + kref_get(hr-hot_range.refs); + return hr; +} david -- Regards, Zhi Yong Wu -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Mon, Nov 5, 2012 at 7:07 PM, Steven Whitehouse wrote: > Hi, > > On Mon, 2012-10-29 at 12:30 +0800, zwu.ker...@gmail.com wrote: >> 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| 179 >> ++ >> fs/hot_tracking.h|7 ++ >> include/linux/hot_tracking.h |2 + >> 3 files changed, 188 insertions(+), 0 deletions(-) >> >> diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c >> index 68591f0..0a7d9a3 100644 >> --- a/fs/hot_tracking.c >> +++ b/fs/hot_tracking.c >> @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) >> } >> } >> >> +struct hot_inode_item >> +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | GFP_NOFS); > This doesn't look quite right... which of these two did you mean? I > assume probably just GFP_NOFS Yes, good catch, thanks. > >> + 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_find); >> + >> +static struct hot_range_item >> +*hot_range_item_find(struct hot_inode_item *he, >> + u32 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_KERNEL | GFP_NOFS); > Likewise, here too. ditto > > Steve. > > > -- Regards, Zhi Yong Wu -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
Hi, On Mon, 2012-10-29 at 12:30 +0800, zwu.ker...@gmail.com wrote: > 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| 179 > ++ > fs/hot_tracking.h|7 ++ > include/linux/hot_tracking.h |2 + > 3 files changed, 188 insertions(+), 0 deletions(-) > > diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c > index 68591f0..0a7d9a3 100644 > --- a/fs/hot_tracking.c > +++ b/fs/hot_tracking.c > @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) > } > } > > +struct hot_inode_item > +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | GFP_NOFS); This doesn't look quite right... which of these two did you mean? I assume probably just 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_find); > + > +static struct hot_range_item > +*hot_range_item_find(struct hot_inode_item *he, > + u32 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_KERNEL | GFP_NOFS); Likewise, here too. Steve. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
Hi, On Mon, 2012-10-29 at 12:30 +0800, zwu.ker...@gmail.com wrote: 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| 179 ++ fs/hot_tracking.h|7 ++ include/linux/hot_tracking.h |2 + 3 files changed, 188 insertions(+), 0 deletions(-) diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c index 68591f0..0a7d9a3 100644 --- a/fs/hot_tracking.c +++ b/fs/hot_tracking.c @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) } } +struct hot_inode_item +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | GFP_NOFS); This doesn't look quite right... which of these two did you mean? I assume probably just 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_find); + +static struct hot_range_item +*hot_range_item_find(struct hot_inode_item *he, + u32 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_KERNEL | GFP_NOFS); Likewise, here too. Steve. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
On Mon, Nov 5, 2012 at 7:07 PM, Steven Whitehouse swhit...@redhat.com wrote: Hi, On Mon, 2012-10-29 at 12:30 +0800, zwu.ker...@gmail.com wrote: 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| 179 ++ fs/hot_tracking.h|7 ++ include/linux/hot_tracking.h |2 + 3 files changed, 188 insertions(+), 0 deletions(-) diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c index 68591f0..0a7d9a3 100644 --- a/fs/hot_tracking.c +++ b/fs/hot_tracking.c @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) } } +struct hot_inode_item +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | GFP_NOFS); This doesn't look quite right... which of these two did you mean? I assume probably just GFP_NOFS Yes, good catch, thanks. + 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_find); + +static struct hot_range_item +*hot_range_item_find(struct hot_inode_item *he, + u32 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_KERNEL | GFP_NOFS); Likewise, here too. ditto Steve. -- Regards, Zhi Yong Wu -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
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| 179 ++ fs/hot_tracking.h|7 ++ include/linux/hot_tracking.h |2 + 3 files changed, 188 insertions(+), 0 deletions(-) diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c index 68591f0..0a7d9a3 100644 --- a/fs/hot_tracking.c +++ b/fs/hot_tracking.c @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) } } +struct hot_inode_item +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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_find); + +static struct hot_range_item +*hot_range_item_find(struct hot_inode_item *he, + u32 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_KERNEL | 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 u64 hot_average_update(struct timespec old_atime, + struct timespec cur_time, u64 old_avg) +{ + struct timespec delta_ts; + u64 new_avg; + u64 new_delta; + + delta_ts = timespec_sub(cur_time, old_atime); + new_delta = timespec_to_ns(_ts) >> FREQ_POWER; + + new_avg = (old_avg << FREQ_POWER) - old_avg + new_delta; + new_avg = new_avg >> FREQ_POWER; + + return new_avg; +} + +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; + freq_data->avg_delta_writes = hot_average_update( + 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; + freq_data->avg_delta_reads = hot_average_update( + 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. */ @@ -199,6 +330,54 @@ 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, u64 start, + u64 len, int rw) +{ + struct hot_info *root = inode->i_sb->s_hot_root; + struct hot_inode_item *he; + struct hot_range_item *hr; + u32 cur, end; + + if (!root || (len == 0)) +
[RFC v4+ hot_track 03/19] vfs: add I/O frequency update function
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| 179 ++ fs/hot_tracking.h|7 ++ include/linux/hot_tracking.h |2 + 3 files changed, 188 insertions(+), 0 deletions(-) diff --git a/fs/hot_tracking.c b/fs/hot_tracking.c index 68591f0..0a7d9a3 100644 --- a/fs/hot_tracking.c +++ b/fs/hot_tracking.c @@ -172,6 +172,137 @@ static void hot_inode_tree_exit(struct hot_info *root) } } +struct hot_inode_item +*hot_inode_item_find(struct hot_info *root, u64 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_KERNEL | 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_find); + +static struct hot_range_item +*hot_range_item_find(struct hot_inode_item *he, + u32 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_KERNEL | 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 u64 hot_average_update(struct timespec old_atime, + struct timespec cur_time, u64 old_avg) +{ + struct timespec delta_ts; + u64 new_avg; + u64 new_delta; + + delta_ts = timespec_sub(cur_time, old_atime); + new_delta = timespec_to_ns(delta_ts) FREQ_POWER; + + new_avg = (old_avg FREQ_POWER) - old_avg + new_delta; + new_avg = new_avg FREQ_POWER; + + return new_avg; +} + +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; + freq_data-avg_delta_writes = hot_average_update( + 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; + freq_data-avg_delta_reads = hot_average_update( + 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. */ @@ -199,6 +330,54 @@ 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, u64 start, + u64 len, int rw) +{ + struct hot_info *root = inode-i_sb-s_hot_root; + struct hot_inode_item *he; + struct