linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: 段熊春 <duanxiongchun@bytedance.com>
To: Michal Hocko <mhocko@kernel.org>
Cc: dong <bauers@126.com>, Vladimir Davydov <vdavydov.dev@gmail.com>,
	Johannes Weiner <hannes@cmpxchg.org>,
	bugzilla-daemon@bugzilla.kernel.org, linux-mm@kvack.org,
	Andrew Morton <akpm@linux-foundation.org>
Subject: Re: [Bug 201699] New: kmemleak in memcg_create_kmem_cache
Date: Fri, 23 Nov 2018 14:54:35 +0800	[thread overview]
Message-ID: <9D46FD61-1B9D-472F-AC6E-17C5780C2606@bytedance.com> (raw)
In-Reply-To: <20181122073420.GB18011@dhcp22.suse.cz>

[-- Attachment #1: Type: text/plain, Size: 11072 bytes --]

I had double check on the newest version 4.20-rc3

I had wrote a small test .


Test service code 

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
	struct stat buf;
	int fd ;
	fd = open("/var/log/test",O_RDWR|O_CREAT|O_APPEND|O_CLOEXEC,0644);
	sleep(1);
	fd = open("/var/log/test.1", O_RDWR|O_CREAT|O_APPEND|O_CLOEXEC|O_SYNC, 0644);
	char log[4096] = {'a'};
	if (fd > 0) {
		write(fd, log, 4096);
		close(fd);
	}

	return 1;
}


Test.service 

[Service]
ExecStart=/usr/bin/test
Restart=always
RestartSec=100ms
MemoryLimit=1G
StartLimitInterval=0
[Install]
WantedBy=default.target

Probe code 

Get test.1 node address kretprobe  code 

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>

static struct kretprobe kprobe_ret_object = {
    .kp.symbol_name    = "d_lookup",
};

static int handler_d_lookup_pre(struct kretprobe_instance *p, struct pt_regs *regs)
{
	int *tmp;
	struct qstr * name =(struct qstr *)regs->si;
	tmp=(int *)p->data;
	*tmp=0;
	if(strcmp("test.1",name->name)==0)
		*tmp=1;
	return 0;
}

static int ret_handler_d_lookup_pre(struct kretprobe_instance *p,struct pt_regs *regs)
{
	int *tmp;
	struct dentry * tmp_dentry = (struct dentry *)regs_return_value(regs);
	tmp = (int *)p->data;
	if(*tmp == 1)
		printk(KERN_INFO "return dentry address %px,inode address %px\n",
			tmp_dentry,tmp_dentry->d_inode);
	return 0;
}
static int __init kprobe_init(void)
{
    int ret;
    kprobe_ret_object.entry_handler = handler_d_lookup_pre;
    kprobe_ret_object.handler = ret_handler_d_lookup_pre;
    kprobe_ret_object.maxactive = 0;
    kprobe_ret_object.data_size = sizeof(int);

    ret = register_kretprobe(&kprobe_ret_object);
    if (ret < 0) {
        printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
        return ret;
    }
    printk(KERN_INFO "Planted kprobe at %p\n", kprobe_ret_object.kp.addr);
    return 0;
}

static void __exit kprobe_exit(void)
{
    unregister_kretprobe(&kprobe_ret_object);
    printk(KERN_INFO "kprobe at %p unregistered\n", kprobe_ret_object.kp.addr);
}

module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL”);

Get unreleased mem_cgroup address

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>

static struct kretprobe css_alloc = {
    .kp.symbol_name    = "mem_cgroup_css_alloc",
};

static struct kprobe css_free = {
    .symbol_name    = "mem_cgroup_css_free",
};
static struct kprobe css_released = {
    .symbol_name    = "mem_cgroup_css_released",
};
static struct kprobe css_offline = {
    .symbol_name    = "mem_cgroup_css_offline",
};
static struct kprobe trycharge = {
    .symbol_name    = "page_counter_try_charge",
};
static struct kprobe charge = {
    .symbol_name    = "page_counter_charge",
};
static struct kprobe uncharge = {
    .symbol_name    = "page_counter_uncharge",
};

atomic_t cssalloc;
atomic_t cssfree;
atomic_t cssreleased;
atomic_t cssoffline;
static spinlock_t my_lock = __SPIN_LOCK_UNLOCKED();
void * css_addr=0;
void * memory_addr=0;

