Sungju's Slow Life

Personal journal


How to check page caches in the kernel memory.

If you would like to know what files were occupying the page caches which you can see with ‘free’ in command line or ‘kmem -I’ in kernel memory, you can start with ‘/proc/sys/vm/drop_caches’.

int drop_caches_sysctl_handler(ctl_table *table, int write,
    void __user *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;
}


/* A global variable is a bit ugly, but it keeps the code simple */
int sysctl_drop_caches;

static void drop_pagecache_sb(struct super_block *sb, void *unused)
{
    struct inode *inode, *toput_inode = NULL;

    spin_lock(&sb->s_inode_list_lock);
    list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
        spin_lock(&inode->i_lock);
        if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) ||
            (inode->i_mapping->nrpages == 0)) {
            spin_unlock(&inode->i_lock);
            continue;
        }
        __iget(inode);
        spin_unlock(&inode->i_lock);
        spin_unlock(&sb->s_inode_list_lock);

        invalidate_mapping_pages(inode->i_mapping, 0, -1);
        iput(toput_inode);
        toput_inode = inode;

        spin_lock(&sb->s_inode_list_lock);
    }
    spin_unlock(&sb->s_inode_list_lock);
    iput(toput_inode);
}


/**
 *  iterate_supers - call function for all active superblocks
 *  @f: function to call
 *  @arg: argument to pass to it
 *
 *  Scans the superblock list and calls given function, passing it
 *  locked superblock and given argument.
 */
void iterate_supers(void (*f)(struct super_block *, void *), void *arg)
{
    struct super_block *sb, *p = NULL;

    spin_lock(&sb_lock);
    list_for_each_entry(sb, &super_blocks, s_list) {
        if (hlist_unhashed(&sb->s_instances))
            continue;
        sb->s_count++;
        spin_unlock(&sb_lock);

        down_read(&sb->s_umount);
        if (sb->s_root && (sb->s_flags & MS_BORN))
            f(sb, arg);
        up_read(&sb->s_umount);

        spin_lock(&sb_lock);
        if (p)
            __put_super(p);
        p = sb;
    }
    if (p)
        __put_super(p);
    spin_unlock(&sb_lock);
}

I wrote a script that is extracting the page caches from the vmcore based on the above information. You can find the code in this link: https://github.com/sungju/pycrashext/commit/4d5c84daa83874ceb270abba6ddfdfa12b800102



Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.