@@ -678,6 +678,61 @@ err:
kmem_cache_destroy(hot_inode_item_cachep);
}
+static int hot_track_prune_map(struct hot_map_head *map_head,
+ bool type, int nr)
+{
+ struct hot_comm_item *node;
+ int i;
+
+ for (i = 0; i < HEAT_MAP_SIZE; i++) {
+ while (!list_empty(&(map_head + i)->node_list)) {
+ if (nr-- <= 0)
+ break;
+
+ node = list_first_entry(&(map_head + i)->node_list,
+ struct hot_comm_item, n_list);
+ if (type) {
+ struct hot_inode_item *hot_inode =
+ container_of(node,
+ struct hot_inode_item, hot_inode);
+ hot_inode_item_put(hot_inode);
+ } else {
+ struct hot_range_item *hot_range =
+ container_of(node,
+ struct hot_range_item, hot_range);
+ hot_range_item_put(hot_range);
+ }
+ }
+ }
+
+ return nr;
+}
+
+/* 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);
+ int ret;
+
+ if (sc->nr_to_scan == 0)
+ return root->hot_map_nr;
+
+ if (!(sc->gfp_mask & __GFP_FS))
+ return -1;
+
+ ret = hot_track_prune_map(root->heat_range_map,
+ false, sc->nr_to_scan);
+ if (ret > 0)
+ ret = hot_track_prune_map(root->heat_inode_map,
+ true, ret);
+ if (ret > 0)
+ root->hot_map_nr -= (sc->nr_to_scan - ret);
+
+ return root->hot_map_nr;
+}
+
/*
* Main function to update access frequency from read/writepage(s) hooks
*/
@@ -758,6 +813,11 @@ int hot_track_init(struct super_block *sb)
queue_delayed_work(root->update_wq, &root->update_work,
msecs_to_jiffies(HEAT_UPDATE_DELAY * 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);
+
printk(KERN_INFO "VFS: Turning on hot data tracking\n");
return 0;
@@ -774,6 +834,7 @@ void hot_track_exit(struct super_block *sb)
{
struct hot_info *root = sb->s_hot_root;
+ unregister_shrinker(&root->hot_shrink);
cancel_delayed_work_sync(&root->update_work);
destroy_workqueue(root->update_wq);
hot_map_array_exit(root);
@@ -85,6 +85,7 @@ struct hot_info {
struct workqueue_struct *update_wq;
struct delayed_work update_work;
+ struct shrinker hot_shrink;
};
void __init hot_cache_init(void);