static int handler_trycharge(struct kprobe *p,struct pt_regs *regs)
{
    if (memory_addr == (void *)(regs->di)){
	printk(KERN_INFO"trycharge_memory %px nr %px",(void *)memory_addr,(void *)regs->si);
	spin_lock(&my_lock);
	dump_stack();
	spin_unlock(&my_lock);
    }
    return 0;
}
static int handler_charge(struct kprobe *p,struct pt_regs *regs)
{
    if (memory_addr == (void *)(regs->di)){
	printk(KERN_INFO"charge_memory %px,nr %px",(void *)memory_addr,(void *)regs->si);
	spin_lock(&my_lock);
	dump_stack();
	spin_unlock(&my_lock);
    }
    return 0;
}
static int handler_uncharge(struct kprobe *p,struct pt_regs *regs)
{
    if (memory_addr == (void *)(regs->di)){
	printk(KERN_INFO"uncharge_memory %px,nr %px",(void *)memory_addr,(void *)regs->si);
	spin_lock(&my_lock);
	dump_stack();
	spin_unlock(&my_lock);
    }
    return 0;
}

static int handler_cssalloc_pre(struct kretprobe_instance *p, struct pt_regs *regs)
{
    atomic_inc(&cssalloc);
    return 0;
}

static int ret_handler_cssalloc_pre(struct kretprobe_instance *p,struct pt_regs *regs)
{
	if (css_addr==0){
		css_addr=(void *)regs_return_value(regs);
		memory_addr=(void *)(regs_return_value(regs)+192);
	}
	return 0;
}

static int handler_cssfree_pre(struct kprobe *p,struct pt_regs *regs)
{
   atomic_inc(&cssfree);
    if (css_addr == (void *)(regs->di))
	css_addr = 0;
    return 0;
}
static int handler_cssreleased_pre(struct kprobe *p,struct pt_regs *regs)
{
   atomic_inc(&cssreleased);
    return 0;
}
static int handler_cssoffline_pre(struct kprobe *p,struct pt_regs *regs)
{
   atomic_inc(&cssoffline);
    return 0;
}

static void handler_post(struct kprobe *p, struct pt_regs *regs,
                unsigned long flags)
{
}

static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
{
    return 0;
}

static int myleak_read(struct seq_file *m, void *v)
{
        seq_printf(m,"alloc %d  offline %d release %d free %d trace addr %px\n",atomic_read(&cssalloc),atomic_read(&cssoffline),
		atomic_read(&cssreleased),atomic_read(&cssfree),css_addr);
        return 0;
}

static int myleak_open(struct inode *inode, struct file *file)
{
        return single_open(file, myleak_read, NULL);
}

ssize_t myleak_write(struct file *filp,const char *buf,size_t count,loff_t *offp){
	css_addr = 0;
	return count;
}

static const struct file_operations myleak = {
        .open =myleak_open,
        .read = seq_read,
	.write = myleak_write,
        .llseek = seq_lseek,
        .release = single_release,
};

static int __init kprobe_init(void)
{
    int ret;
    css_alloc.entry_handler = handler_cssalloc_pre;
    css_alloc.handler = ret_handler_cssalloc_pre;
    css_alloc.maxactive = 0;

    css_free.pre_handler = handler_cssfree_pre;
    css_free.post_handler = handler_post;
    css_free.fault_handler = handler_fault;

    css_released.pre_handler = handler_cssreleased_pre;
    css_released.post_handler = handler_post;
    css_released.fault_handler = handler_fault;

    css_offline.pre_handler = handler_cssoffline_pre;
    css_offline.post_handler = handler_post;
    css_offline.fault_handler = handler_fault;

    trycharge.pre_handler = handler_trycharge;
    trycharge.post_handler = handler_post;
    trycharge.fault_handler = handler_fault;

    charge.pre_handler = handler_charge;
    charge.post_handler = handler_post;
    charge.fault_handler = handler_fault;

    uncharge.pre_handler = handler_uncharge;
    uncharge.post_handler = handler_post;
    uncharge.fault_handler = handler_fault;
    atomic_set(&cssalloc,0);
    atomic_set(&cssfree,0);
    atomic_set(&cssreleased,0);
    atomic_set(&cssoffline,0);

    ret = register_kretprobe(&css_alloc);
    if (ret < 0) {
        printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
        return ret;
    }
    ret = register_kprobe(&css_free);
    if (ret < 0) {
        printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
        return ret;
    }
    ret = register_kprobe(&css_released);
    if (ret < 0) {
        printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
        return ret;
    }
    ret = register_kprobe(&css_offline);
    if (ret < 0) {
        printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
        return ret;
    }
    ret = register_kprobe(&trycharge);
    if (ret < 0) {
        printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
        return ret;
    }
    ret = register_kprobe(&charge);
    if (ret < 0) {
        printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
        return ret;
    }
    ret = register_kprobe(&uncharge);
    if (ret < 0) {
        printk(KERN_INFO "register_kprobe failed, returned %d\n", ret);
        return ret;
    }
    proc_create("cgroup_leak", 0, NULL, &myleak);
    printk(KERN_INFO "Planted kprobe at %p\n", css_alloc.kp.addr);
    printk(KERN_INFO "Planted kprobe at %p\n", css_free.addr);
    printk(KERN_INFO "Planted kprobe at %p\n", css_released.addr);
    printk(KERN_INFO "Planted kprobe at %p\n", css_offline.addr);
    printk(KERN_INFO "Planted kprobe at %p\n", trycharge.addr);
    printk(KERN_INFO "Planted kprobe at %p\n", charge.addr);
    printk(KERN_INFO "Planted kprobe at %p\n", uncharge.addr);
    return 0;
}

