VFS hot tracking
Subsystems (8)
v2 cover VFS hot tracking
From: Zhi Yong Wu <[email protected]>
The patchset is trying to introduce hot tracking function in
VFS layer, which will keep track of real disk I/O in memory. By it, you will easily know more details about disk I/O, and then detect where disk I/O hot spots are. Also, specific FS can take use of it to do accurate defragment, and hot relocation support, etc.
After V1 was sent out, Chandra Seetharaman has reviewed and
made a lot of comments, thanks a lot to him. Not it's time to send out its V2 for external review, any comments or ideas are appreciated, thanks.
NOTE:
The patchset can be obtained via my kernel dev git on github:git://github.com/wuzhy/kernel.git hot_tracking
If you're interested, you can also review them via
https://github.com/wuzhy/kernel/commits/hot_tracking
For how to use and more other info and performance report,
please check hot_tracking.txt in Documentation and following links:
1.) http://lwn.net/Articles/525651/
2.) https://lkml.org/lkml/2012/12/20/199
Changelog from v1:
- Refactored to be under RCU [Chandra Seetharaman]
- Merged some code changes [Chandra Seetharaman]
- Fixed some issues [Chandra Seetharaman]
v1:
- Solved 64 bits inode number issue. [David Sterba]
- Embed struct hot_type in struct file_system_type [Darrick J. Wong]
- Cleanup Some issues [David Sterba]
- Use a static hot debugfs root [Greg KH]
rfcv4:
- Introduce hot func registering framework [Zhiyong]
- Remove global variable for hot tracking [Zhiyong]
- Add btrfs hot tracking support [Zhiyong]
rfcv3:
1.) Rewritten debugfs support based seq_file operation. [Dave Chinner] 2.) Refactored workqueue support. [Dave Chinner]
3.) Turn some Micro into be tunable [Zhiyong, Liu Zheng]
TIME_TO_KICK, and HEAT_UPDATE_DELAY
4.) Cleanedup a lot of other issues [Dave Chinner]
rfcv2:
1.) Converted to Radix trees, not RB-tree [Zhiyong, Dave Chinner] 2.) Added memory shrinker [Dave Chinner]
3.) Converted to one workqueue to update map info periodically [Dave Chinner] 4.) Cleanedup a lot of other issues [Dave Chinner]
rfcv1:
1.) Reduce new files and put all in fs/hot_tracking.[ch] [Dave Chinner] 2.) The first three patches can probably just be flattened into one.
[Marco Stornelli , Dave Chinner]
Zhi Yong Wu (12):
VFS hot tracking: introduce some data structures VFS hot tracking: add i/o freq tracking hooks
VFS hot tracking: add one workqueue to update hot map VFS hot tracking: register one shrinker
VFS hot tracking, rcu: introduce one rcu macro for list VFS hot tracking, seq_file: introduce one set of rcu seq_list
interfaces
VFS hot tracking: add debugfs support
VFS hot tracking: add one ioctl interface
VFS hot tracking, procfs: add two proc interfaces VFS hot tracking, btrfs: add hot tracking support VFS hot tracking: add documentation
VFS hot tracking: add fs hot type support
Documentation/filesystems/00-INDEX | 2 + Documentation/filesystems/hot_tracking.txt | 256 ++++++ fs/Makefile | 2 +- fs/btrfs/ctree.h | 1 + fs/btrfs/super.c | 22 +- fs/compat_ioctl.c | 5 + fs/dcache.c | 2 + fs/direct-io.c | 5 + fs/hot_tracking.c | 1320 ++++++++++++++++++++++++++++ fs/hot_tracking.h | 67 ++ fs/ioctl.c | 70 ++ fs/namei.c | 2 + fs/seq_file.c | 37 + include/linux/fs.h | 5 + include/linux/hot_tracking.h | 175 ++++ include/linux/rculist.h | 5 + include/linux/seq_file.h | 7 + kernel/sysctl.c | 14 + mm/filemap.c | 6 + mm/page-writeback.c | 12 + mm/readahead.c | 6 + 21 files changed, 2019 insertions(+), 2 deletions(-) create mode 100644 Documentation/filesystems/hot_tracking.txt create mode 100644 fs/hot_tracking.c create mode 100644 fs/hot_tracking.h create mode 100644 include/linux/hot_tracking.h
Signature · 1 line
1.7.11.7
PATCH v2 1/12 VFS hot tracking: introduce some data structures
From: Zhi Yong Wu <[email protected]>
One root structure hot_info is defined, is hooked
up in super_block, and will be used to hold radix tree root, hash list root and some other information, etc.
Adds hot_inode_tree struct to keep track of
frequently accessed files, and be keyed by {inode, offset}. Trees contain hot_inode_items representing those files and ranges.
Having these trees means that vfs can quickly determine the
temperature of some data by doing some calculations on the hot_freq_data struct that hangs off of the tree item.
Define two items hot_inode_item and hot_range_item,
one of them represents one tracked file
to keep track of its access frequency and the tree of ranges in this file, while the latter represents
a file range of one inode.
--- fs/Makefile | 2 +- fs/dcache.c | 2 + fs/hot_tracking.c | 209 +++++++++++++++++++++++++++++++++++++++++++ fs/hot_tracking.h | 17 ++++ include/linux/fs.h | 4 + include/linux/hot_tracking.h | 103 +++++++++++++++++++++ 6 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 fs/hot_tracking.c create mode 100644 fs/hot_tracking.h create mode 100644 include/linux/hot_tracking.h
fs/Makefile +1 -1
@@ -13,7 +13,7 @@ obj-y := open.o read_write.o file_table.o super.o \ attr.o bad_inode.o file.o filesystems.o namespace.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ pnode.o splice.o sync.o utimes.o \ - stack.o fs_struct.o statfs.o + stack.o fs_struct.o statfs.o hot_tracking.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
fs/dcache.c +2 -0
@@ -37,6 +37,7 @@#include <linux/rculist_bl.h> #include <linux/prefetch.h> #include <linux/ratelimit.h> +#include <linux/hot_tracking.h> #include "internal.h" #include "mount.h"
@@ -3094,4 +3095,5 @@ void __init vfs_caches_init(unsigned long mempages)mnt_init ();bdev_cache_init ();chrdev_init (); +hot_cache_init (); }
fs/hot_tracking.c new file +209 -0
209 lines not on this page · raw message
fs/hot_tracking.h new file +17 -0
@@ -0,0 +1,17 @@ +/* +* fs/hot_tracking.h +* +* Copyright (C) 2013 IBM Corp. All rights reserved. +* Written by Zhi Yong Wu <[email protected]> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public +* License v2 as published by the Free Software Foundation. +*/ + +#ifndef __HOT_TRACKING__ +#define __HOT_TRACKING__ + +#include <linux/hot_tracking.h> + +#endif /* __HOT_TRACKING__ */
include/linux/fs.h +4 -0
@@ -27,6 +27,7 @@#include <linux/lockdep.h> #include <linux/percpu-rwsem.h> #include <linux/blk_types.h> +#include <linux/hot_tracking.h> #include <asm/byteorder.h> #include <uapi/linux/fs.h>
@@ -1322,6 +1323,9 @@ struct super_block {/* Being remounted read-only */ int s_readonly_remount; + +/* Hot data tracking*/ +struct hot_info *s_hot_root; };/* superblock cache pruning functions */
include/linux/hot_tracking.h new file +103 -0
103 lines not on this page · raw message
Signature · 1 line
1.7.11.7
PATCH v2 2/12 VFS hot tracking: add i/o freq tracking hooks
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
Add i/o freq tracking hooks in real read/write code paths
which include read_pages(), do_writepages(), do_generic_file_read(), and __blockdev_direct_IO().
Currently whole FS has one RB tree to track i/o freqs for
all inodes which had real disk i/o, while every inode has its own one RB tree to track i/o freqs for all of its extents.
When real disk i/o for the inode are done, its own i/o freq will
be created or updated in the RB tree per FS, and the i/o freq for all of its extents will also be done in the RB-tree per inode.
Also, Each of the two structures hot_inode_item and hot_range_item
contains a hot_freq_data struct with its frequency of access metrics (number of {reads, writes}, last {read,write} time, frequency of {reads,writes}).
Also, each hot_inode_item contains one hot_range_tree
struct which is keyed by {inode, offset, length}
and used to keep track of all the ranges in this file.
--- fs/direct-io.c | 5 + fs/hot_tracking.c | 284 +++++++++++++++++++++++++++++++++++++++++++ fs/hot_tracking.h | 4 + fs/namei.c | 2 + include/linux/hot_tracking.h | 17 +++ mm/filemap.c | 6 + mm/page-writeback.c | 12 ++ mm/readahead.c | 6 + 8 files changed, 336 insertions(+)
fs/direct-io.c +5 -0
@@ -38,6 +38,7 @@#include <linux/atomic.h> #include <linux/prefetch.h> #include <linux/aio.h> +#include "hot_tracking.h" /* * How many user pages to map in one call to get_user_pages(). This determines
@@ -1295,6 +1296,10 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,prefetch (bdev->bd_queue);prefetch ((char *)bdev->bd_queue +SMP_CACHE_BYTES ); +/* Hot data tracking */ +hot_update_freqs (inode, offset,iov_length (iov, nr_segs), + rw &WRITE ); +return do_blockdev_direct_IO (rw, iocb, inode, bdev, iov, offset, nr_segs, get_block, end_io, submit_io, flags);
fs/hot_tracking.c +284 -0
318 lines not on this page · raw message
fs/hot_tracking.h +4 -0
@@ -14,4 +14,8 @@#include <linux/hot_tracking.h> +/* size of sub-file ranges */ +#define RANGE_BITS 20 +#define FREQ_POWER 4 +#endif /* __HOT_TRACKING__ */
fs/namei.c +2 -0
@@ -3394,6 +3394,8 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)if (!dir->i_op->unlink)return -EPERM ; +hot_inode_item_delete (dentry->d_inode); +mutex_lock (&dentry->d_inode->i_mutex);if (d_mountpoint (dentry)) error = -EBUSY ;
include/linux/hot_tracking.h +17 -0
@@ -67,6 +67,8 @@ struct hot_inode_item {struct hot_comm_item hot_inode;/* node in hot_inode_tree */ struct rb_root hot_range_tree;/* tree of ranges */ spinlock_t i_lock;/* protect above tree */ +struct hot_info *hot_root;/* associated hot_info */ +u64 i_ino;/* inode number from inode */ };/*
@@ -76,6 +78,9 @@ struct hot_inode_item {struct hot_range_item {struct hot_comm_item hot_range;struct hot_inode_item *hot_inode;/* associated hot_inode_item */ +loff_t start;/* offset in bytes */ +size_t len;/* length in bytes */ +int storage_type;/* type of storage */ };struct hot_info {
@@ -89,6 +94,13 @@ extern void __init hot_cache_init(void);extern int hot_track_init (struct super_block *sb);extern void hot_track_exit (struct super_block *sb);extern void hot_comm_item_put (struct hot_comm_item *ci); +extern void hot_update_freqs (struct inode *inode,loff_t start, +size_t len,int rw); +extern struct hot_inode_item *hot_inode_item_lookup (struct hot_info *root, +u64 ino,int alloc); +extern struct hot_range_item *hot_range_item_lookup (struct hot_inode_item *he, +loff_t start,int alloc); +extern void hot_inode_item_delete (struct inode *inode);static inline u64 hot_shift (u64 counter,u32 bits,bool dir) {
@@ -98,6 +110,11 @@ static inline u64 hot_shift(u64 counter, u32 bits, bool dir)return counter >> bits; } +static inline void hot_comm_item_get (struct hot_comm_item *ci) +{ +kref_get (&ci->refs); +} +#endif /* __KERNEL__ */ #endif /* _LINUX_HOTTRACK_H */
mm/filemap.c +6 -0
@@ -33,6 +33,7 @@#include <linux/hardirq.h> /* for BUG_ON(!in_atomic()) only */ #include <linux/memcontrol.h> #include <linux/cleancache.h> +#include <linux/hot_tracking.h> #include "internal.h" #define CREATE_TRACE_POINTS
@@ -1242,6 +1243,11 @@ readpage:* PG_error will be set again if readpage fails. */ ClearPageError (page); + +/* Hot data tracking */ +hot_update_freqs (inode, (loff_t )page->index <<PAGE_CACHE_SHIFT , +PAGE_CACHE_SIZE ,0 ); +/* Start the actual read. The read will unlock the page. */ error = mapping->a_ops->readpage (filp, page);
mm/page-writeback.c +12 -0
@@ -36,6 +36,7 @@#include <linux/pagevec.h> #include <linux/timer.h> #include <linux/sched/rt.h> +#include <linux/hot_tracking.h> #include <trace/events/writeback.h> /*
@@ -1921,13 +1922,24 @@ EXPORT_SYMBOL(generic_writepages);int do_writepages (struct address_space *mapping,struct writeback_control *wbc) {int ret; +loff_t start =0 ; +size_t count =0 ;if (wbc->nr_to_write <=0 )return 0 ; + + start = mapping->writeback_index <<PAGE_CACHE_SHIFT ; + count = wbc->nr_to_write; +if (mapping->a_ops->writepages) ret = mapping->a_ops->writepages (mapping, wbc);else ret =generic_writepages (mapping, wbc); + +/* Hot data tracking */ +hot_update_freqs (mapping->host, start, + (count - wbc->nr_to_write) *PAGE_CACHE_SIZE ,1 ); +return ret; }
mm/readahead.c +6 -0
@@ -19,6 +19,7 @@#include <linux/pagemap.h> #include <linux/syscalls.h> #include <linux/file.h> +#include <linux/hot_tracking.h> /* * Initialise a struct file's readahead state. Assumes that the caller has
@@ -115,6 +116,11 @@ static int read_pages(struct address_space *mapping, struct file *filp,unsigned page_idx;int ret; +/* Hot data tracking */ +hot_update_freqs (mapping->host, +list_to_page (pages)->index <<PAGE_CACHE_SHIFT , + (size_t )nr_pages *PAGE_CACHE_SIZE ,0 ); +blk_start_plug (&plug);if (mapping->a_ops->readpages) {
Signature · 1 line
1.7.11.7
PATCH v2 3/12 VFS hot tracking: add one workqueue to update hot map
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
Add a workqueue per superblock and a delayed_work
to run periodic work to update map info on each superblock.
Two arrays of map list are defined, one is for hot inode
items, and the other is for hot extent items.
The hot items in the RB-tree will be at first distilled
into one temperature in the range [0, 255]. If it is old, it will be not linked or aged out, otherwise then it will be linked to its corresponding array of map list which use the temperature as its index.
--- fs/hot_tracking.c | 298 ++++++++++++++++++++++++++++++++++++++++++- fs/hot_tracking.h | 25 ++++ include/linux/hot_tracking.h | 4 + 3 files changed, 326 insertions(+), 1 deletion(-)
fs/hot_tracking.c +297 -1
@@ -29,7 +29,9 @@ static void hot_inode_item_free(struct kref *kref);static void hot_comm_item_init (struct hot_comm_item *ci,int type) {kref_init (&ci->refs); +clear_bit (HOT_IN_LIST , &ci->delete_flag);clear_bit (HOT_DELETING , &ci->delete_flag); +INIT_LIST_HEAD (&ci->track_list);memset (&ci->hot_freq_data,0 ,sizeof (struct hot_freq_data )); ci->hot_freq_data.avg_delta_reads = (u64) -1 ; ci->hot_freq_data.avg_delta_writes = (u64) -1 ;
@@ -86,12 +88,21 @@ void hot_comm_item_put(struct hot_comm_item *ci)EXPORT_SYMBOL_GPL (hot_comm_item_put);/* -* root->t_lock or he->i_lock is acquired in this function +* root->t_lock or he->i_lock, and root->m_lock +* are acquired in this function */ static void hot_comm_item_unlink (struct hot_info *root,struct hot_comm_item *ci) {if (!test_and_set_bit (HOT_DELETING , &ci->delete_flag)) { +if (test_and_clear_bit (HOT_IN_LIST , &ci->delete_flag)) { +spin_lock (&root->m_lock); +list_del_rcu (&ci->track_list); +spin_unlock (&root->m_lock); + +hot_comm_item_put (ci); + } +if (ci->hot_freq_data.flags ==TYPE_RANGE ) {struct hot_range_item *hr =container_of (ci, struct hot_range_item, hot_range);
@@ -343,6 +354,274 @@ static void hot_freq_update(struct hot_info *root, }/* +* hot_temp_calc() is responsible for distilling the six heat +* criteria down into a single temperature value for the data, +* which is an integer between 0 and HEAT_MAX_VALUE. +* +* With the six values, we first do some very rudimentary +* "normalizations" to each metric such that they affect the +* final temperature calculation exactly the right way. It's +* important to note that we still weren't really sure that +* these six adjustments were exactly right. +* They could definitely use more tweaking and adjustment, +* especially in terms of the memory footprint they consume. +* +* Next, we take the adjusted values and shift them down to +* a manageable size, whereafter they are weighted using the +* the *_COEFF_POWER values and combined to a single temperature +* value. +*/ +static u32 hot_temp_calc (struct hot_comm_item *ci) +{ +u32 result =0 ; +struct hot_freq_data *freq_data = &ci->hot_freq_data; + +struct timespec ckt =current_kernel_time (); +u64 cur_time =timespec_to_ns (&ckt); +u32 nrr_heat, nrw_heat; +u64 ltr_heat, ltw_heat, avr_heat, avw_heat; + + nrr_heat = (u32 )hot_shift ((u64 )freq_data->nr_reads, +NRR_MULTIPLIER_POWER , true); + nrw_heat = (u32 )hot_shift ((u64 )freq_data->nr_writes, +NRW_MULTIPLIER_POWER , true); + + ltr_heat = +hot_shift ((cur_time -timespec_to_ns (&freq_data->last_read_time)), +LTR_DIVIDER_POWER , false); + ltw_heat = +hot_shift ((cur_time -timespec_to_ns (&freq_data->last_write_time)), +LTW_DIVIDER_POWER , false); + + avr_heat = +hot_shift ((((u64) -1 ) - freq_data->avg_delta_reads), +AVR_DIVIDER_POWER , false); + avw_heat = +hot_shift ((((u64) -1 ) - freq_data->avg_delta_writes), +AVW_DIVIDER_POWER , false); + +/* ltr_heat is now guaranteed to be u32 safe */ +if (ltr_heat >=hot_shift ((u64 )1 ,32 , true)) + ltr_heat =0 ; +else + ltr_heat =hot_shift ((u64 )1 ,32 , true) - ltr_heat; + +/* ltw_heat is now guaranteed to be u32 safe */ +if (ltw_heat >=hot_shift ((u64 )1 ,32 , true)) + ltw_heat =0 ; +else + ltw_heat =hot_shift ((u64 )1 ,32 , true) - ltw_heat; + +/* avr_heat is now guaranteed to be u32 safe */ +if (avr_heat >=hot_shift ((u64 )1 ,32 , true)) + avr_heat = (u32) -1 ; + +/* avw_heat is now guaranteed to be u32 safe */ +if (avw_heat >=hot_shift ((u64 )1 ,32 , true)) + avw_heat = (u32) -1 ; + + nrr_heat = (u32 )hot_shift ((u64 )nrr_heat, + (3 -NRR_COEFF_POWER ), false); + nrw_heat = (u32 )hot_shift ((u64 )nrw_heat, + (3 -NRW_COEFF_POWER ), false); + ltr_heat =hot_shift (ltr_heat, (3 -LTR_COEFF_POWER ), false); + ltw_heat =hot_shift (ltw_heat, (3 -LTW_COEFF_POWER ), false); + avr_heat =hot_shift (avr_heat, (3 -AVR_COEFF_POWER ), false); + avw_heat =hot_shift (avw_heat, (3 -AVW_COEFF_POWER ), false); + + result = nrr_heat + nrw_heat + (u32 ) ltr_heat + + (u32 ) ltw_heat + (u32 ) avr_heat + (u32 ) avw_heat; + +return result; +} + +static bool hot_is_obsolete (struct hot_comm_item *ci) +{ +int ret =0 ; +struct timespec ckt =current_kernel_time (); +struct hot_freq_data *freq_data = &ci->hot_freq_data; +u64 last_read_ns, last_write_ns; +u64 cur_time =timespec_to_ns (&ckt); +u64 kick_ns =HOT_AGE_INTERVAL *NSEC_PER_SEC ; + + last_read_ns = + (cur_time -timespec_to_ns (&freq_data->last_read_time)); + last_write_ns = + (cur_time -timespec_to_ns (&freq_data->last_write_time)); + +if ((last_read_ns > kick_ns) && (last_write_ns > kick_ns)) + ret =1 ; + +return ret; +} + +static void hot_comm_item_link_cb (struct rcu_head *head) +{ +struct hot_comm_item *ci =container_of (head, + struct hot_comm_item, c_rcu); +struct hot_info *root; +u32 cur_temp = ci->hot_freq_data.last_temp; + +if (ci->hot_freq_data.flags ==TYPE_RANGE ) { +struct hot_range_item *hr =container_of (ci, + struct hot_range_item, hot_range); + root = hr->hot_inode->hot_root; + }else { +struct hot_inode_item *he =container_of (ci, + struct hot_inode_item, hot_inode); + root = he->hot_root; + + } + +spin_lock (&root->m_lock); +if (test_bit (HOT_DELETING , &ci->delete_flag)) { +spin_unlock (&root->m_lock); +return ; + } +list_add_tail_rcu (&ci->track_list, + &root->hot_map[ci->hot_freq_data.flags][cur_temp]); +spin_unlock (&root->m_lock); +} + +/* +* Calculate a new temperature and, if necessary, +* move the list_head corresponding to this inode or range +* to the proper list with the new temperature. +*/ +static int hot_map_update (struct hot_info *root, +struct hot_comm_item *ci) +{ +u32 temp =hot_temp_calc (ci); +u8 cur_temp, prev_temp; +int flag = false; + + cur_temp = (u8 )hot_shift ((u64 )temp, + (32 -MAP_BITS ), false); + prev_temp = (u8 )hot_shift ((u64 )ci->hot_freq_data.last_temp, + (32 -MAP_BITS ), false); + +if (cur_temp != prev_temp) { +if (test_and_set_bit (HOT_IN_LIST , &ci->delete_flag)) { +spin_lock (&root->m_lock); +list_del_rcu (&ci->track_list); +spin_unlock (&root->m_lock); + flag = true; + } + + ci->hot_freq_data.last_temp = temp; + +if (flag) +call_rcu (&ci->c_rcu, hot_comm_item_link_cb); +if (test_bit (HOT_DELETING , &ci->delete_flag)) +return 1 ; +else { +u32 flags = ci->hot_freq_data.flags; + +hot_comm_item_get (ci); + +spin_lock (&root->m_lock); +if (test_bit (HOT_DELETING , &ci->delete_flag)) { +spin_unlock (&root->m_lock); +return 1 ; + } +list_add_tail_rcu (&ci->track_list, + &root->hot_map[flags][cur_temp]); +spin_unlock (&root->m_lock); + } + } + +return 0 ; +} + +/* +* Update temperatures for each range item for aging purposes. +* If one hot range item is old, it will be aged out. +*/ +static void hot_range_update (struct hot_inode_item *he, +struct hot_info *root) +{ +struct rb_node *node; +struct hot_comm_item *ci; +bool obsolete; + +rcu_read_lock (); + node =rb_first (&he->hot_range_tree); +while (node) { + ci = rb_entry(node, struct hot_comm_item, rb_node); + node =rb_next (node); +if (test_bit (HOT_DELETING , &ci->delete_flag) || +hot_map_update (root, ci)) { +continue ; + } + obsolete =hot_is_obsolete (ci); +if (obsolete) +hot_comm_item_unlink (root, ci); + } +rcu_read_unlock (); +} + +/* Temperature compare function*/ +static int hot_temp_cmp (void *priv,struct list_head *a, +struct list_head *b) +{ +struct hot_comm_item *ap =container_of (a, + struct hot_comm_item, track_list); +struct hot_comm_item *bp =container_of (b, + struct hot_comm_item, track_list); + +int diff = ap->hot_freq_data.last_temp + - bp->hot_freq_data.last_temp; +if (diff >0 ) +return -1 ; +if (diff <0 ) +return 1 ; +return 0 ; +} + +/* +* Every sync period we update temperatures for +* each hot inode item and hot range item for aging +* purposes. +*/ +static void hot_update_worker (struct work_struct *work) +{ +struct hot_info *root =container_of (to_delayed_work (work), + struct hot_info, update_work); +struct rb_node *node; +struct hot_comm_item *ci; +struct hot_inode_item *he; +int i, j; + +rcu_read_lock (); + node =rb_first (&root->hot_inode_tree); +while (node) { + ci = rb_entry(node, struct hot_comm_item, rb_node); + node =rb_next (node); +if (test_bit (HOT_DELETING , &ci->delete_flag) || +hot_map_update (root, ci)) { +continue ; + } + he =container_of (ci, + struct hot_inode_item, hot_inode); +hot_range_update (he, root); + } +rcu_read_unlock (); + +/* Sort temperature map info based on last temperature*/ +for (i =0 ; i <MAP_SIZE ; i++) { +for (j =0 ; j <MAX_TYPES ; j++) { +spin_lock (&root->m_lock); +list_sort (NULL , &root->hot_map[j][i], hot_temp_cmp); +spin_unlock (&root->m_lock); + } + } + +/* Instert next delayed work */ +queue_delayed_work (root->update_wq, &root->update_work, +msecs_to_jiffies (HOT_UPDATE_INTERVAL *MSEC_PER_SEC )); +} + +/* * Initialize kmem cache for hot_inode_item and hot_range_item. */ void __init hot_cache_init (void )
@@ -433,6 +712,20 @@ static struct hot_info *hot_tree_init(struct super_block *sb)INIT_LIST_HEAD (&root->hot_map[j][i]); } + root->update_wq =alloc_workqueue ( +"hot_update_wq" ,WQ_NON_REENTRANT ,0 ); +if (!root->update_wq) { +printk (KERN_ERR "%s: Failed to create " +"hot update workqueue\n" , __func__); +kfree (root); +return ERR_PTR (-ENOMEM ); + } + +/* Initialize hot tracking wq and arm one delayed work */ +INIT_DELAYED_WORK (&root->update_work, hot_update_worker); +queue_delayed_work (root->update_wq, &root->update_work, +msecs_to_jiffies (HOT_UPDATE_INTERVAL *MSEC_PER_SEC )); +return root; }
@@ -444,6 +737,9 @@ static void hot_tree_exit(struct hot_info *root)struct rb_node *node;struct hot_comm_item *ci; +cancel_delayed_work_sync (&root->update_work); +destroy_workqueue (root->update_wq); +rcu_read_lock (); node =rb_first (&root->hot_inode_tree);while (node) {
fs/hot_tracking.h +25 -0
@@ -12,10 +12,35 @@#ifndef __HOT_TRACKING__#define __HOT_TRACKING__ +#include <linux/workqueue.h> #include <linux/hot_tracking.h> +#define HOT_UPDATE_INTERVAL 150 +#define HOT_AGE_INTERVAL 300 +/* size of sub-file ranges */ #define RANGE_BITS 20#define FREQ_POWER 4 +/* NRR/NRW heat unit = 2^X accesses */ +#define NRR_MULTIPLIER_POWER 20/* NRR - number of reads since mount */ +#define NRR_COEFF_POWER 0 +#define NRW_MULTIPLIER_POWER 20/* NRW - number of writes since mount */ +#define NRW_COEFF_POWER 0 + +/* LTR/LTW heat unit = 2^X ns of age */ +#define LTR_DIVIDER_POWER 30/* LTR - time elapsed since last read(ns) */ +#define LTR_COEFF_POWER 1 +#define LTW_DIVIDER_POWER 30/* LTW - time elapsed since last write(ns) */ +#define LTW_COEFF_POWER 1 + +/* +* AVR/AVW cold unit = 2^X ns of average delta +* AVR/AVW heat unit = HEAT_MAX_VALUE - cold unit +*/ +#define AVR_DIVIDER_POWER 40/* AVR - average delta between recent reads(ns) */ +#define AVR_COEFF_POWER 0 +#define AVW_DIVIDER_POWER 40/* AVW - average delta between recent writes(ns) */ +#define AVW_COEFF_POWER 0 +#endif /* __HOT_TRACKING__ */
include/linux/hot_tracking.h +4 -0
@@ -35,6 +35,7 @@ enum {enum {HOT_DELETING , +HOT_IN_LIST , };/*
@@ -60,6 +61,7 @@ struct hot_comm_item {struct rb_node rb_node;/* rbtree index */ unsigned long delete_flag;struct rcu_head c_rcu; +struct list_head track_list;/* link to *_map[] */ };/* An item representing an inode and its access frequency */
@@ -88,6 +90,8 @@ struct hot_info {spinlock_t t_lock;/* protect above tree */ struct list_head hot_map[MAX_TYPES ][MAP_SIZE ];/* map of inode temp */ spinlock_t m_lock; +struct workqueue_struct *update_wq; +struct delayed_work update_work; };extern void __init hot_cache_init (void );
Signature · 1 line
1.7.11.7
PATCH v2 4/12 VFS hot tracking: register one shrinker
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
Register a shrinker to control the amount of memory that
is used in tracking hot regions. If we are throwing inodes out of memory due to memory pressure, we most definitely are going to need to reduce the amount of memory the tracking code is using, even if it means losing useful information That is, the shrinker accelerates the aging process.
--- fs/hot_tracking.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/hot_tracking.h | 2 ++ 2 files changed, 60 insertions(+)
fs/hot_tracking.c +58 -0
@@ -100,6 +100,7 @@ static void hot_comm_item_unlink(struct hot_info *root,list_del_rcu (&ci->track_list);spin_unlock (&root->m_lock); +atomic_dec (&root->hot_map_nr);hot_comm_item_put (ci); }
@@ -517,6 +518,7 @@ static int hot_map_update(struct hot_info *root,else {u32 flags = ci->hot_freq_data.flags; +atomic_inc (&root->hot_map_nr);hot_comm_item_get (ci);spin_lock (&root->m_lock);
@@ -642,6 +644,55 @@ void __init hot_cache_init(void) }EXPORT_SYMBOL_GPL (hot_cache_init); +static void hot_prune_map (struct hot_info *root,long nr) +{ +int i; + +for (i =0 ; i <MAP_SIZE ; i++) { +struct hot_comm_item *ci; +unsigned long prev_nr; + +rcu_read_lock (); +if (list_empty (&root->hot_map[TYPE_INODE ][i])) { +rcu_read_unlock (); +continue ; + } + +list_for_each_entry_rcu (ci, &root->hot_map[TYPE_INODE ][i], + track_list) { + prev_nr =atomic_read (&root->hot_map_nr); +hot_comm_item_unlink (root, ci); + nr -= (prev_nr -atomic_read (&root->hot_map_nr)); +if (nr <=0 ) +break ; + } +rcu_read_unlock (); + +if (nr <=0 ) +break ; + } + +return ; +} + +/* The shrinker callback function */ +static int hot_track_prune (struct shrinker *shrink, +struct shrink_control *sc) +{ +struct hot_info *root = + container_of(shrink, struct hot_info, hot_shrink); + +if (sc->nr_to_scan ==0 ) +return atomic_read (&root->hot_map_nr) /2 ; + +if (!(sc->gfp_mask & __GFP_FS)) +return -1 ; + +hot_prune_map (root, sc->nr_to_scan); + +return atomic_read (&root->hot_map_nr); +} +/* * Main function to update i/o access frequencies, and it will be called * from read/writepages() hooks, which are read_pages(), do_writepages(),
@@ -706,6 +757,7 @@ static struct hot_info *hot_tree_init(struct super_block *sb) root->hot_inode_tree =RB_ROOT ;spin_lock_init (&root->t_lock);spin_lock_init (&root->m_lock); +atomic_set (&root->hot_map_nr,0 );for (i =0 ; i <MAP_SIZE ; i++) {for (j =0 ; j <MAX_TYPES ; j++)
@@ -726,6 +778,11 @@ static struct hot_info *hot_tree_init(struct super_block *sb)queue_delayed_work (root->update_wq, &root->update_work,msecs_to_jiffies (HOT_UPDATE_INTERVAL *MSEC_PER_SEC )); +/* Register a shrinker callback */ + root->hot_shrink.shrink = hot_track_prune; + root->hot_shrink.seeks =DEFAULT_SEEKS ; +register_shrinker (&root->hot_shrink); +return root; }
@@ -737,6 +794,7 @@ static void hot_tree_exit(struct hot_info *root)struct rb_node *node;struct hot_comm_item *ci; +unregister_shrinker (&root->hot_shrink);cancel_delayed_work_sync (&root->update_work);destroy_workqueue (root->update_wq);
include/linux/hot_tracking.h +2 -0
@@ -90,8 +90,10 @@ struct hot_info {spinlock_t t_lock;/* protect above tree */ struct list_head hot_map[MAX_TYPES ][MAP_SIZE ];/* map of inode temp */ spinlock_t m_lock; +atomic_t hot_map_nr;struct workqueue_struct *update_wq;struct delayed_work update_work; +struct shrinker hot_shrink; };extern void __init hot_cache_init (void );
Signature · 1 line
1.7.11.7
PATCH v2 5/12 VFS hot tracking, rcu: introduce one rcu macro for list
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
This rcu macro for list will be used in seq_list
rcu interfaces.
--- include/linux/rculist.h | 5 +++++ 1 file changed, 5 insertions(+)
include/linux/rculist.h +5 -0
@@ -218,6 +218,11 @@ static inline void list_splice_init_rcu(struct list_head *list, at->prev = last; } +#define __list_for_each_rcu (pos, head) \ + for (pos = rcu_dereference(list_next_rcu(head)); \ + pos != head; \ + pos = rcu_dereference(list_next_rcu(pos))) +/** * list_entry_rcu - get the struct for this entry * @ptr: the &struct list_head pointer.
Signature · 1 line
1.7.11.7
PATCH v2 6/12 VFS hot tracking, seq_file: introduce one set of rcu seq_list interfaces
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
The patch will introduce one set of rcu interface for seq_list.
--- fs/seq_file.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/seq_file.h | 7 +++++++ 2 files changed, 44 insertions(+)
fs/seq_file.c +37 -0
@@ -795,6 +795,43 @@ struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos) }EXPORT_SYMBOL (seq_list_next); +struct list_head *seq_list_start_rcu (struct list_head *head,loff_t pos) +{ +struct list_head *lh; + +__list_for_each_rcu (lh, head) +if (pos-- ==0 ) +return lh; + +return NULL ; +} +EXPORT_SYMBOL (seq_list_start_rcu); + +struct list_head *seq_list_start_head_rcu (struct list_head *head,loff_t pos) +{ +if (!pos) +return head; + +return seq_list_start_rcu (head, pos -1 ); +} +EXPORT_SYMBOL (seq_list_start_head_rcu); + +struct list_head *seq_list_next_rcu (void *v,struct list_head *head, +loff_t *ppos) +{ +struct list_head *lh; + + ++*ppos; +rcu_read_lock (); + lh =rcu_dereference (((struct list_head *)v)->next); +if (lh == head) + lh =NULL ; +rcu_read_unlock (); + +return lh; +} +EXPORT_SYMBOL (seq_list_next_rcu); +/** * seq_hlist_start - start an iteration of a hlist * @head: the head of the hlist
include/linux/seq_file.h +7 -0
@@ -155,6 +155,13 @@ extern struct list_head *seq_list_start_head(struct list_head *head,extern struct list_head *seq_list_next (void *v,struct list_head *head,loff_t *ppos); +extern struct list_head *seq_list_start_rcu (struct list_head *head, +loff_t pos); +extern struct list_head *seq_list_start_head_rcu (struct list_head *head, +loff_t pos); +extern struct list_head *seq_list_next_rcu (void *v,struct list_head *head, +loff_t *ppos); +/* * Helpers for iteration over hlist_head-s in seq_files */
Signature · 1 line
1.7.11.7
PATCH v2 7/12 VFS hot tracking: add debugfs support
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
Add a directory '<dev_name>' in /sys/kernel/debug/hot_track/
for each volume that contains four files which are 'inode_stat', 'extent_stat', 'inode_spot', and 'extent_spot'.
--- fs/hot_tracking.c | 455 +++++++++++++++++++++++++++++++++++++++++++ fs/hot_tracking.h | 5 + include/linux/hot_tracking.h | 1 + 3 files changed, 461 insertions(+)
fs/hot_tracking.c +455 -0
@@ -17,9 +17,12 @@#include <linux/fs.h> #include <linux/types.h> #include <linux/list_sort.h> +#include <linux/debugfs.h> #include <linux/limits.h> #include "hot_tracking.h" +static struct dentry *hot_debugfs_root; +/* kmem_cache pointers for slab caches */ static struct kmem_cache *hot_inode_item_cachep__read_mostly ;static struct kmem_cache *hot_range_item_cachep__read_mostly ;
@@ -623,6 +626,444 @@ static void hot_update_worker(struct work_struct *work) msecs_to_jiffies(HOT_UPDATE_INTERVAL * MSEC_PER_SEC)); } +static void *hot_range_seq_start (struct seq_file *seq,loff_t *pos) +__acquires (rcu) +{ +struct hot_info *root = seq->private; +struct rb_node *node_he, *node_hr; +struct hot_comm_item *ci_he, *ci_hr; +struct hot_inode_item *he; +struct hot_range_item *hr; +loff_t l = *pos; + +rcu_read_lock (); + node_he =rb_first (&root->hot_inode_tree); +while (node_he) { + ci_he = rb_entry(node_he, struct hot_comm_item, rb_node); + he = container_of(ci_he, struct hot_inode_item, hot_inode); + node_hr =rb_first (&he->hot_range_tree); +while (node_hr) { +if (!l--) { + ci_hr =rb_entry (node_hr, + struct hot_comm_item, rb_node); + hr =container_of (ci_hr, + struct hot_range_item, hot_range); +return hr; + } + node_hr =rb_next (node_hr); + } + node_he =rb_next (node_he); + } + +return NULL ; +} + +static void *hot_range_seq_next (struct seq_file *seq, +void *v,loff_t *pos) +{ +struct rb_node *node_he, *node_hr; +struct hot_comm_item *ci_he, *ci_hr; +struct hot_range_item *hr_next =NULL , *hr = v; +struct hot_inode_item *he_next; + + (*pos)++; + node_hr =rb_next (&hr->hot_range.rb_node); +if (node_hr) { + ci_hr = rb_entry(node_hr, struct hot_comm_item, rb_node); + hr_next = container_of(ci_hr, struct hot_range_item, hot_range); + +return hr_next; + } + + node_he =rb_next (&hr->hot_inode->hot_inode.rb_node); +loop_he: +if (node_he) { + ci_he = rb_entry(node_he, struct hot_comm_item, rb_node); + he_next = container_of(ci_he, struct hot_inode_item, hot_inode); + node_hr =rb_first (&he_next->hot_range_tree); +if (node_hr) { + ci_hr =rb_entry (node_hr, + struct hot_comm_item, rb_node); + hr_next =container_of (ci_hr, + struct hot_range_item, hot_range); + }else { + node_he =rb_next (node_he); + goto loop_he; + } + } + +return hr_next; +} + +static void hot_range_seq_stop (struct seq_file *seq,void *v) +__releases (rcu) +{ +rcu_read_unlock (); +} + +static int hot_range_seq_show (struct seq_file *seq,void *v) +{ +struct hot_range_item *hr = v; +struct hot_inode_item *he = hr->hot_inode; +struct hot_freq_data *freq_data; + + freq_data = &hr->hot_range.hot_freq_data; +seq_printf (seq,"inode %llu, extent %llu+%llu, " \ +"reads %u, writes %u, temp %u, " \ +"storage type %s\n" , + he->i_ino, (unsigned long long )hr->start, + (unsigned long long )hr->len, + freq_data->nr_reads, + freq_data->nr_writes, + (u8 )hot_shift ((u64 )freq_data->last_temp, + (32 -MAP_BITS ), false), + (hr->storage_type ==1 ) ?"nonrot" :"rot" ); + +return 0 ; +} + +static void *hot_inode_seq_start (struct seq_file *seq,loff_t *pos) +__acquires (rcu) +{ +struct hot_info *root = seq->private; +struct rb_node *node; +struct hot_comm_item *ci; +struct hot_inode_item *he =NULL ; +loff_t l = *pos; + +rcu_read_lock (); + node =rb_first (&root->hot_inode_tree); +while (node) { +if (!l--) { + ci = rb_entry(node, struct hot_comm_item, rb_node); + he = container_of(ci, struct hot_inode_item, hot_inode); +break ; + } + node =rb_next (node); + } + +return he; +} + +static void *hot_inode_seq_next (struct seq_file *seq,void *v,loff_t *pos) +{ +struct hot_inode_item *he_next =NULL , *he = v; +struct rb_node *node; +struct hot_comm_item *ci; + + (*pos)++; + node =rb_next (&he->hot_inode.rb_node); +if (node) { + ci = rb_entry(node, struct hot_comm_item, rb_node); + he_next = container_of(ci, struct hot_inode_item, hot_inode); + } + +return he_next; +} + +static void hot_inode_seq_stop (struct seq_file *seq,void *v) +__releases (rcu) +{ +rcu_read_unlock (); +} + +static int hot_inode_seq_show (struct seq_file *seq,void *v) +{ +struct hot_inode_item *he = v; +struct hot_freq_data *freq_data = &he->hot_inode.hot_freq_data; + +seq_printf (seq,"inode %llu, reads %u, writes %u, temp %d\n" , + he->i_ino, + freq_data->nr_reads, + freq_data->nr_writes, + (u8 )hot_shift ((u64 )freq_data->last_temp, + (32 -MAP_BITS ), false)); + +return 0 ; +} + +static struct hot_comm_item *hot_spot_seq_start (struct hot_info *root, +loff_t *pos,int type) +__acquires (rcu) +{ +struct hot_comm_item *ci; +struct list_head *track_list; +int i; + +rcu_read_lock (); +for (i =MAP_SIZE -1 ; i >=0 ; i--) { + track_list =seq_list_start_rcu (&root->hot_map[type][i], *pos); +if (track_list) { + ci =container_of (track_list, + struct hot_comm_item, track_list); +return ci; + } + } + +return NULL ; +} + +static struct hot_comm_item *hot_spot_seq_next (struct hot_info *root, +struct hot_comm_item *ci, +loff_t *pos,int type) +{ +struct hot_comm_item *ci_next =NULL ; +struct list_head *track_list; +int i; + + i = (int )hot_shift (ci->hot_freq_data.last_temp, + (32 -MAP_BITS ), false); + + track_list =seq_list_next_rcu (&ci->track_list, + &root->hot_map[type][i], pos); +next: +if (track_list) + ci_next =container_of (track_list, + struct hot_comm_item, track_list); +else if (--i >=0 ) { + track_list =seq_list_next_rcu (&root->hot_map[type][i], + &root->hot_map[type][i], pos); + goto next; + } + +return ci_next; +} + +static void *hot_spot_range_seq_start (struct seq_file *seq,loff_t *pos) +{ +struct hot_info *root = seq->private; +struct hot_range_item *hr =NULL ; +struct hot_comm_item *ci; + + ci =hot_spot_seq_start (root, pos,TYPE_RANGE ); +if (ci) + hr = container_of(ci, struct hot_range_item, hot_range); + +return hr; +} + +static void *hot_spot_range_seq_next (struct seq_file *seq,void *v,loff_t *pos) +{ +struct hot_info *root = seq->private; +struct hot_range_item *hr_next =NULL , *hr = v; +struct hot_comm_item *ci_next; + + ci_next =hot_spot_seq_next (root, &hr->hot_range, pos,TYPE_RANGE ); +if (ci_next) + hr_next =container_of (ci_next, + struct hot_range_item, hot_range); + +return hr_next; +} + +static void *hot_spot_inode_seq_start (struct seq_file *seq,loff_t *pos) +{ +struct hot_info *root = seq->private; +struct hot_inode_item *he =NULL ; +struct hot_comm_item *ci; + + ci =hot_spot_seq_start (root, pos,TYPE_INODE ); +if (ci) + he = container_of(ci, struct hot_inode_item, hot_inode); + +return he; +} + +static void *hot_spot_inode_seq_next (struct seq_file *seq,void *v,loff_t *pos) +{ +struct hot_info *root = seq->private; +struct hot_inode_item *he_next =NULL , *he = v; +struct hot_comm_item *ci_next; + + ci_next =hot_spot_seq_next (root, &he->hot_inode, pos,TYPE_INODE ); +if (ci_next) + he_next =container_of (ci_next, + struct hot_inode_item, hot_inode); + +return he_next; +} + +static const struct seq_operations hot_range_seq_ops = { + .start = hot_range_seq_start, + .next = hot_range_seq_next, + .stop = hot_range_seq_stop, + .show = hot_range_seq_show +}; + +static const struct seq_operations hot_inode_seq_ops = { + .start = hot_inode_seq_start, + .next = hot_inode_seq_next, + .stop = hot_inode_seq_stop, + .show = hot_inode_seq_show +}; + +static const struct seq_operations hot_spot_range_seq_ops = { + .start = hot_spot_range_seq_start, + .next = hot_spot_range_seq_next, + .stop = hot_range_seq_stop, + .show = hot_range_seq_show +}; + +static const struct seq_operations hot_spot_inode_seq_ops = { + .start = hot_spot_inode_seq_start, + .next = hot_spot_inode_seq_next, + .stop = hot_inode_seq_stop, + .show = hot_inode_seq_show +}; + +static int hot_range_seq_open (struct inode *inode,struct file *file) +{ +int ret =seq_open_private (file, &hot_range_seq_ops,0 ); +if (ret ==0 ) { +struct seq_file *seq = file->private_data; + seq->private = inode->i_private; + } +return ret; +} + +static int hot_inode_seq_open (struct inode *inode,struct file *file) +{ +int ret =seq_open_private (file, &hot_inode_seq_ops,0 ); +if (ret ==0 ) { +struct seq_file *seq = file->private_data; + seq->private = inode->i_private; + } +return ret; +} + +static int hot_spot_range_seq_open (struct inode *inode,struct file *file) +{ +int ret =seq_open_private (file, &hot_spot_range_seq_ops,0 ); +if (ret ==0 ) { +struct seq_file *seq = file->private_data; + seq->private = inode->i_private; + } +return ret; +} + +static int hot_spot_inode_seq_open (struct inode *inode,struct file *file) +{ +int ret =seq_open_private (file, &hot_spot_inode_seq_ops,0 ); +if (ret ==0 ) { +struct seq_file *seq = file->private_data; + seq->private = inode->i_private; + } +return ret; +} + +/* fops to override for printing range data */ +static const struct file_operations hot_debugfs_range_fops = { + .open = hot_range_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* fops to override for printing inode data */ +static const struct file_operations hot_debugfs_inode_fops = { + .open = hot_inode_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* fops to override for printing temperature data */ +static const struct file_operations hot_debugfs_spot_range_fops = { + .open = hot_spot_range_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static const struct file_operations hot_debugfs_spot_inode_fops = { + .open = hot_spot_inode_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static const struct hot_debugfs hot_debugfs[] = { + { + .name ="extent_stat" , + .fops = &hot_debugfs_range_fops, + }, + { + .name ="inode_stat" , + .fops = &hot_debugfs_inode_fops, + }, + { + .name ="extent_spot" , + .fops = &hot_debugfs_spot_range_fops, + }, + { + .name ="inode_spot" , + .fops = &hot_debugfs_spot_inode_fops, + }, +}; + +/* initialize debugfs */ +static int hot_debugfs_init (struct super_block *sb) +{ +static const char hot_name[] ="hot_track" ; +struct dentry *dentry; +int i, ret =0 ; + +/* Determine if hot debufs root has existed */ +if (!hot_debugfs_root) { + hot_debugfs_root =debugfs_create_dir (hot_name,NULL ); +if (IS_ERR (hot_debugfs_root)) { + ret =PTR_ERR (hot_debugfs_root); +return ret; + } + } + +/* create debugfs folder for this volume by mounted dev name */ + sb->s_hot_root->debugfs_dentry = +debugfs_create_dir (sb->s_id, hot_debugfs_root); +if (IS_ERR (sb->s_hot_root->debugfs_dentry)) { + ret =PTR_ERR (sb->s_hot_root->debugfs_dentry); + goto root_err; + } + +/* create debugfs hot data files */ +for (i =0 ; i <ARRAY_SIZE (hot_debugfs); i++) { + dentry =debugfs_create_file (hot_debugfs[i].name, +S_IFREG |S_IRUSR |S_IWUSR , + sb->s_hot_root->debugfs_dentry, + sb->s_hot_root, + hot_debugfs[i].fops); +if (IS_ERR (dentry)) { + ret =PTR_ERR (dentry); + goto err; + } + } + +return 0 ; + +err: +debugfs_remove_recursive (sb->s_hot_root->debugfs_dentry); + +root_err: +if (list_empty (&hot_debugfs_root->d_subdirs)) { +debugfs_remove (hot_debugfs_root); + hot_debugfs_root =NULL ; + } + +return ret; +} + +/* remove dentries for debugsfs */ +static void hot_debugfs_exit (struct super_block *sb) +{ +/* remove all debugfs entries recursively from the volume root */ +debugfs_remove_recursive (sb->s_hot_root->debugfs_dentry); + +if (list_empty (&hot_debugfs_root->d_subdirs)) { +debugfs_remove (hot_debugfs_root); + hot_debugfs_root =NULL ; + } +} +/* * Initialize kmem cache for hot_inode_item and hot_range_item. */
@@ -818,6 +1259,7 @@ static void hot_tree_exit(struct hot_info *root)int hot_track_init (struct super_block *sb) {struct hot_info *root; +int ret; root =hot_tree_init (sb);if (IS_ERR (root))
@@ -825,9 +1267,21 @@ int hot_track_init(struct super_block *sb) sb->s_hot_root = root; + ret =hot_debugfs_init (sb); +if (ret) { +printk (KERN_ERR "%s: hot_debugfs_init error: %d\n" , + __func__, ret); + goto out; + } +printk (KERN_INFO "VFS: Turning on hot data tracking\n" );return 0 ; + +out: +hot_tree_exit (root); + sb->s_hot_root =NULL ; +return ret; }EXPORT_SYMBOL_GPL (hot_track_init);
@@ -840,6 +1294,7 @@ void hot_track_exit(struct super_block *sb) {struct hot_info *root = sb->s_hot_root; +hot_debugfs_exit (sb);hot_tree_exit (root); sb->s_hot_root =NULL ;kfree (root);
fs/hot_tracking.h +5 -0
@@ -43,4 +43,9 @@#define AVW_DIVIDER_POWER 40/* AVW - average delta between recent writes(ns) */ #define AVW_COEFF_POWER 0 +struct hot_debugfs { +const char *name; +const struct file_operations *fops; +}; +#endif /* __HOT_TRACKING__ */
include/linux/hot_tracking.h +1 -0
@@ -94,6 +94,7 @@ struct hot_info {struct workqueue_struct *update_wq;struct delayed_work update_work;struct shrinker hot_shrink; +struct dentry *debugfs_dentry; };extern void __init hot_cache_init (void );
Signature · 1 line
1.7.11.7
PATCH v2 8/12 VFS hot tracking: add one ioctl interface
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
FS_IOC_GET_HEAT_INFO: return a struct containing the various
metrics collected in hot_freq_data structs, and also return a calculated data temperature based on those metrics. Optionally, retrieve the temperature from the hot data hash list instead of recalculating it.
--- fs/compat_ioctl.c | 5 ++++ fs/hot_tracking.c | 2 +- fs/ioctl.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/hot_tracking.h | 21 +++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-)
fs/compat_ioctl.c +5 -0
@@ -57,6 +57,7 @@#include <linux/i2c-dev.h> #include <linux/atalk.h> #include <linux/gfp.h> +#include <linux/hot_tracking.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci.h>
@@ -1402,6 +1403,9 @@ COMPATIBLE_IOCTL(TIOCSTART) COMPATIBLE_IOCTL(TIOCSTOP)#endif +/*Hot data tracking*/ +COMPATIBLE_IOCTL (FS_IOC_GET_HEAT_INFO ) +/* fat 'r' ioctls. These are handled by fat with ->compat_ioctl, but we don't want warnings on other file systems. So declare them as compatible here. */
@@ -1581,6 +1585,7 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,case FIBMAP :case FIGETBSZ :case FIONREAD : +case FS_IOC_GET_HEAT_INFO :if (S_ISREG (file_inode (f.file)->i_mode))break ;/*FALL THROUGH*/
fs/hot_tracking.c +1 -1
@@ -375,7 +375,7 @@ static void hot_freq_update(struct hot_info *root,* the *_COEFF_POWER values and combined to a single temperature * value. */ -static u32 hot_temp_calc (struct hot_comm_item *ci) +u32 hot_temp_calc (struct hot_comm_item *ci) {u32 result =0 ;struct hot_freq_data *freq_data = &ci->hot_freq_data;
fs/ioctl.c +70 -0
88 lines not on this page · raw message
include/linux/hot_tracking.h +21 -0
@@ -17,6 +17,18 @@#include <linux/types.h> +struct hot_heat_info { +__u64 avg_delta_reads; +__u64 avg_delta_writes; +__u64 last_read_time; +__u64 last_write_time; +__u32 num_reads; +__u32 num_writes; +__u32 temp; +__u8 live; +__u8 resv[3 ]; +}; +#ifdef __KERNEL__#include <linux/rbtree.h>
@@ -97,6 +109,14 @@ struct hot_info {struct dentry *debugfs_dentry; }; +/* +* Hot data tracking ioctls: +* +* HOT_INFO - retrieve info on frequency of access +*/ +#define FS_IOC_GET_HEAT_INFO _IOR('f', 17, \ + struct hot_heat_info) +extern void __init hot_cache_init (void );extern int hot_track_init (struct super_block *sb);extern void hot_track_exit (struct super_block *sb);
@@ -108,6 +128,7 @@ extern struct hot_inode_item *hot_inode_item_lookup(struct hot_info *root,extern struct hot_range_item *hot_range_item_lookup (struct hot_inode_item *he,loff_t start,int alloc);extern void hot_inode_item_delete (struct inode *inode); +extern u32 hot_temp_calc (struct hot_comm_item *ci);static inline u64 hot_shift (u64 counter,u32 bits,bool dir) {
Signature · 1 line
1.7.11.7
PATCH v2 9/12 VFS hot tracking, procfs: add two proc interfaces
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
Add two proc interfaces hot-age-interval and hot-update-interval
under the dir /proc/sys/fs/ in order to turn HOT_AGE_INTERVAL and HOT_UPDATE_INTERVAL into be tunable.
--- fs/hot_tracking.c | 12 +++++++++--- fs/hot_tracking.h | 3 --- include/linux/hot_tracking.h | 7 +++++++ kernel/sysctl.c | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 6 deletions(-)
fs/hot_tracking.c +9 -3
@@ -23,6 +23,12 @@static struct dentry *hot_debugfs_root; +int sysctl_hot_age_interval__read_mostly =300 ; +EXPORT_SYMBOL_GPL (sysctl_hot_age_interval); + +int sysctl_hot_update_interval__read_mostly =300 ; +EXPORT_SYMBOL_GPL (sysctl_hot_update_interval); +/* kmem_cache pointers for slab caches */ static struct kmem_cache *hot_inode_item_cachep__read_mostly ;static struct kmem_cache *hot_range_item_cachep__read_mostly ;
@@ -446,7 +452,7 @@ static bool hot_is_obsolete(struct hot_comm_item *ci)struct hot_freq_data *freq_data = &ci->hot_freq_data;u64 last_read_ns, last_write_ns;u64 cur_time =timespec_to_ns (&ckt); -u64 kick_ns =HOT_AGE_INTERVAL *NSEC_PER_SEC ; +u64 kick_ns = sysctl_hot_age_interval *NSEC_PER_SEC ; last_read_ns = (cur_time -timespec_to_ns (&freq_data->last_read_time));
@@ -623,7 +629,7 @@ static void hot_update_worker(struct work_struct *work)/* Instert next delayed work */ queue_delayed_work (root->update_wq, &root->update_work, -msecs_to_jiffies (HOT_UPDATE_INTERVAL *MSEC_PER_SEC )); +msecs_to_jiffies (sysctl_hot_update_interval *MSEC_PER_SEC )); }static void *hot_range_seq_start (struct seq_file *seq,loff_t *pos)
@@ -1217,7 +1223,7 @@ static struct hot_info *hot_tree_init(struct super_block *sb)/* Initialize hot tracking wq and arm one delayed work */ INIT_DELAYED_WORK (&root->update_work, hot_update_worker);queue_delayed_work (root->update_wq, &root->update_work, -msecs_to_jiffies (HOT_UPDATE_INTERVAL *MSEC_PER_SEC )); +msecs_to_jiffies (sysctl_hot_update_interval *MSEC_PER_SEC ));/* Register a shrinker callback */ root->hot_shrink.shrink = hot_track_prune;
fs/hot_tracking.h +0 -3
@@ -15,9 +15,6 @@#include <linux/workqueue.h> #include <linux/hot_tracking.h> -#define HOT_UPDATE_INTERVAL 150 -#define HOT_AGE_INTERVAL 300 -/* size of sub-file ranges */ #define RANGE_BITS 20#define FREQ_POWER 4
include/linux/hot_tracking.h +7 -0
@@ -110,6 +110,13 @@ struct hot_info { };/* +* Two variables have meanings as below: +* 1. time to quit keeping track of tracking data (seconds) +* 2. set how often to update temperatures (seconds) +*/ +extern int sysctl_hot_age_interval, sysctl_hot_update_interval; + +/* * Hot data tracking ioctls: * * HOT_INFO - retrieve info on frequency of access
kernel/sysctl.c +14 -0
@@ -1616,6 +1616,20 @@ static struct ctl_table fs_table[] = { .proc_handler = &pipe_proc_fn, .extra1 = &pipe_min_size, }, + { + .procname = "hot-age-interval", + .data = &sysctl_hot_age_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .procname = "hot-update-interval", + .data = &sysctl_hot_update_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { } };
Signature · 1 line
1.7.11.7
PATCH v2 10/12 VFS hot tracking, btrfs: add hot tracking support
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
Introduce one new mount option '-o hot_track',
and add its parsing support.
Its usage looks like:
mount -o hot_track
mount -o nouser,hot_track
mount -o nouser,hot_track,loop
mount -o hot_track,nouser
--- fs/btrfs/ctree.h | 1 + fs/btrfs/super.c | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-)
fs/btrfs/ctree.h +1 -0
@@ -1927,6 +1927,7 @@ struct btrfs_ioctl_defrag_range_args {#define BTRFS_MOUNT_CHECK_INTEGRITY (1 << 20)#define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)#define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR (1 << 22) +#define BTRFS_MOUNT_HOT_TRACK (1 << 23)#define btrfs_clear_opt (o, opt) ((o) &= ~BTRFS_MOUNT_##opt)#define btrfs_set_opt (o, opt) ((o) |= BTRFS_MOUNT_##opt)
fs/btrfs/super.c +21 -1
@@ -42,6 +42,7 @@#include <linux/cleancache.h> #include <linux/ratelimit.h> #include <linux/btrfs.h> +#include <linux/hot_tracking.h> #include "compat.h" #include "delayed-inode.h" #include "ctree.h"
@@ -306,6 +307,10 @@ static void btrfs_put_super(struct super_block *sb)* last process that kept it busy. Or segfault in the aforementioned * process... Whom would you report that to? */ + +/* Hot data tracking */ +if (btrfs_test_opt (btrfs_sb (sb)->tree_root,HOT_TRACK )) +hot_track_exit (sb); }enum {
@@ -318,7 +323,7 @@ enum { Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, Opt_inode_cache, Opt_no_space_cache, Opt_recovery, Opt_skip_balance, Opt_check_integrity, Opt_check_integrity_including_extent_data, - Opt_check_integrity_print_mask, Opt_fatal_errors, + Opt_check_integrity_print_mask, Opt_fatal_errors, Opt_hot_track, Opt_err, };
@@ -359,6 +364,7 @@ static match_table_t tokens = { {Opt_check_integrity_including_extent_data, "check_int_data"}, {Opt_check_integrity_print_mask, "check_int_print_mask=%d"}, {Opt_fatal_errors, "fatal_errors=%s"}, + {Opt_hot_track, "hot_track"}, {Opt_err, NULL}, };
@@ -624,6 +630,9 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) goto out; }break ; +case Opt_hot_track: +btrfs_set_opt (info->mount_opt,HOT_TRACK ); +break ;case Opt_err:printk (KERN_INFO "btrfs: unrecognized mount option " "'%s'\n" , p);
@@ -843,11 +852,20 @@ static int btrfs_fill_super(struct super_block *sb, goto fail_close; } +if (btrfs_test_opt (fs_info->tree_root,HOT_TRACK )) { + err =hot_track_init (sb); +if (err) + goto fail_hot; + } +save_mount_options (sb, data);cleancache_init_fs (sb); sb->s_flags |=MS_ACTIVE ;return 0 ; +fail_hot: +dput (sb->s_root); + sb->s_root =NULL ; fail_close:close_ctree (fs_info->tree_root);return err;
@@ -943,6 +961,8 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)seq_puts (seq,",skip_balance" );if (btrfs_test_opt (root,PANIC_ON_FATAL_ERROR ))seq_puts (seq,",fatal_errors=panic" ); +if (btrfs_test_opt (root,HOT_TRACK )) +seq_puts (seq,",hot_track" );return 0 ; }
Signature · 1 line
1.7.11.7
PATCH v2 11/12 VFS hot tracking: add documentation
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
Add Documentation for VFS hot tracking feature
--- Documentation/filesystems/00-INDEX | 2 + Documentation/filesystems/hot_tracking.txt | 256 +++++++++++++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 Documentation/filesystems/hot_tracking.txt
Documentation/filesystems/00-INDEX +2 -0
@@ -122,3 +122,5 @@ xfs.txt - info and mount options for the XFS filesystem. xip.txt - info on execute-in-place for file mappings. +hot_tracking.txt + - info on hot data tracking in VFS layer
Documentation/filesystems/hot_tracking.txt new file +256 -0
256 lines not on this page · raw message
Signature · 1 line
1.7.11.7
PATCH v2 12/12 VFS hot tracking: add fs hot type support
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
Introduce one ability to enable that specific FS
can register its own hot tracking functions.
--- fs/hot_tracking.c | 32 ++++++++++++++++++++++---------- fs/hot_tracking.h | 19 +++++++++++++++++++ fs/ioctl.c | 2 +- include/linux/fs.h | 1 + include/linux/hot_tracking.h | 22 +++++++++++++++++++++- 5 files changed, 64 insertions(+), 12 deletions(-)
fs/hot_tracking.c +22 -10
@@ -51,7 +51,7 @@ static void hot_range_item_init(struct hot_range_item *hr, struct hot_inode_item *he, loff_t start) { hr->start = start; - hr->len =hot_shift (1 ,RANGE_BITS , true); + hr->len =hot_shift (1 , he->hot_root->hot_type->range_bits, true); hr->hot_inode = he; hr->storage_type =-1 ;hot_comm_item_init (&hr->hot_range,TYPE_RANGE );
@@ -259,10 +259,11 @@ struct hot_range_item {struct rb_node **p;struct rb_node *parent =NULL ; +struct hot_info *root = he->hot_root;struct hot_comm_item *ci;struct hot_range_item *hr, *hr_new =NULL ; - start =hot_shift (start,RANGE_BITS , true); + start =hot_shift (start, root->hot_type->range_bits, true);/* walk tree to find insertion point */ redo:
@@ -350,13 +351,13 @@ static void hot_freq_update(struct hot_info *root,if (write) { freq_data->nr_writes +=1 ; -hot_freq_calc (freq_data->last_write_time, +HOT_FREQ_CALC (root, 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_freq_calc (freq_data->last_read_time, +HOT_FREQ_CALC (root, freq_data->last_read_time, cur_time, &freq_data->avg_delta_reads); freq_data->last_read_time = cur_time;
@@ -381,7 +382,7 @@ static void hot_freq_update(struct hot_info *root,* the *_COEFF_POWER values and combined to a single temperature * value. */ -u32 hot_temp_calc (struct hot_comm_item *ci) +static u32 hot_temp_calc (struct hot_comm_item *ci) {u32 result =0 ;struct hot_freq_data *freq_data = &ci->hot_freq_data;
@@ -501,7 +502,7 @@ static void hot_comm_item_link_cb(struct rcu_head *head)static int hot_map_update (struct hot_info *root,struct hot_comm_item *ci) { -u32 temp =hot_temp_calc (ci); +u32 temp =HOT_TEMP_CALC (root, ci);u8 cur_temp, prev_temp;int flag = false;
@@ -564,7 +565,7 @@ static void hot_range_update(struct hot_inode_item *he, hot_map_update(root, ci)) {continue ; } - obsolete =hot_is_obsolete (ci); + obsolete =HOT_IS_OBSOLETE (root, ci);if (obsolete)hot_comm_item_unlink (root, ci); }
@@ -1167,10 +1168,10 @@ void hot_update_freqs(struct inode *inode, loff_t start,* Align ranges on range size boundary * to prevent proliferation of range structs */ - range_size =hot_shift (1 ,RANGE_BITS , true); + range_size =hot_shift (1 , root->hot_type->range_bits, true); end =hot_shift ((start + len + range_size -1 ), -RANGE_BITS , false); - cur =hot_shift (start,RANGE_BITS , false); + root->hot_type->range_bits, false); + cur =hot_shift (start, root->hot_type->range_bits, false);for (; cur < end; cur++) { hr =hot_range_item_lookup (he, cur,1 );if (IS_ERR (hr)) {
@@ -1211,6 +1212,17 @@ static struct hot_info *hot_tree_init(struct super_block *sb)INIT_LIST_HEAD (&root->hot_map[j][i]); } +/* Get hot type for specific FS */ + root->hot_type = &sb->s_type->hot_type; +if (!HOT_FREQ_FN_EXIST (root)) +SET_HOT_FREQ_FN (root, hot_freq_calc); +if (!HOT_TEMP_FN_EXIST (root)) +SET_HOT_TEMP_FN (root, hot_temp_calc); +if (!HOT_OBSOLETE_FN_EXIST (root)) +SET_HOT_OBSOLETE_FN (root, hot_is_obsolete); +if (root->hot_type->range_bits ==0 ) + root->hot_type->range_bits =RANGE_BITS ; + root->update_wq =alloc_workqueue ("hot_update_wq" ,WQ_NON_REENTRANT ,0 );if (!root->update_wq) {
fs/hot_tracking.h +19 -0
@@ -40,6 +40,25 @@#define AVW_DIVIDER_POWER 40/* AVW - average delta between recent writes(ns) */ #define AVW_COEFF_POWER 0 +#define HOT_FREQ_FN_EXIST (root) \ + ((root)->hot_type->ops.hot_freq_calc) +#define HOT_TEMP_FN_EXIST (root) \ + ((root)->hot_type->ops.hot_temp_calc) +#define HOT_OBSOLETE_FN_EXIST (root) \ + ((root)->hot_type->ops.hot_is_obsolete) + +#define HOT_FREQ_CALC (root, lt, ct, avg) \ + ((root)->hot_type->ops.hot_freq_calc(lt, ct, avg)) +#define HOT_IS_OBSOLETE (root, ci) \ + ((root)->hot_type->ops.hot_is_obsolete(ci)) + +#define SET_HOT_FREQ_FN (root, fn) \ + (root)->hot_type->ops.hot_freq_calc = fn +#define SET_HOT_TEMP_FN (root, fn) \ + (root)->hot_type->ops.hot_temp_calc = fn +#define SET_HOT_OBSOLETE_FN (root, fn) \ + (root)->hot_type->ops.hot_is_obsolete = fn +struct hot_debugfs {const char *name;const struct file_operations *fops;
fs/ioctl.c +1 -1
@@ -585,7 +585,7 @@ static int ioctl_heat_info(struct file *file, void __user *argp)* got a request for live temperature, * call hot_calc_temp() to recalculate */ - heat_info.temp =hot_temp_calc (&he->hot_inode); + heat_info.temp =HOT_TEMP_CALC (he->hot_root, &he->hot_inode); }else {/* not live temperature, get it from the map list */ heat_info.temp = he->hot_inode.hot_freq_data.last_temp;
include/linux/fs.h +1 -0
@@ -1817,6 +1817,7 @@ struct file_system_type {struct dentry *(*mount) (struct file_system_type *,int ,const char *,void *);void (*kill_sb) (struct super_block *); +struct hot_type hot_type;struct module *owner;struct file_system_type * next;struct hlist_head fs_supers;
include/linux/hot_tracking.h +21 -1
@@ -97,6 +97,26 @@ struct hot_range_item {int storage_type;/* type of storage */ }; +typedef void (hot_freq_calc_fn ) (struct timespec old_atime, +struct timespec cur_time,u64 *avg); +typedef u32 (hot_temp_calc_fn ) (struct hot_comm_item *ci); +typedef bool (hot_is_obsolete_fn ) (struct hot_comm_item *ci); + +struct hot_func_ops { +hot_freq_calc_fn *hot_freq_calc; +hot_temp_calc_fn *hot_temp_calc; +hot_is_obsolete_fn *hot_is_obsolete; +}; + +/* identifies an hot type */ +struct hot_type { +u64 range_bits; +struct hot_func_ops ops;/* fields provided by specific FS */ +}; + +#define HOT_TEMP_CALC (root, ci) \ + ((root)->hot_type->ops.hot_temp_calc(ci)) +struct hot_info {struct rb_root hot_inode_tree;spinlock_t t_lock;/* protect above tree */
@@ -105,6 +125,7 @@ struct hot_info {atomic_t hot_map_nr;struct workqueue_struct *update_wq;struct delayed_work update_work; +struct hot_type *hot_type;struct shrinker hot_shrink;struct dentry *debugfs_dentry; };
@@ -135,7 +156,6 @@ extern struct hot_inode_item *hot_inode_item_lookup(struct hot_info *root,extern struct hot_range_item *hot_range_item_lookup (struct hot_inode_item *he,loff_t start,int alloc);extern void hot_inode_item_delete (struct inode *inode); -extern u32 hot_temp_calc (struct hot_comm_item *ci);static inline u64 hot_shift (u64 counter,u32 bits,bool dir) {
Signature · 1 line
1.7.11.7
Ping...
Quoted 110 lines · On Tue, May 14, 2013 at 8:59 AM, <[email protected]> wrote:
From: Zhi Yong Wu <[email protected]>
The patchset is trying to introduce hot tracking function in
VFS layer, which will keep track of real disk I/O in memory. By it, you will easily know more details about disk I/O, and then detect where disk I/O hot spots are. Also, specific FS can take use of it to do accurate defragment, and hot relocation support, etc.After V1 was sent out, Chandra Seetharaman has reviewed and
made a lot of comments, thanks a lot to him. Not it's time to send out its V2 for external review, any comments or ideas are appreciated, thanks.NOTE:
The patchset can be obtained via my kernel dev git on github:
git://github.com/wuzhy/kernel.githot_tracking
If you're interested, you can also review them via
https://github.com/wuzhy/kernel/commits/hot_trackingFor how to use and more other info and performance report,
please check hot_tracking.txt in Documentation and following links:
1.) http://lwn.net/Articles/525651/
2.) https://lkml.org/lkml/2012/12/20/199Changelog from v1:
- Refactored to be under RCU [Chandra Seetharaman]
- Merged some code changes [Chandra Seetharaman]
- Fixed some issues [Chandra Seetharaman]v1:
- Solved 64 bits inode number issue. [David Sterba]
- Embed structhot_typein structfile_system_type[Darrick J. Wong]
- Cleanup Some issues [David Sterba]
- Use a static hot debugfs root [Greg KH]rfcv4:
- Introduce hot func registering framework [Zhiyong]
- Remove global variable for hot tracking [Zhiyong]
- Add btrfs hot tracking support [Zhiyong]rfcv3:
1.) Rewritten debugfs support basedseq_fileoperation. [Dave Chinner] 2.) Refactored workqueue support. [Dave Chinner]
3.) Turn some Micro into be tunable [Zhiyong, Liu Zheng]
TIME_TO_KICK, andHEAT_UPDATE_DELAY
4.) Cleanedup a lot of other issues [Dave Chinner]rfcv2:
1.) Converted to Radix trees, not RB-tree [Zhiyong, Dave Chinner] 2.) Added memory shrinker [Dave Chinner]
3.) Converted to one workqueue to update map info periodically [Dave Chinner] 4.) Cleanedup a lot of other issues [Dave Chinner]rfcv1:
1.) Reduce new files and put all in fs/hot_tracking.[ch] [Dave Chinner] 2.) The first three patches can probably just be flattened into one.
[Marco Stornelli , Dave Chinner]Zhi Yong Wu (12):
VFS hot tracking: introduce some data structures VFS hot tracking: add i/o freq tracking hooks
VFS hot tracking: add one workqueue to update hot map VFS hot tracking: register one shrinker
VFS hot tracking, rcu: introduce one rcu macro for list VFS hot tracking,seq_file: introduce one set of rcuseq_list
interfaces
VFS hot tracking: add debugfs support
VFS hot tracking: add one ioctl interface
VFS hot tracking, procfs: add two proc interfaces VFS hot tracking, btrfs: add hot tracking support VFS hot tracking: add documentation
VFS hot tracking: add fs hot type supportDocumentation/filesystems/00-INDEX | 2 + Documentation/filesystems/hot_tracking.txt | 256 ++++++ fs/Makefile | 2 +- fs/btrfs/ctree.h | 1 + fs/btrfs/super.c | 22 +- fs/compat_ioctl.c | 5 + fs/dcache.c | 2 + fs/direct-io.c | 5 + fs/hot_tracking.c | 1320 ++++++++++++++++++++++++++++ fs/hot_tracking.h | 67 ++ fs/ioctl.c | 70 ++ fs/namei.c | 2 + fs/seq_file.c | 37 + include/linux/fs.h | 5 + include/linux/hot_tracking.h | 175 ++++ include/linux/rculist.h | 5 + include/linux/seq_file.h | 7 + kernel/sysctl.c | 14 + mm/filemap.c | 6 + mm/page-writeback.c | 12 + mm/readahead.c | 6 + 21 files changed, 2019 insertions(+), 2 deletions(-) create mode 100644 Documentation/filesystems/hot_tracking.txt create mode 100644 fs/hot_tracking.c create mode 100644 fs/hot_tracking.h create mode 100644 include/linux/hot_tracking.h--
1.7.11.7--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 3 lines
Regards, Zhi Yong Wu
HI, Al Viro.
I have incorporated all comments from all reviewers and waited for
so long time. If you have no comments, can you merge the patchset? thanks.