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 Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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

About Me

A software engineer who loves any technologies that makes life easier. That’s why I love Linux and Mac at the same time.

Newsletter

%d bloggers like this: