Drop cache类型(/proc/sys/vm/drop_cache):

  1. 只释放page cache的可回收部分

    static void drop_pagecache_sb(struct super_block *sb, void *unused)
    {
    	struct inode *inode, *toput_inode = NULL;
    	// 一个super_block,就是一个文件系统的实例,管理了这个文件系统下的所有inode
    	spin_lock(&sb->s_inode_list_lock);
    	// 遍历这个文件系统下的所有inode
    	list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
    		spin_lock(&inode->i_lock);
    		/*
    		 * We must skip inodes in unusual state. We may also skip
    		 * inodes without pages but we deliberately won't in case
    		 * we need to reschedule to avoid softlockups.
    		 */
    		// 过滤掉无效的inode(正在释放、新创建的、没有mapping的)
    		if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
    		    (mapping_empty(inode->i_mapping) && !need_resched())) {
    			spin_unlock(&inode->i_lock);
    			continue;
    		}
    		// 增加inode引用计数
    		__iget(inode);
    		spin_unlock(&inode->i_lock);
    		spin_unlock(&sb->s_inode_list_lock);
    		// invalidate_mapping_pages 
    		// Invalidate all clean, unlocked cache of one inode
    		invalidate_mapping_pages(inode->i_mapping, 0, -1);
    		iput(toput_inode);
    		toput_inode = inode;
    
    		cond_resched();
    		spin_lock(&sb->s_inode_list_lock);
    	}
    	spin_unlock(&sb->s_inode_list_lock);
    	iput(toput_inode);
    }
    
  2. 只释放slab cache中的可回收部分 kmem_cache_create创建的,并指定了SLAB_RECLAIM_ACCOUNT标志,主要是dentry cache和inode cache都属于这个部分

    inode_cachep = kmem_cache_create("inode_cache",
    					 sizeof(struct inode),
    					 0,
    					 (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
    					 SLAB_MEM_SPREAD|SLAB_ACCOUNT),
    					 init_once);
    

    /proc/sys/fs/dentry-state/proc/sys/fs/inode-state查看inode、dentry两者的cache状态

    void drop_slab(void)
    {
    	int nid;
    
    	for_each_online_node(nid)
    		drop_slab_node(nid);
    }
    

    /proc/sys/vm/vfs_cache_pressure 调节slab cache的回收倾向

    shrinker -> count_objects (super_cache_count)
    total_objects += list_lru_shrink_count(&sb->s_dentry_lru, sc);
    total_objects += list_lru_shrink_count(&sb->s_inode_lru, sc);
    total_objects = vfs_pressure_ratio(total_objects);
    
  3. 同时释放page cache和reclaimable slab cache

完整的实现如下:

int drop_caches_sysctl_handler(struct ctl_table *table, int write,
		void *buffer, size_t *length, loff_t *ppos)
{
	int ret;

	ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
	if (ret)
		return ret;
	if (write) {
		static int stfu;

		if (sysctl_drop_caches & 1) {
			iterate_supers(drop_pagecache_sb, NULL);
			count_vm_event(DROP_PAGECACHE);
		}
		if (sysctl_drop_caches & 2) {
			drop_slab();
			count_vm_event(DROP_SLAB);
		}
		if (!stfu) {
			pr_info("%s (%d): drop_caches: %d\\n",
				current->comm, task_pid_nr(current),
				sysctl_drop_caches);
		}
		stfu |= sysctl_drop_caches & 4;
	}
	return 0;
}

Reference

https://zhuanlan.zhihu.com/p/93962657