patch-pre2.0.13 linux/mm/mmap.c

Next file: linux/mm/vmscan.c
Previous file: linux/kernel/sys.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file pre2.0.12/linux/mm/mmap.c linux/mm/mmap.c
@@ -12,6 +12,8 @@
 #include <linux/mman.h>
 #include <linux/string.h>
 #include <linux/malloc.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -40,6 +42,78 @@
 };
 
 /*
+ * Check that a process has enough memory to allocate a
+ * new virtual mapping.
+ */
+static inline int vm_enough_memory(long pages)
+{
+	/*
+	 * stupid algorithm to decide if we have enough memory: while
+	 * simple, it hopefully works in most obvious cases.. Easy to
+	 * fool it, but this should catch most mistakes.
+	 */
+	long freepages;
+	freepages = buffermem >> PAGE_SHIFT;
+	freepages += page_cache_size;
+	freepages >>= 1;
+	freepages += nr_free_pages;
+	freepages += nr_swap_pages;
+	freepages -= MAP_NR(high_memory) >> 4;
+	return freepages > pages;
+}
+
+asmlinkage unsigned long sys_brk(unsigned long brk)
+{
+	unsigned long rlim;
+	unsigned long newbrk, oldbrk;
+
+	if (brk < current->mm->end_code)
+		return current->mm->brk;
+	newbrk = PAGE_ALIGN(brk);
+	oldbrk = PAGE_ALIGN(current->mm->brk);
+	if (oldbrk == newbrk)
+		return current->mm->brk = brk;
+
+	/*
+	 * Always allow shrinking brk
+	 */
+	if (brk <= current->mm->brk) {
+		current->mm->brk = brk;
+		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 - current->mm->end_code > rlim)
+		return current->mm->brk;
+
+	/*
+	 * Check against existing mmap mappings.
+	 */
+	if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE))
+		return current->mm->brk;
+
+	/*
+	 * Check if we have enough memory..
+	 */
+	if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
+		return current->mm->brk;
+
+	/*
+	 * Ok, looks good - let it rip.
+	 */
+	current->mm->brk = brk;
+	do_mmap(NULL, oldbrk, newbrk-oldbrk,
+		PROT_READ|PROT_WRITE|PROT_EXEC,
+		MAP_FIXED|MAP_PRIVATE, 0);
+	return brk;
+}
+
+/*
  * Combine the mmap "prot" and "flags" argument into one "vm_flags" used
  * internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits
  * into "VM_xxx".
@@ -178,6 +252,14 @@
 	vma->vm_pte = 0;
 
 	do_munmap(addr, len);	/* Clear old maps */
+
+	/* Private writable mapping? Check memory availability.. */
+	if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) {
+		if (!vm_enough_memory(len >> PAGE_SHIFT)) {
+			kfree(vma);
+			return -ENOMEM;
+		}
+	}
 
 	if (file) {
 		int error = file->f_op->mmap(file->f_inode, file, vma);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this