[S390] Fix memory leak in /proc/cio_ignore
There is a memory leak in /proc/cio_ignore. The iterator is allocated in cio_ignore_proc_seq_start, but never freed in cio_ignore_proc_seq_stop, because we cannot use the iterator that was passed by seqfile. The seqfile interface passes the last seen iterator to the stop function and not the first one. Since our next function will return NULL at the end, the iter passed to cio_ignore_proc_seq_stop is NULL. The original iter has leaked. The solution is to use seq_open_private. Found with kmemleak: unreferenced object 0x1c720580 (size 32): comm "head", pid 973, jiffies 4294958302 hex dump (first 32 bytes): 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<0000000000203154>] kmem_cache_alloc+0x190/0x19c [<00000000003fb462>] cio_ignore_proc_seq_start+0x5e/0x128 [<0000000000231018>] seq_read+0xc8/0x4bc [<0000000000273954>] proc_reg_read+0xa8/0xf4 [<000000000020e3d8>] vfs_read+0xac/0x1a4 [<000000000020e5c6>] SyS_read+0x52/0xa8 [<000000000011836e>] sysc_noemu+0x10/0x16 [<0000004690b7936c>] 0x4690b7936c Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
ec00440786
commit
05d419b11f
|
@ -265,13 +265,11 @@ struct ccwdev_iter {
|
||||||
static void *
|
static void *
|
||||||
cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
|
cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
|
||||||
{
|
{
|
||||||
struct ccwdev_iter *iter;
|
struct ccwdev_iter *iter = s->private;
|
||||||
|
|
||||||
if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
|
if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
|
||||||
return NULL;
|
return NULL;
|
||||||
iter = kzalloc(sizeof(struct ccwdev_iter), GFP_KERNEL);
|
memset(iter, 0, sizeof(*iter));
|
||||||
if (!iter)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
|
iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
|
||||||
iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
|
iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
|
||||||
return iter;
|
return iter;
|
||||||
|
@ -280,8 +278,6 @@ cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
|
||||||
static void
|
static void
|
||||||
cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
|
cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
|
||||||
{
|
{
|
||||||
if (!IS_ERR(it))
|
|
||||||
kfree(it);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
|
@ -378,14 +374,15 @@ static const struct seq_operations cio_ignore_proc_seq_ops = {
|
||||||
static int
|
static int
|
||||||
cio_ignore_proc_open(struct inode *inode, struct file *file)
|
cio_ignore_proc_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
return seq_open(file, &cio_ignore_proc_seq_ops);
|
return seq_open_private(file, &cio_ignore_proc_seq_ops,
|
||||||
|
sizeof(struct ccwdev_iter));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations cio_ignore_proc_fops = {
|
static const struct file_operations cio_ignore_proc_fops = {
|
||||||
.open = cio_ignore_proc_open,
|
.open = cio_ignore_proc_open,
|
||||||
.read = seq_read,
|
.read = seq_read,
|
||||||
.llseek = seq_lseek,
|
.llseek = seq_lseek,
|
||||||
.release = seq_release,
|
.release = seq_release_private,
|
||||||
.write = cio_ignore_write,
|
.write = cio_ignore_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue