[PATCH] Patch to Memory Subsystem ... (Needed?)

Brian Schau (bsc@fleggaard.dk)
Fri, 06 Nov 1998 19:21:37 +0100


This is a multi-part message in MIME format.
--------------4951A3669A1E87ABE7DE010E
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hello,

(This is long ...)

Find attached three files - one a patch to the memory-subsystem, one a
shell-script and one a simple c-program.

Motivation. Today one of my servers had to be 'hard'-rebooted due to
lack of memory. One user-space program ate all available memory -
resulting in a lot of 'Unable to load interpreter' and the like. Even
root couldn't get a login at the console.

Solution. Some way to specify an amount of free pages which is only
accessible by root-processes so that root can get a login and kill the
offending memory-eater ...

Description. The attached patch patches against a clean 2.1.126. It
touches the following files:

mm/mmap.c
include/linux/sysctl.h
kernel/sysctl.c

It adds an entry to /proc/sys/vm/ called rootpages. Reading 'rootpages'
returns the no. of pages reserved exclusively for root (defaults to
0). Writing to 'rootpages' sets the no. of pages to reserve
exclusively for root. A shell script ('rootpages') is attached for
your convenience:

cryo:/home/bsc # /home/bsc/rootpages
Rootpages fixed at 0 pages.
cryo:/home/bsc # /home/bsc/rootpages 1024
Setting new rootpages value to 1024 pages.

Test. To test, compile the third file 'eat.c':

gcc -Wall -o eat eat.c

... it compiles without warnings/errors on my 2.1.117. On tty1, run:

free -mtos 1

On tty2, run 'eat' as a normal user and with /proc/sys/vm/rootpages set
to 0. 'eat' should eat all available memory (it does on my machine).
Watch 'free' on tty1 report loses of memory.
Press ctrl-c on tty2 thus aborting 'eat'. The amount of free memory
should rise.
Now set the no. of freepages to say, 1024 (4 Mb on Intel-platforms) and
run 'eat' again as normal user. Watch the amount of free memory. It
should drop down to ~ 4Mb - not below! You're then able to login as
root and do your stuff ... ;o)
(Running 'eat' as root eats all available memory - so take care!)

Notes. The patch has been developed on a 2.1.117 kernel. It runs with
no errors on a 2.1.117. It patches cleanly against a 2.1.126 kernel -
but I haven't tried it on a 2.1.126 kernel (due to compilation errors in
the sound sub-system). But with my un-trained eye (and some help from
'diff'), it seems like there has been no fundamental changes to the
files touched between .117 and .126 ...
There is no check to see if the number of rootpages exceed some
??strange?? value (like 10000000). So, 'roots' beware!

Conclusion. I don't know if this patch is needed in the kernel at all
(haven't checked to see if somebody have done this already) - but it was
a simple 1 hour hack which, if the facility existed in the kernel I use
at work (2.1.107 - soon to be upgraded ;o), would have saved me from a
hard-reboot, a lot of fsck'ing and loosing lots of precious time better
spent at work (14 people total ...).
I would like, though, that somebody validates the patch - is it safe?

Kind regards,

Brisse
--------------4951A3669A1E87ABE7DE010E
Content-Type: text/plain; charset=us-ascii; name="eat.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="eat.c"

#include <stdlib.h>
#include <stdio.h>

#define CHUNKSIZE 10240
#define STEP 1024

int
main(int argc, char* argv[])
{
char* ptr=NULL;
int cnt=0;
int c;


while (1) {
cnt++;
if ((ptr=(char*)calloc(CHUNKSIZE, 1))) {
for (c=0; c<CHUNKSIZE; c+=STEP) *(ptr+c)=1;
printf("(%06i) Ate %i bytes ...\n", cnt, CHUNKSIZE);
} else printf("(%06i) Couldn't eat %i bytes ...\n", cnt, CHUNKSIZE);
}
exit(0);
}

--------------4951A3669A1E87ABE7DE010E
Content-Type: text/plain; charset=us-ascii; name="rootpages"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="rootpages"

#!/bin/sh
ROOTPAGES=/proc/sys/vm/rootpages
if test "$(whoami)" = "root"; then
if test -f $ROOTPAGES; then
if test $# -gt 0; then
echo "Setting new rootpages value to $1 pages."
echo $1 > $ROOTPAGES
else
rp="$(cat $ROOTPAGES)"
echo "Rootpages fixed at $rp pages."
fi
else
echo "Can't find $ROOTPAGES ..."
fi
else
echo "You must be root to use this program!"
fi
exit 0

--------------4951A3669A1E87ABE7DE010E
Content-Type: text/plain; charset=us-ascii; name="mm.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="mm.diff"

diff -ur linux-2.1.117/include/linux/sysctl.h linux/include/linux/sysctl.h
--- linux-2.1.117/include/linux/sysctl.h Fri Nov 6 16:45:44 1998
+++ linux/include/linux/sysctl.h Fri Nov 6 16:50:59 1998
@@ -99,7 +99,8 @@
VM_BUFFERMEM, /* struct: Set buffer memory thresholds */
VM_PAGECACHE, /* struct: Set cache memory thresholds */
VM_PAGERDAEMON, /* struct: Control kswapd behaviour */
-/*9*/ VM_PGT_CACHE /* struct: Set page table cache parameters */
+/*9*/ VM_PGT_CACHE, /* struct: Set page table cache parameters */
+ VM_ROOTPAGES /* int: No. of free pages reserved for UID 0 */
};


diff -ur linux-2.1.117/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-2.1.117/kernel/sysctl.c Fri Nov 6 16:42:17 1998
+++ linux/kernel/sysctl.c Fri Nov 6 16:48:32 1998
@@ -42,6 +42,7 @@
extern int bdf_prm[], bdflush_min[], bdflush_max[];
extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
extern int sysctl_overcommit_memory;
+extern int rootpages;
#ifdef CONFIG_KMOD
extern char modprobe_path[];
#endif
@@ -211,6 +212,8 @@
&pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
{VM_PGT_CACHE, "pagetable_cache",
&pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec},
+ {VM_ROOTPAGES, "rootpages",
+ &rootpages, sizeof(int), 0600, NULL, &proc_dointvec},
{0}
};

diff -ur linux-2.1.117/mm/mmap.c linux/mm/mmap.c
--- linux-2.1.117/mm/mmap.c Fri Nov 6 16:40:49 1998
+++ linux/mm/mmap.c Fri Nov 6 17:21:26 1998
@@ -47,6 +47,7 @@
kmem_cache_t *vm_area_cachep;

int sysctl_overcommit_memory;
+int rootpages=0;

/* Check that a process has enough memory to allocate a
* new virtual mapping.
@@ -58,7 +59,7 @@
* fool it, but this should catch most mistakes.
*/
long free;
-
+
/* Sometimes we want to use more memory than we have. */
if (sysctl_overcommit_memory)
return 1;
@@ -68,6 +69,7 @@
free >>= 1;
free += nr_free_pages;
free += nr_swap_pages;
+ if (current->uid) free -= rootpages;
free -= num_physpages >> 4;
return free > pages;
}

--------------4951A3669A1E87ABE7DE010E--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/