Fix to make RLIMIT_DATA work with mmap and some questions about threads.

Greg Alexander (galexand@sietch.bloomington.in.us)
Fri, 28 Mar 1997 12:47:23 -0500 (EST)


Now, finally, for my very first really on-topic post.
This is a simple patch to make RLIMIT_DATA do something useful
with all allocated memory, including that which is mmap'd. It limits the
amount of data PER USER, not per process as the old one did with brk(). For
my purposes, per process was pretty pointless (we either stop them from
running netscape at all, or we leave ourselves open to them running multiple
netscapes. yucky). I have no idea what POSIX says about this, I'm only
implementing what is useful for me.
The big problem with this patch is that it doesn't allow _any_
overcommiting. If the user has shared memory that will probably never get
faulted to be copy on write, all copies of that shared memory still count
towards the user's RLIMIT_DATA limit. I was going to modify the fault
routines, but it was too complex (would have been too slow anyways, I
expect).
Any comments, whatever, are welcome. This is just my hack, so I
don't expect it to make it into the kernel.

Now for my threading question. Kernel threads are not pre-emptively
multi-tasked, correct? Is there a plan for them to become pre-emptive by
2.2.0? I'm asking because I am using an ext2 compression patch (to enable
chattr +c), but when it is under heavy usage, it will stay in kernel-mode
for full seconds at a time on my 486/100. Could I make the compression be a
kerneld-like (though I don't think kerneld's pipe is made for speed, is it?)
daemon to handle this in userspace? Or would there be any way to start a
pre-emptively task-switched, user-mode process from the kernel (better than
having it start up in my /etc/rc.d scripts so that I can read, say a
compressed init or whatever)?

On with my patch:
--- linux/mm/mmap.c.orig Fri Mar 28 03:15:00 1997
+++ linux/mm/mmap.c Fri Mar 28 05:28:32 1997
@@ -64,7 +64,6 @@

asmlinkage unsigned long sys_brk(unsigned long brk)
{
- unsigned long rlim;
unsigned long newbrk, oldbrk;
struct mm_struct *mm = current->mm;

@@ -83,14 +82,6 @@
do_munmap(newbrk, oldbrk-newbrk);
return brk;
}
- /*
- * Check against rlimit and stack..
- */
- rlim = current->rlim[RLIMIT_DATA].rlim_cur;
- if (rlim >= RLIM_INFINITY)
- rlim = ~0;
- if (brk - mm->end_code > rlim)
- return mm->brk;

/*
* Check against existing mmap mappings.
@@ -258,6 +249,23 @@
> current->rlim[RLIMIT_AS].rlim_cur) {
kfree(vma);
return -ENOMEM;
+ }
+
+ /* Check against data size */
+ if ((current->rlim[RLIMIT_DATA].rlim_cur < RLIM_INFINITY) &&
+ (prot & PROT_WRITE) &&
+ (flags & MAP_PRIVATE)) {
+ struct task_struct *p;
+ unsigned long used=len;
+
+ for_each_task(p) {
+ if (p->mm && p->uid==current->uid)
+ used+=(p->mm->total_vm<<PAGE_SHIFT);
+ }
+ if (used > current->rlim[RLIMIT_DATA].rlim_cur) {
+ kfree(vma);
+ return -ENOMEM;
+ }
}

/* Private writable mapping? Check memory availability.. */
-----------------------------------------------------------------------------

Greg Alexander
http://www.cia-g.com/~sietch/
----
Anyone who cannot cope with mathematics is not fully human. At best he is a
tolerable subhuman who has learned to wear shoes, bathe and not make messes
in the house.
-- Paul Erdos
also -- Lazarus Long, "Time Enough for Love"