PATCH v4 00/10] VFS hot tracking
Subsystems (8)
PATCH RESEND 1/1 PATCH v4 00/10] 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.
Now it's time to send out its V4 for external review, and
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 v3:
- Removed debugfs support, but leave it to TODO list [viro, Chandra]
- Killed HOT_DELETING and HOT_IN_LIST flag [viro]
- Fixed unlink issues [viro]
- Fixed the issue on lookups (both for inode and range) leak on race with unlink [viro]
- Killed hot_comm_item and split the functions which take it [virio]
- Fixed some other issues [zwu, Chandra]
v3:
- Added memory caping function for hot items [Zhiyong]
- Cleanup aging function [Zhiyong]
v2:
- 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]
Dave Chinner (1):
VFS hot tracking, xfs: Add hot tracking support
Zhi Yong Wu (9):
VFS hot tracking: Define basic data structures and functions VFS hot tracking: Track IO and record heat information VFS hot tracking: Add a workqueue to move items between hot maps VFS hot tracking: Add shrinker functionality to curtail memory usage VFS hot tracking: Add an ioctl to get hot tracking information VFS hot tracking: Add a /proc interface to make the interval tunable VFS hot tracking: Add a /proc interfaces to control memory usage VFS hot tracking: Add documentation
VFS hot tracking, btrfs: Add hot tracking support
Documentation/filesystems/00-INDEX | 2 + Documentation/filesystems/hot_tracking.txt | 207 +++++++ 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 | 833 +++++++++++++++++++++++++++++ fs/hot_tracking.h | 66 +++ fs/ioctl.c | 68 +++ fs/namei.c | 3 + fs/xfs/xfs_mount.h | 1 + fs/xfs/xfs_super.c | 18 + include/linux/fs.h | 4 + include/linux/hot_tracking.h | 148 +++++ kernel/sysctl.c | 14 + mm/filemap.c | 6 + mm/page-writeback.c | 12 + mm/readahead.c | 6 + 20 files changed, 1423 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 RESEND 1/1 PATCH v4 01/10] VFS hot tracking: Define basic data structures and functions
From: Zhi Yong Wu <[email protected]>
This patch includes the basic data structure and functions needed for VFS hot tracking.
It adds hot_inode_tree struct to keep track of frequently accessed files, and is keyed by {inode, offset}. Trees contain hot_inode_items representing those files and hot_range_items representing ranges in that file.
It defines a data structure hot_info, which is associated with a mounted filesystem, and will be used to store the inode tree and range tree for hot items pertaining to that filesystem.
--- fs/Makefile | 2 +- fs/dcache.c | 2 + fs/hot_tracking.c | 233 +++++++++++++++++++++++++++++++++++++++++++ fs/hot_tracking.h | 20 ++++ include/linux/fs.h | 4 + include/linux/hot_tracking.h | 84 ++++++++++++++++ 6 files changed, 344 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
@@ -11,7 +11,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"
@@ -3081,4 +3082,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 +233 -0
233 lines not on this page · raw message
fs/hot_tracking.h new file +20 -0
@@ -0,0 +1,20 @@ +/* +* 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> + +/* size of sub-file ranges */ +#define RANGE_BITS 20 + +#endif /* __HOT_TRACKING__ */
include/linux/fs.h +4 -0
@@ -28,6 +28,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>
@@ -1328,6 +1329,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 +84 -0
84 lines not on this page · raw message
Signature · 1 line
1.7.11.7
PATCH RESEND 1/1 PATCH v4 02/10] VFS hot tracking: Track IO and record heat information
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
This patch adds read/write code paths: include read_pages(), do_writepages(), do_generic_file_read() and __blockdev_direct_IO() to record heat information.
When real disk i/o for an inode is done, its own hot_inode_item will be created or updated in the RB tree for the filesystem, and the i/o freq for all of its extents will also be created/updated in the RB-tree per inode.
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}).
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 | 234 +++++++++++++++++++++++++++++++++++++++++++ fs/hot_tracking.h | 1 + fs/namei.c | 3 + include/linux/hot_tracking.h | 28 ++++++ mm/filemap.c | 6 ++ mm/page-writeback.c | 12 +++ mm/readahead.c | 6 ++ 8 files changed, 295 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 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 +234 -0
264 lines not on this page · raw message
fs/hot_tracking.h +1 -0
@@ -16,5 +16,6 @@/* size of sub-file ranges */ #define RANGE_BITS 20 +#define FREQ_POWER 4#endif /* __HOT_TRACKING__ */
fs/namei.c +3 -0
@@ -3454,6 +3454,9 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) }mutex_unlock (&dentry->d_inode->i_mutex); +if (!error && !dentry->d_inode->i_nlink) +hot_inode_item_unlink (dentry->d_inode); +/* We don't d_delete() NFS sillyrenamed files--they still exist. */ if (!error && !(dentry->d_flags &DCACHE_NFSFS_RENAMED )) {fsnotify_link_count (dentry->d_inode);
include/linux/hot_tracking.h +28 -0
@@ -34,8 +34,24 @@ enum { MAX_TYPES, }; +/* +* A frequency data struct holds values that are used to +* determine temperature of files and file ranges. These structs +* are members of hot_inode_item and hot_range_item +*/ +struct hot_freq { +struct timespec last_read_time; +struct timespec last_write_time; +u32 nr_reads; +u32 nr_writes; +u64 avg_delta_reads; +u64 avg_delta_writes; +u32 last_temp; +}; +/* An item representing an inode and its access frequency */ struct hot_inode_item { +struct hot_freq freq;/* frequency data */ struct kref refs;struct rb_node rb_node;/* rbtree index */ struct rcu_head rcu;
@@ -50,6 +66,7 @@ struct hot_inode_item {* an inode whose frequency is being tracked */ struct hot_range_item { +struct hot_freq freq;/* frequency data */ struct kref refs;struct rb_node rb_node;/* rbtree index */ struct rcu_head rcu;
@@ -70,6 +87,17 @@ extern void hot_range_item_put(struct hot_range_item *hr);extern void hot_inode_item_put (struct hot_inode_item *he);extern void hot_range_item_get (struct hot_range_item *hr);extern void hot_inode_item_get (struct hot_inode_item *he); +extern void hot_update_freqs (struct inode *inode, +loff_t start,size_t len,int rw); +extern struct hot_range_item +*hot_range_item_lookup (struct hot_inode_item *he, +loff_t start,int alloc); +extern struct hot_inode_item +*hot_inode_item_lookup (struct hot_info *root, +u64 ino,int alloc); +extern void hot_inode_item_unlink (struct inode *inode); +extern void hot_update_freqs (struct inode *inode,loff_t start, +size_t len,int rw);static inline u64 hot_bit_shift (u64 counter,u32 bits,bool dir) {
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 tracking */ +hot_update_freqs (inode, 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 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 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 RESEND 1/1 PATCH v4 03/10] VFS hot tracking: Add a workqueue to move items between hot maps
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]. It will be be linked to its corresponding array of map list which use the temperature as its index.
--- fs/hot_tracking.c | 262 +++++++++++++++++++++++++++++++++++++++++++ fs/hot_tracking.h | 24 ++++ include/linux/hot_tracking.h | 9 +- 3 files changed, 294 insertions(+), 1 deletion(-)
fs/hot_tracking.c +262 -0
@@ -23,6 +23,7 @@ static void hot_range_item_init(struct hot_range_item *hr, struct hot_inode_item *he, loff_t start) {kref_init (&hr->refs); +INIT_LIST_HEAD (&hr->track_list); hr->freq.avg_delta_reads = (u64) -1 ; hr->freq.avg_delta_writes = (u64) -1 ; hr->start = start;
@@ -45,6 +46,9 @@ static void hot_range_item_free(struct kref *kref)struct hot_info *root = hr->hot_inode->hot_root;rb_erase (&hr->rb_node, &hr->hot_inode->hot_range_tree); +spin_lock (&root->m_lock); +list_del_init (&hr->track_list); +spin_unlock (&root->m_lock);call_rcu (&hr->rcu, hot_range_item_free_cb); }
@@ -70,6 +74,8 @@ struct hot_range_itemstruct rb_node **p;struct rb_node *parent =NULL ;struct hot_range_item *hr, *hr_new =NULL ; +u32 temp; +u8 temp_cur; start =hot_bit_shift (start,RANGE_BITS , true);
@@ -103,6 +109,12 @@ redo:if (hr_new) {rb_link_node (&hr_new->rb_node, parent, p);rb_insert_color (&hr_new->rb_node, &he->hot_range_tree); + temp =hot_temp_calc (&hr_new->freq); + temp_cur = (u8 )hot_bit_shift ((u64 )temp, (32 -MAP_BITS ), false); +spin_lock (&he->hot_root->m_lock); +list_add_tail (&hr_new->track_list, + &he->hot_root->hot_map[TYPE_RANGE ][temp_cur]); +spin_unlock (&he->hot_root->m_lock);hot_range_item_get (hr_new);/* For the caller */ spin_unlock (&he->i_lock);return hr_new;
@@ -141,10 +153,67 @@ static void hot_range_tree_free(struct hot_inode_item *he)spin_unlock (&he->i_lock); } +static void hot_range_map_update (struct hot_info *root, +struct hot_range_item *hr) +{ +u32 temp =hot_temp_calc (&hr->freq); +u8 temp_cur = (u8 )hot_bit_shift ((u64 )temp, (32 -MAP_BITS ), false); +u8 temp_prev = (u8 )hot_bit_shift ((u64 )hr->freq.last_temp, + (32 -MAP_BITS ), false); + +spin_lock (&root->m_lock); +if (!list_empty (&hr->track_list) + && (temp_cur != temp_prev)) { + hr->freq.last_temp = temp; +list_del_init (&hr->track_list); +list_add_tail (&hr->track_list, + &root->hot_map[TYPE_RANGE ][temp_cur]); + } +spin_unlock (&root->m_lock); +} + +/* +* 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_tree_update (struct hot_inode_item *he, +struct hot_info *root) +{ +struct rb_node *node; +struct hot_range_item *hr; + +rcu_read_lock (); + node =rb_first (&he->hot_range_tree); +while (node) { + hr = rb_entry(node, struct hot_range_item, rb_node); + node =rb_next (node); +hot_range_map_update (root, hr); + } +rcu_read_unlock (); +} + +static int hot_range_temp_cmp (void *priv,struct list_head *a, +struct list_head *b) +{ +struct hot_range_item *ap =container_of (a, + struct hot_range_item, track_list); +struct hot_range_item *bp =container_of (b, + struct hot_range_item, track_list); + +int diff = ap->freq.last_temp - bp->freq.last_temp; +if (diff >0 ) +return -1 ; +else if (diff <0 ) +return 1 ; +else +return 0 ; +} +static void hot_inode_item_init (struct hot_inode_item *he,struct hot_info *root,u64 ino) {kref_init (&he->refs); +INIT_LIST_HEAD (&he->track_list); he->freq.avg_delta_reads = (u64) -1 ; he->freq.avg_delta_writes = (u64) -1 ; he->i_ino = ino;
@@ -166,6 +235,7 @@ static void hot_inode_item_free(struct kref *kref) struct hot_inode_item, refs);rb_erase (&he->rb_node, &he->hot_root->hot_inode_tree); +list_del_init (&he->track_list);hot_range_tree_free (he);call_rcu (&he->rcu, hot_inode_item_free_cb); }
@@ -192,6 +262,8 @@ struct hot_inode_itemstruct rb_node **p;struct rb_node *parent =NULL ;struct hot_inode_item *he, *he_new =NULL ; +u32 temp; +u8 temp_cur;/* walk tree to find insertion point */ redo:
@@ -223,6 +295,10 @@ redo:if (he_new) {rb_link_node (&he_new->rb_node, parent, p);rb_insert_color (&he_new->rb_node, &root->hot_inode_tree); + temp =hot_temp_calc (&he_new->freq); + temp_cur = (u8 )hot_bit_shift ((u64 )temp, (32 -MAP_BITS ), false); +list_add_tail (&he_new->track_list, + &root->hot_map[TYPE_INODE ][temp_cur]);hot_inode_item_get (he_new);/* For the caller */ spin_unlock (&root->t_lock);return he_new;
@@ -262,6 +338,47 @@ void hot_inode_item_unlink(struct inode *inode)EXPORT_SYMBOL_GPL (hot_inode_item_unlink);/* +* 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 void hot_inode_map_update (struct hot_info *root, +struct hot_inode_item *he) +{ +u32 temp =hot_temp_calc (&he->freq); +u8 temp_cur = (u8 )hot_bit_shift ((u64 )temp, (32 -MAP_BITS ), false); +u8 temp_prev = (u8 )hot_bit_shift ((u64 )he->freq.last_temp, + (32 -MAP_BITS ), false); + +spin_lock (&root->t_lock); +if (!list_empty (&he->track_list) + && (temp_cur != temp_prev)) { + he->freq.last_temp = temp; +list_del_init (&he->track_list); +list_add_tail (&he->track_list, + &root->hot_map[TYPE_INODE ][temp_cur]); + } +spin_unlock (&root->t_lock); +} + +static int hot_inode_temp_cmp (void *priv,struct list_head *a, +struct list_head *b) +{ +struct hot_inode_item *ap =container_of (a, + struct hot_inode_item, track_list); +struct hot_inode_item *bp =container_of (b, + struct hot_inode_item, track_list); + +int diff = ap->freq.last_temp - bp->freq.last_temp; +if (diff >0 ) +return -1 ; +else if (diff <0 ) +return 1 ; +else +return 0 ; +} + +/* * This function does the actual work of updating * the frequency numbers. *
@@ -307,6 +424,128 @@ 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. +*/ +u32 hot_temp_calc (struct hot_freq *freq) +{ +u32 result =0 ; + +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_bit_shift ((u64 )freq->nr_reads, +NRR_MULTIPLIER_POWER , true); + nrw_heat = (u32 )hot_bit_shift ((u64 )freq->nr_writes, +NRW_MULTIPLIER_POWER , true); + + ltr_heat = +hot_bit_shift ((cur_time -timespec_to_ns (&freq->last_read_time)), +LTR_DIVIDER_POWER , false); + ltw_heat = +hot_bit_shift ((cur_time -timespec_to_ns (&freq->last_write_time)), +LTW_DIVIDER_POWER , false); + + avr_heat = +hot_bit_shift ((((u64) -1 ) - freq->avg_delta_reads), +AVR_DIVIDER_POWER , false); + avw_heat = +hot_bit_shift ((((u64) -1 ) - freq->avg_delta_writes), +AVW_DIVIDER_POWER , false); + +/* ltr_heat is now guaranteed to be u32 safe */ +if (ltr_heat >=hot_bit_shift ((u64 )1 ,32 , true)) + ltr_heat =0 ; +else + ltr_heat =hot_bit_shift ((u64 )1 ,32 , true) - ltr_heat; + +/* ltw_heat is now guaranteed to be u32 safe */ +if (ltw_heat >=hot_bit_shift ((u64 )1 ,32 , true)) + ltw_heat =0 ; +else + ltw_heat =hot_bit_shift ((u64 )1 ,32 , true) - ltw_heat; + +/* avr_heat is now guaranteed to be u32 safe */ +if (avr_heat >=hot_bit_shift ((u64 )1 ,32 , true)) + avr_heat = (u32) -1 ; + +/* avw_heat is now guaranteed to be u32 safe */ +if (avw_heat >=hot_bit_shift ((u64 )1 ,32 , true)) + avw_heat = (u32) -1 ; + + nrr_heat = (u32 )hot_bit_shift ((u64 )nrr_heat, + (3 -NRR_COEFF_POWER ), false); + nrw_heat = (u32 )hot_bit_shift ((u64 )nrw_heat, + (3 -NRW_COEFF_POWER ), false); + ltr_heat =hot_bit_shift (ltr_heat, (3 -LTR_COEFF_POWER ), false); + ltw_heat =hot_bit_shift (ltw_heat, (3 -LTW_COEFF_POWER ), false); + avr_heat =hot_bit_shift (avr_heat, (3 -AVR_COEFF_POWER ), false); + avw_heat =hot_bit_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; +} + +/* +* 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 hot_inode_item *he; +struct rb_node *node; +int i; + +rcu_read_lock (); + node =rb_first (&root->hot_inode_tree); +while (node) { + he = rb_entry(node, struct hot_inode_item, rb_node); + node =rb_next (node); +hot_inode_map_update (root, he); +hot_range_tree_update (he, root); + } +rcu_read_unlock (); + +/* Sort temperature map info based on last temperature */ +for (i =0 ; i <MAP_SIZE ; i++) { +spin_lock (&root->t_lock); +list_sort (NULL , &root->hot_map[TYPE_INODE ][i], + hot_inode_temp_cmp); +spin_unlock (&root->t_lock); + +spin_lock (&root->m_lock); +list_sort (NULL , &root->hot_map[TYPE_RANGE ][i], + hot_range_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 )
@@ -393,6 +632,26 @@ 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); + +for (i =0 ; i <MAP_SIZE ; i++) { +for (j =0 ; j <MAX_TYPES ; j++) +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; }
@@ -404,6 +663,9 @@ static void hot_tree_exit(struct hot_info *root) {struct rb_node *node; +cancel_delayed_work_sync (&root->update_work); +destroy_workqueue (root->update_wq); +spin_lock (&root->t_lock); node =rb_first (&root->hot_inode_tree);while (node) {
fs/hot_tracking.h +24 -0
@@ -12,10 +12,34 @@#ifndef __HOT_TRACKING__#define __HOT_TRACKING__ +#include <linux/workqueue.h> #include <linux/hot_tracking.h> +#define HOT_UPDATE_INTERVAL 150 +/* 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 +8 -1
@@ -55,6 +55,7 @@ struct hot_inode_item {struct kref refs;struct rb_node rb_node;/* rbtree index */ struct rcu_head rcu; +struct list_head track_list;/* link to *_map[] */ struct rb_root hot_range_tree;/* tree of ranges */ spinlock_t i_lock;/* protect above tree */ struct hot_info *hot_root;/* associated hot_info */
@@ -70,6 +71,7 @@ struct hot_range_item {struct kref refs;struct rb_node rb_node;/* rbtree index */ struct rcu_head rcu; +struct list_head track_list;/* link to *_map[] */ struct hot_inode_item *hot_inode;/* associated hot_inode_item */ loff_t start;/* offset in bytes */ size_t len;/* length in bytes */
@@ -77,7 +79,11 @@ struct hot_range_item {struct hot_info {struct rb_root hot_inode_tree; -spinlock_t t_lock;/* protect above tree */ +struct list_head hot_map[MAX_TYPES ][MAP_SIZE ];/* map of inode temp */ +spinlock_t t_lock;/* protect tree and map for inode item */ +spinlock_t m_lock;/* protect map for range item */ +struct workqueue_struct *update_wq; +struct delayed_work update_work; };extern void __init hot_cache_init (void );
@@ -96,6 +102,7 @@ extern struct hot_inode_item *hot_inode_item_lookup(struct hot_info *root, u64 ino, int alloc);extern void hot_inode_item_unlink (struct inode *inode); +extern u32 hot_temp_calc (struct hot_freq *freq);extern void hot_update_freqs (struct inode *inode,loff_t start,size_t len,int rw);
Signature · 1 line
1.7.11.7
PATCH RESEND 1/1 PATCH v4 04/10] VFS hot tracking: Add shrinker functionality to curtail memory usage
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.
--- fs/hot_tracking.c | 74 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/hot_tracking.h | 2 ++ 2 files changed, 76 insertions(+)
fs/hot_tracking.c +74 -0
@@ -29,13 +29,16 @@ static void hot_range_item_init(struct hot_range_item *hr, hr->start = start; hr->len =hot_bit_shift (1 ,RANGE_BITS , true); hr->hot_inode = he; +atomic_long_inc (&he->hot_root->hot_cnt); }static void hot_range_item_free_cb (struct rcu_head *head) {struct hot_range_item *hr =container_of (head, struct hot_range_item, rcu); +struct hot_info *root = hr->hot_inode->hot_root; +atomic_long_dec (&root->hot_cnt);kmem_cache_free (hot_range_item_cachep, hr); }
@@ -219,13 +222,16 @@ static void hot_inode_item_init(struct hot_inode_item *he, he->i_ino = ino; he->hot_root = root;spin_lock_init (&he->i_lock); +atomic_long_inc (&root->hot_cnt); }static void hot_inode_item_free_cb (struct rcu_head *head) {struct hot_inode_item *he =container_of (head, struct hot_inode_item, rcu); +struct hot_info *root = he->hot_root; +atomic_long_dec (&root->hot_cnt);kmem_cache_free (hot_inode_item_cachep, he); }
@@ -504,6 +510,39 @@ u32 hot_temp_calc(struct hot_freq *freq)return result; } +static void hot_item_evict (struct hot_info *root,unsigned long work, +unsigned long (*work_get)(struct hot_info *root)) +{ +int i; + +if (work <=0 ) +return ; + +for (i =0 ; i <MAP_SIZE ; i++) { +struct hot_inode_item *he, *next; +unsigned long work_prev; + +spin_lock (&root->t_lock); +if (list_empty (&root->hot_map[TYPE_INODE ][i])) { +spin_unlock (&root->t_lock); +continue ; + } + +list_for_each_entry_safe (he, next, + &root->hot_map[TYPE_INODE ][i], track_list) { + work_prev =work_get (root); +hot_inode_item_put (he); + work -= (work_prev -work_get (root)); +if (work <=0 ) +break ; + } +spin_unlock (&root->t_lock); + +if (work <=0 ) +break ; + } +} +/* * Every sync period we update temperatures for * each hot inode item and hot range item for aging
@@ -566,6 +605,34 @@ void __init hot_cache_init(void) }EXPORT_SYMBOL_GPL (hot_cache_init); +static inline unsigned long hot_cnt_get (struct hot_info *root) +{ +return (unsigned long )atomic_long_read (&root->hot_cnt); +} + +static void hot_prune_map (struct hot_info *root,unsigned long nr) +{ +hot_item_evict (root, nr, hot_cnt_get); +} + +/* 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_long_read (&root->hot_cnt) /2 ; + +if (!(sc->gfp_mask & __GFP_FS)) +return -1 ; + +hot_prune_map (root, sc->nr_to_scan); + +return atomic_long_read (&root->hot_cnt); +} +/* * Main function to update i/o access frequencies, and it will be called * from read/writepages() hooks, which are read_pages(), do_writepages(),
@@ -633,6 +700,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_long_set (&root->hot_cnt,0 );for (i =0 ; i <MAP_SIZE ; i++) {for (j =0 ; j <MAX_TYPES ; j++)
@@ -653,6 +721,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; }
@@ -663,6 +736,7 @@ static void hot_tree_exit(struct hot_info *root) {struct rb_node *node; +unregister_shrinker (&root->hot_shrink);cancel_delayed_work_sync (&root->update_work);destroy_workqueue (root->update_wq);
include/linux/hot_tracking.h +2 -0
@@ -82,8 +82,10 @@ struct hot_info {struct list_head hot_map[MAX_TYPES ][MAP_SIZE ];/* map of inode temp */ spinlock_t t_lock;/* protect tree and map for inode item */ spinlock_t m_lock;/* protect map for range item */ +atomic_long_t hot_cnt;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 RESEND 1/1 PATCH v4 05/10] VFS hot tracking: Add an ioctl to get hot tracking information
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/ioctl.c | 68 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/hot_tracking.h | 21 ++++++++++++++ 3 files changed, 94 insertions(+)
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>
@@ -1399,6 +1400,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. */
@@ -1578,6 +1582,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/ioctl.c +68 -0
86 lines not on this page · raw message
include/linux/hot_tracking.h +21 -0
@@ -18,6 +18,19 @@#include <linux/types.h> #include <linux/slab.h> +struct hot_heat_info { +__u8 live; +__u8 resv[3 ]; +__u32 temp; +__u64 avg_delta_reads; +__u64 avg_delta_writes; +__u64 last_read_time; +__u64 last_write_time; +__u32 num_reads; +__u32 num_writes; +__u64 future[4 ];/* For future expansions */ +}; +#ifdef __KERNEL__#include <linux/rbtree.h>
@@ -88,6 +101,14 @@ struct hot_info {struct shrinker hot_shrink; }; +/* +* 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);
Signature · 1 line
1.7.11.7
PATCH RESEND 1/1 PATCH v4 06/10] VFS hot tracking: Add a /proc interface to make the interval tunable
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
Add a proc interface hot-update-interval under the dir /proc/sys/fs/ in order to turn HOT_UPDATE_INTERVAL into a tunable parameter.
--- fs/hot_tracking.c | 7 +++++-- fs/hot_tracking.h | 2 -- include/linux/hot_tracking.h | 3 +++ kernel/sysctl.c | 7 +++++++ 4 files changed, 15 insertions(+), 4 deletions(-)
fs/hot_tracking.c +5 -2
@@ -15,6 +15,9 @@#include <linux/list_sort.h> #include "hot_tracking.h" +int sysctl_hot_update_interval__read_mostly =150 ; +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 ;
@@ -581,7 +584,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 )); }/*
@@ -719,7 +722,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 -2
@@ -15,8 +15,6 @@#include <linux/workqueue.h> #include <linux/hot_tracking.h> -#define HOT_UPDATE_INTERVAL 150 -/* size of sub-file ranges */ #define RANGE_BITS 20#define FREQ_POWER 4
include/linux/hot_tracking.h +3 -0
@@ -101,6 +101,9 @@ struct hot_info {struct shrinker hot_shrink; }; +/* set how often to update temperatures (seconds) */ +extern int sysctl_hot_update_interval; +/* * Hot data tracking ioctls: *
kernel/sysctl.c +7 -0
@@ -1631,6 +1631,13 @@ static struct ctl_table fs_table[] = { .proc_handler = &pipe_proc_fn, .extra1 = &pipe_min_size, }, + { + .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 RESEND 1/1 PATCH v4 07/10] VFS hot tracking: Add a /proc interfaces to control memory usage
In reply to [email protected]From: Zhi Yong Wu <[email protected]>
Introduce a proc interfaces hot-mem-high-thresh and to cap the memory which is consumed by hot_inode_item and hot_range_item, and they will be in the unit of 1M bytes.
--- fs/hot_tracking.c | 27 +++++++++++++++++++++++++++ fs/hot_tracking.h | 23 +++++++++++++++++++++++ include/linux/hot_tracking.h | 3 +++ kernel/sysctl.c | 7 +++++++ 4 files changed, 60 insertions(+)
fs/hot_tracking.c +27 -0
@@ -15,6 +15,9 @@#include <linux/list_sort.h> #include "hot_tracking.h" +int sysctl_hot_mem_high_thresh__read_mostly =0 ; +EXPORT_SYMBOL_GPL (sysctl_hot_mem_high_thresh); +int sysctl_hot_update_interval__read_mostly =150 ;EXPORT_SYMBOL_GPL (sysctl_hot_update_interval);
@@ -33,6 +36,7 @@ static void hot_range_item_init(struct hot_range_item *hr, hr->len =hot_bit_shift (1 ,RANGE_BITS , true); hr->hot_inode = he;atomic_long_inc (&he->hot_root->hot_cnt); +hot_mem_limit_add (he->hot_root,sizeof (struct hot_range_item )); }static void hot_range_item_free_cb (struct rcu_head *head)
@@ -42,6 +46,7 @@ static void hot_range_item_free_cb(struct rcu_head *head)struct hot_info *root = hr->hot_inode->hot_root;atomic_long_dec (&root->hot_cnt); +hot_mem_limit_sub (root,sizeof (struct hot_range_item ));kmem_cache_free (hot_range_item_cachep, hr); }
@@ -226,6 +231,7 @@ static void hot_inode_item_init(struct hot_inode_item *he, he->hot_root = root;spin_lock_init (&he->i_lock);atomic_long_inc (&root->hot_cnt); +hot_mem_limit_add (root,sizeof (struct hot_inode_item )); }static void hot_inode_item_free_cb (struct rcu_head *head)
@@ -235,6 +241,7 @@ static void hot_inode_item_free_cb(struct rcu_head *head)struct hot_info *root = he->hot_root;atomic_long_dec (&root->hot_cnt); +hot_mem_limit_sub (root,sizeof (struct hot_inode_item ));kmem_cache_free (hot_inode_item_cachep, he); }
@@ -546,6 +553,23 @@ static void hot_item_evict(struct hot_info *root, unsigned long work, } } +static void hot_mem_evict (struct hot_info *root) +{ +unsigned long sum, thresh; + +if (sysctl_hot_mem_high_thresh ==0 ) +return ; + + sum =hot_mem_limit_sum (root); +/* Note: sysctl_** is in the unit of 1M bytes */ + thresh = sysctl_hot_mem_high_thresh; + thresh *=1024 *1024 ; +if (sum <= thresh) +return ; + +hot_item_evict (root, sum - thresh, hot_mem_limit_sum); +} +/* * Every sync period we update temperatures for * each hot inode item and hot range item for aging
@@ -559,6 +583,8 @@ static void hot_update_worker(struct work_struct *work)struct rb_node *node;int i; +hot_mem_evict (root); +rcu_read_lock (); node =rb_first (&root->hot_inode_tree);while (node) {
@@ -775,6 +801,7 @@ int hot_track_init(struct super_block *sb) goto err; } +hot_mem_limit_init (root); sb->s_hot_root = root;printk (KERN_INFO "VFS: Turning on hot tracking\n" );
fs/hot_tracking.h +23 -0
@@ -40,4 +40,27 @@#define AVW_DIVIDER_POWER 40/* AVW - average delta between recent writes(ns) */ #define AVW_COEFF_POWER 0 +/* Memory Tracking Functions. */ +static inline unsigned long hot_mem_limit_sum (struct hot_info *root) +{ +return atomic_long_read (&root->mem); +} + +static inline void hot_mem_limit_sub (struct hot_info *root, +unsigned long count) +{ +atomic_long_sub (count, &root->mem); +} + +static inline void hot_mem_limit_add (struct hot_info *root, +unsigned long count) +{ +atomic_long_add (count, &root->mem); +} + +static inline void hot_mem_limit_init (struct hot_info *root) +{ +atomic_long_set (&root->mem,0 ); +} +#endif /* __HOT_TRACKING__ */
include/linux/hot_tracking.h +3 -0
@@ -99,10 +99,13 @@ struct hot_info {struct workqueue_struct *update_wq;struct delayed_work update_work;struct shrinker hot_shrink; +atomic_long_t mem; };/* set how often to update temperatures (seconds) */ extern int sysctl_hot_update_interval; +/* note: sysctl_** is in the unit of 1M bytes */ +extern int sysctl_hot_mem_high_thresh;/* * Hot data tracking ioctls:
kernel/sysctl.c +7 -0
@@ -1632,6 +1632,13 @@ static struct ctl_table fs_table[] = { .extra1 = &pipe_min_size, }, { + .procname = "hot-mem-high-thresh", + .data = &sysctl_hot_mem_high_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { .procname = "hot-update-interval", .data = &sysctl_hot_update_interval, .maxlen = sizeof(int),
Signature · 1 line
1.7.11.7
PATCH RESEND 1/1 PATCH v4 08/10] 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 | 207 +++++++++++++++++++++++++++++ 2 files changed, 209 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 tracking in VFS layer
Documentation/filesystems/hot_tracking.txt new file +207 -0
207 lines not on this page · raw message
Signature · 1 line
1.7.11.7
PATCH RESEND 1/1 PATCH v4 09/10] 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
@@ -1967,6 +1967,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"
@@ -308,6 +309,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 {
@@ -320,7 +325,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, };
@@ -361,6 +366,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}, };
@@ -626,6 +632,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);
@@ -842,11 +851,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;
@@ -942,6 +960,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 RESEND 1/1 PATCH v4 10/10] VFS hot tracking, xfs: Add hot tracking support
In reply to [email protected]From: Dave Chinner <[email protected]>
Connect up the VFS hot tracking support so XFS filesystem can make use of it.
--- fs/xfs/xfs_mount.h | 1 + fs/xfs/xfs_super.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+)
fs/xfs/xfs_mount.h +1 -0
@@ -222,6 +222,7 @@ typedef struct xfs_mount {#define XFS_MOUNT_WSYNC (1ULL << 0)/* for nfs - all metadata ops must be synchronous except for space allocations */ +#define XFS_MOUNT_HOTTRACK (1ULL << 1)/* hot tracking */ #define XFS_MOUNT_WAS_CLEAN (1ULL << 3)#define XFS_MOUNT_FS_SHUTDOWN (1ULL << 4)/* atomic stop of all filesystem operations, typically for
fs/xfs/xfs_super.c +18 -0
@@ -62,6 +62,7 @@#include <linux/kthread.h> #include <linux/freezer.h> #include <linux/parser.h> +#include <linux/hot_tracking.h> static const struct super_operations xfs_super_operations;static kmem_zone_t *xfs_ioend_zone;
@@ -115,6 +116,7 @@ mempool_t *xfs_ioend_pool;#define MNTOPT_NODELAYLOG "nodelaylog"/* Delayed logging disabled */ #define MNTOPT_DISCARD "discard"/* Discard unused blocks */ #define MNTOPT_NODISCARD "nodiscard"/* Do not discard unused blocks */ +#define MNTOPT_HOTTRACK "hot_track"/* hot tracking */ /* * Table driven mount option parser.
@@ -381,6 +383,8 @@ xfs_parseargs( mp->m_flags |=XFS_MOUNT_DISCARD ; }else if (!strcmp (this_char,MNTOPT_NODISCARD )) { mp->m_flags &= ~XFS_MOUNT_DISCARD ; + }else if (!strcmp (this_char,MNTOPT_HOTTRACK )) { + mp->m_flags |=XFS_MOUNT_HOTTRACK ; }else if (!strcmp (this_char,"ihashsize" )) {xfs_warn (mp,"ihashsize no longer used, option is deprecated." );
@@ -510,6 +514,7 @@ xfs_showargs( { XFS_MOUNT_GRPID, "," MNTOPT_GRPID }, { XFS_MOUNT_DISCARD, "," MNTOPT_DISCARD }, { XFS_MOUNT_SMALL_INUMS, "," MNTOPT_32BITINODE }, + { XFS_MOUNT_HOTTRACK, "," MNTOPT_HOTTRACK }, { 0, NULL } }; static struct proc_xfs_info xfs_info_unset[] = {
@@ -1053,6 +1058,9 @@ xfs_fs_put_super( {struct xfs_mount *mp =XFS_M (sb); +if (mp->m_flags &XFS_MOUNT_HOTTRACK ) +hot_track_exit (sb); +xfs_filestream_unmount (mp);xfs_unmountfs (mp);
@@ -1500,8 +1508,18 @@ xfs_fs_fill_super( goto out_unmount; } +if (mp->m_flags &XFS_MOUNT_HOTTRACK ) { + error =hot_track_init (sb); +if (error) + goto out_free_root; + } +return 0 ; + out_free_root: +dput (sb->s_root); + sb->s_root =NULL ; + out_filestream_unmount:xfs_filestream_unmount (mp); out_free_sb:
Signature · 1 line
1.7.11.7
HI, Viro
any comment? If no, please merge it, thanks.
Quoted 120 lines · On Mon, Aug 12, 2013 at 10:20 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.Now it's time to send out its V4 for external review, and
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 v3:
- Removed debugfs support, but leave it to TODO list [viro, Chandra]
- KilledHOT_DELETINGandHOT_IN_LISTflag [viro]
- Fixed unlink issues [viro]
- Fixed the issue on lookups (both for inode and range) leak on race with unlink [viro]
- Killedhot_comm_itemand split the functions which take it [virio]
- Fixed some other issues [zwu, Chandra]v3:
- Added memory caping function for hot items [Zhiyong]
- Cleanup aging function [Zhiyong]v2:
- 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]Dave Chinner (1):
VFS hot tracking, xfs: Add hot tracking supportZhi Yong Wu (9):
VFS hot tracking: Define basic data structures and functions VFS hot tracking: Track IO and record heat information VFS hot tracking: Add a workqueue to move items between hot maps VFS hot tracking: Add shrinker functionality to curtail memory usage VFS hot tracking: Add an ioctl to get hot tracking information VFS hot tracking: Add a /proc interface to make the interval tunable VFS hot tracking: Add a /proc interfaces to control memory usage VFS hot tracking: Add documentation
VFS hot tracking, btrfs: Add hot tracking supportDocumentation/filesystems/00-INDEX | 2 + Documentation/filesystems/hot_tracking.txt | 207 +++++++ 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 | 833 +++++++++++++++++++++++++++++ fs/hot_tracking.h | 66 +++ fs/ioctl.c | 68 +++ fs/namei.c | 3 + fs/xfs/xfs_mount.h | 1 + fs/xfs/xfs_super.c | 18 + include/linux/fs.h | 4 + include/linux/hot_tracking.h | 148 +++++ kernel/sysctl.c | 14 + mm/filemap.c | 6 + mm/page-writeback.c | 12 + mm/readahead.c | 6 + 20 files changed, 1423 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-fsdevel" 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
Quoted 7 lines · On Mon, 12 August 2013 10:20:14 +0800, [email protected] wrote:
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.
I find this description extremely uninteresting. Sure, you can track hot now. Grammatically, I am missing a noun. Are you tracking hot pages, hot files or hot potatoes?
More importantly, once you have identified the hot stuff, why should I care? What problem does it solve? The documentation patch at the end has a "motivation" paragraph, but the introduction email does not. As a result, every time you sent these patches, I quickly glanced at them, decided not to care and moved on.
And finally, now that I have hunted down the motivation and know it is about caching stuff on ssd, I question your basic approach. Why do you want to touch the vfs at all and not do it as a block device driver? The big advantage of a block driver is that noone cares. People without ssd shouldn't care, as caching doesn't help them. People without spinning rust shouldn't care as caching doesn't help them either. And people with a mixture of both shouldn't care in a few years time, once they have fully transitioned to ssd.
If you solve the problem in the vfs, I am forced to care. I cannot just select CONFIG_CACHING_BLOCK_DEVICE=n and be done with it. If you want me to carry such a cost for you, you better demonstrate some enticing advantages for me as well. There is no CONFIG_VFS=n, after all.
Jörn
--
Audacity augments courage; hesitation, fear.
-- Publilius Syrus
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Al Viro
maintainerQuoted 8 lines · On Mon, Aug 12, 2013 at 10:20:14AM +0800, [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.
Sigh...
a) ioctl_heat_info() calls hot_inode_item_put() with no locks held. Obviously racy.
b) refcount on range_item is completely pointless; there are two call sites of hot_range_item_put() that might drop the final reference *and* they always do so - hot_range_item_lookup() after having lost the race (in which case we are freeing an item that had never been seen by anybody else) and hot_range_tree_free(), which is doing bulk freeing of range_item when an inode_item is being freed.
c) ->m_lock is going to be badly contended from time to time (== when hot_update_worker() is doing list_sort()). Moreover, the same spinlock will see one hell of cacheline bouncing...
How much overhead does that thing cause on reasonable loads on large SMP setups? Is that supposed to be possible to enable on production boxen?