static void __exit kprobe_exit(void)
{
    unregister_kretprobe(&css_alloc);
    unregister_kprobe(&css_free);
    unregister_kprobe(&css_released);
    unregister_kprobe(&css_offline);
    unregister_kprobe(&trycharge);
    unregister_kprobe(&charge);
    unregister_kprobe(&uncharge);
    printk(KERN_INFO "kprobe at %p unregistered\n", css_alloc.kp.addr);
    printk(KERN_INFO "kprobe at %p unregistered\n", css_free.addr);
    printk(KERN_INFO "kprobe at %p unregistered\n", css_released.addr);
    printk(KERN_INFO "kprobe at %p unregistered\n", css_offline.addr);
    printk(KERN_INFO "kprobe at %p unregistered\n", trycharge.addr);
    printk(KERN_INFO "kprobe at %p unregistered\n", charge.addr);
    printk(KERN_INFO "kprobe at %p unregistered\n", uncharge.addr);
    remove_proc_entry("cgroup_leak",NULL);
}

module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");




First delete /var/log/test /var/log/test.1

Then run command systemctl start test ,After three second run command systemctl stop test 

Then write a python script open /var/log/test.1
Import time
f=open("/var/log/test.1”)
Time.sleep(1000)

Then in other console echo 3 > /proc/sys/vm/drop_caches

after that we find mem_cgroup object  still unreleased。

if we close the python process,then echo 3 >  /proc/sys/vm/drop_caches。
the mem_cgroup was released。

I think because the inode of test.1 is hold by python process , so drop_caches is no used。

I do not think this is a real bug。 but programer should care about   the memory used。 -:)

Thanks for reply
bytedance.net
段熊春
duanxiongchun@bytedance.com




> On Nov 22, 2018, at 3:34 PM, Michal Hocko <mhocko@kernel.org> wrote:
> 
> On Thu 22-11-18 10:56:04, 段熊春 wrote:
>> After long time dig, we find their lots of offline but not release memcg object in memory eating lots of memory.
>> Why this memcg not release? Because the inode pagecache use  some page which is charged to those memcg,
> 
> As already explained these objects should be reclaimed under memory
> pressure. If they are not then there is a bug. And Roman has fixed some
> of those recently.
> 
> Which kernel version are you using?
> -- 
> Michal Hocko
> SUSE Labs


[-- Attachment #2: Type: text/html, Size: 24593 bytes --]

  parent reply	other threads:[~2018-11-23  6:54 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <bug-201699-27@https.bugzilla.kernel.org/>
2018-11-15 21:06 ` Andrew Morton
2018-11-16  2:23   ` dong
2018-11-16  3:04     ` dong
2018-11-16  3:37       ` dong
2018-11-16 17:50   ` Vladimir Davydov
2018-11-18  0:44     ` dong
2018-11-19  8:30       ` Vladimir Davydov
2018-11-19 10:24         ` Michal Hocko
2018-11-19 11:56         ` dong
2018-11-21  8:46           ` dong
2018-11-21  8:56             ` Vladimir Davydov
2018-11-21  9:06               ` dong
2018-11-21  9:10             ` Michal Hocko
2018-11-21  9:22               ` dong
2018-11-21  9:36                 ` 段熊春
2018-11-21 16:27                   ` Michal Hocko
2018-11-22  2:19                     ` 段熊春
2018-11-22  7:32                       ` Michal Hocko
2018-11-22  2:56                     ` 段熊春
2018-11-22  7:34                       ` Michal Hocko
2018-11-22  8:21                         ` 段熊春
2018-11-23  6:54                         ` 段熊春 [this message]
2018-11-21  8:52           ` Re: " Vladimir Davydov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9D46FD61-1B9D-472F-AC6E-17C5780C2606@bytedance.com \
    --to=duanxiongchun@bytedance.com \
    --cc=akpm@linux-foundation.org \
    --cc=bauers@126.com \
    --cc=bugzilla-daemon@bugzilla.kernel.org \
    --cc=hannes@cmpxchg.org \
    --cc=linux-mm@kvack.org \
    --cc=mhocko@kernel.org \
    --cc=vdavydov.dev@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox