From: Alexey Dobriyan "[PATCH] Fix leaks on /proc/{*/sched,sched_debug,timer_list,timer_stats}" and "[PATCH] Fix leak on /proc/lockdep_stats" fixed 5 leaks which happen if one uses single_open() as .open function and seq_release() as .release function. Let's add small amount of runtime checking. Sample output is: memory leak: 'timer_list' WARNING: at fs/seq_file.c:289 seq_release() [] seq_release+0x53/0x68 [] proc_reg_release+0x63/0x74 [] __fput+0x28/0xd3 [] filp_close+0x48/0x4f [] sys_close+0x74/0xbe [] sysenter_past_esp+0x5f/0x85 ======================= Signed-off-by: Alexey Dobriyan Cc: Al Viro Signed-off-by: Andrew Morton --- fs/seq_file.c | 25 ++++++++++++++++++++----- include/linux/seq_file.h | 1 + 2 files changed, 21 insertions(+), 5 deletions(-) diff -puN fs/seq_file.c~single_open-seq_release-leak-diagnostics fs/seq_file.c --- a/fs/seq_file.c~single_open-seq_release-leak-diagnostics +++ a/fs/seq_file.c @@ -281,6 +281,13 @@ EXPORT_SYMBOL(seq_lseek); int seq_release(struct inode *inode, struct file *file) { struct seq_file *m = (struct seq_file *)file->private_data; + + if (m->seq_ops_allocated) { + struct dentry *dentry = file->f_dentry; + printk("memory leak: '%.*s'\n", + dentry->d_name.len, dentry->d_name.name); + WARN_ON(1); + } kfree(m->buf); kfree(m); return 0; @@ -399,9 +406,12 @@ int single_open(struct file *file, int ( op->stop = single_stop; op->show = show; res = seq_open(file, op); - if (!res) - ((struct seq_file *)file->private_data)->private = data; - else + if (!res) { + struct seq_file *seq = file->private_data; + + seq->private = data; + seq->seq_ops_allocated = 1; + } else kfree(op); } return res; @@ -410,8 +420,13 @@ EXPORT_SYMBOL(single_open); int single_release(struct inode *inode, struct file *file) { - const struct seq_operations *op = ((struct seq_file *)file->private_data)->op; - int res = seq_release(inode, file); + struct seq_file *seq = file->private_data; + const struct seq_operations *op = seq->op; + int res; + + /* All roads lead to seq_release(), so... */ + seq->seq_ops_allocated = 0; + res = seq_release(inode, file); kfree(op); return res; } diff -puN include/linux/seq_file.h~single_open-seq_release-leak-diagnostics include/linux/seq_file.h --- a/include/linux/seq_file.h~single_open-seq_release-leak-diagnostics +++ a/include/linux/seq_file.h @@ -21,6 +21,7 @@ struct seq_file { struct mutex lock; const struct seq_operations *op; void *private; + unsigned int seq_ops_allocated:1; }; struct seq_operations { _