lkml.org 
[lkml]   [2003]   [Nov]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patches in this message
/
Date
From
Subject2.6 /proc/interrupts fails on systems with many CPUs
Howdy.

On systems with lots of processors (512 for example), catting /proc/interrupts
fails with a "not enough memory" error.

This was observed in 2.6.0-test8

I tracked this down to this in proc_misc.c:

static int interrupts_open(struct inode *inode, struct file *file)
{
unsigned size = 4096 * (1 + num_online_cpus() / 8);
char *buf = kmalloc(size, GFP_KERNEL);

The kmalloc fails here.

I'm looking for suggestions on how to fix this. I came up with one fix
that seems to work OK for ia64. I have attached it to this message.
I'm looking for advice on what should be proposed for the real fix.

Thanks!

--
Erik Jacobson - Linux System Software - Silicon Graphics - Eagan, Minnesota
===========================================================================
linux/fs/proc/proc_misc.c
===========================================================================

--- /usr/tmp/TmpDir.18901-0/linux/fs/proc/proc_misc.c_1.52 Tue Nov 11 09:55:19 2003
+++ linux/fs/proc/proc_misc.c Tue Nov 11 09:43:32 2003
@@ -445,7 +445,7 @@
/* don't ask for more than the kmalloc() max size, currently 128 KB */
if (size > 128 * 1024)
size = 128 * 1024;
- buf = kmalloc(size, GFP_KERNEL);
+ buf = __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
if (!buf)
return -ENOMEM;

@@ -476,20 +476,21 @@
extern int show_interrupts(struct seq_file *p, void *v);
static int interrupts_open(struct inode *inode, struct file *file)
{
- unsigned size = 4096 * (1 + num_online_cpus() / 8);
- char *buf = kmalloc(size, GFP_KERNEL);
+ unsigned size = 4096 * (1 + num_online_cpus() / 8);
+ char *buf = __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
struct seq_file *m;
int res;

- if (!buf)
+ if (!buf)
return -ENOMEM;
+
res = single_open(file, show_interrupts, NULL);
if (!res) {
m = file->private_data;
m->buf = buf;
m->size = size;
} else
- kfree(buf);
+ vfree(buf);
return res;
}
static struct file_operations proc_interrupts_operations = {
===========================================================================
linux/fs/seq_file.c
===========================================================================
--- /usr/tmp/TmpDir.18901-0/linux/fs/seq_file.c_1.8 Tue Nov 11 09:55:19 2003
+++ linux/fs/seq_file.c Tue Nov 11 09:18:06 2003
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>

#include <asm/uaccess.h>
#include <asm/page.h>
@@ -29,6 +30,7 @@
int seq_open(struct file *file, struct seq_operations *op)
{
struct seq_file *p = kmalloc(sizeof(*p), GFP_KERNEL);
+
if (!p)
return -ENOMEM;
memset(p, 0, sizeof(*p));
@@ -61,7 +63,7 @@
down(&m->sem);
/* grab buffer if we didn't have one */
if (!m->buf) {
- m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
+ m->buf = __vmalloc(m->size = PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
if (!m->buf)
goto Enomem;
}
@@ -94,8 +96,8 @@
if (m->count < m->size)
goto Fill;
m->op->stop(m, p);
- kfree(m->buf);
- m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
+ vfree(m->buf);
+ m->buf = __vmalloc(m->size <<= 1, GFP_KERNEL, PAGE_KERNEL);
if (!m->buf)
goto Enomem;
m->count = 0;
@@ -160,7 +162,7 @@
if (!offset)
return 0;
if (!m->buf) {
- m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
+ m->buf = __vmalloc(m->size = PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL);
if (!m->buf)
return -ENOMEM;
}
@@ -192,8 +194,8 @@

Eoverflow:
m->op->stop(m, p);
- kfree(m->buf);
- m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
+ vfree(m->buf);
+ m->buf = __vmalloc(m->size <<= 1, GFP_KERNEL, PAGE_KERNEL);
return !m->buf ? -ENOMEM : -EAGAIN;
}

@@ -246,7 +248,7 @@
int seq_release(struct inode *inode, struct file *file)
{
struct seq_file *m = (struct seq_file *)file->private_data;
- kfree(m->buf);
+ vfree(m->buf);
kfree(m);
return 0;
}
\
 
 \ /
  Last update: 2005-03-22 13:58    [W:0.057 / U:1.740 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site