linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Jeff Garzik <jgarzik@mandrakesoft.com>
To: linux-kernel@vger.rutgers.edu
Cc: linux-mm@kvack.org
Subject: PATCH 2.4.0.1.ac10: a KISS memory pressure callback (rev 2)
Date: Wed, 07 Jun 2000 06:25:00 -0400	[thread overview]
Message-ID: <393E22FC.2EDB1124@mandrakesoft.com> (raw)
In-Reply-To: <oupln0hkgag.fsf@pigdrop.muc.suse.de>

[-- Attachment #1: Type: text/plain, Size: 605 bytes --]

Attached is a patch against 2.4.0-test1-ac10 which adds a VM pressure
callback list, and cleans up the notifier chain code in the process. 
Since the callback occurs in do_try_to_free_pages, it is rather low
level, giving other kernel code flexibility when it comes to freeing
memory.  Kernel code wishing to handle memory pressure should call
register_freemem_notifier.  Thanks for the suggestions Andi.  Goodnight
all.  :)

-- 
Jeff Garzik              | Liberty is always dangerous, but
Building 1024            | it is the safest thing we have.
MandrakeSoft, Inc.       |      -- Harry Emerson Fosdick

[-- Attachment #2: vm-pressure-2.4.0.1.ac10.patch --]
[-- Type: text/plain, Size: 11123 bytes --]

diff -ur vanilla/linux-2.4.0-test1-ac10/mm/vmscan.c linux_2_3/mm/vmscan.c
--- vanilla/linux-2.4.0-test1-ac10/mm/vmscan.c	Tue Jun  6 14:44:31 2000
+++ linux_2_3/mm/vmscan.c	Wed Jun  7 06:14:32 2000
@@ -23,6 +23,9 @@
 
 #include <asm/pgalloc.h>
 
+/* list of funcs to call when memory pressure occurs */
+extern struct notifier_block *freemem_notifier_list;
+
 /*
  * The swap-out functions return 1 if they successfully
  * threw something out, and we got a free page. It returns
@@ -428,6 +431,29 @@
 }
 
 /*
+ * The freemem notifier list holds a list of functions
+ * that are to be called when trying to free pages.
+ *
+ * Call them...  We don't use notifier_call_chain
+ * because the return code from a freemem notifier
+ * is treated as a shrink_*_memory-style return value.
+ */
+static int shrink_misc_memory (int priority, unsigned int gfp_mask)
+{
+	int count = 0;
+	struct notifier_block *nb = freemem_notifier_list;
+
+	while (nb) {
+		count += nb->notifier_call(nb,
+			(unsigned long) priority,
+			(void *)(unsigned long) gfp_mask);
+		nb = nb->next;
+	}
+
+	return count;
+}
+
+/*
  * We need to make the locks finer granularity, but right
  * now we need this so that we can do page allocations
  * without holding the kernel lock etc.
@@ -475,6 +501,20 @@
 				ret = 1;
 				if (!--count)
 					goto done;
+			}
+		}
+
+		/*
+		 * Call everybody who registered a mem pressure notifier.
+		 *
+		 * If freemem_notifier_list will usually be non-NULL
+		 * during normal system operation, remove the non-NULL test.
+		 */
+		if (freemem_notifier_list != NULL) {
+			count -= shrink_misc_memory(priority, gfp_mask);
+			if (count <= 0) {
+				ret = 1;
+				goto done;
 			}
 		}
 
diff -ur vanilla/linux-2.4.0-test1-ac10/include/linux/mm.h linux_2_3/include/linux/mm.h
--- vanilla/linux-2.4.0-test1-ac10/include/linux/mm.h	Tue Jun  6 14:44:30 2000
+++ linux_2_3/include/linux/mm.h	Wed Jun  7 06:14:31 2000
@@ -10,6 +10,7 @@
 #include <linux/string.h>
 #include <linux/list.h>
 #include <linux/mmzone.h>
+#include <linux/notifier.h>
 
 extern unsigned long max_mapnr;
 extern unsigned long num_physpages;
@@ -415,6 +416,9 @@
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
 extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char *dst, int len);
 extern int ptrace_writedata(struct task_struct *tsk, char * src, unsigned long dst, int len);
+
+extern int register_freemem_notifier(struct notifier_block *);
+extern int unregister_freemem_notifier(struct notifier_block *);
 
 extern int pgt_cache_water[2];
 extern int check_pgt_cache(void);
diff -ur vanilla/linux-2.4.0-test1-ac10/include/linux/notifier.h linux_2_3/include/linux/notifier.h
--- vanilla/linux-2.4.0-test1-ac10/include/linux/notifier.h	Thu Mar 30 10:03:49 2000
+++ linux_2_3/include/linux/notifier.h	Wed Jun  7 06:14:32 2000
@@ -21,62 +21,15 @@
 
 #ifdef __KERNEL__
 
+extern int notifier_chain_register(struct notifier_block **list, struct notifier_block *n);
+extern int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n);
+extern int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v);
+
 #define NOTIFY_DONE		0x0000		/* Don't care */
 #define NOTIFY_OK		0x0001		/* Suits me */
 #define NOTIFY_STOP_MASK	0x8000		/* Don't call further */
 #define NOTIFY_BAD		(NOTIFY_STOP_MASK|0x0002)	/* Bad/Veto action	*/
 
-extern __inline__ int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
-{
-	while(*list)
-	{
-		if(n->priority > (*list)->priority)
-			break;
-		list= &((*list)->next);
-	}
-	n->next = *list;
-	*list=n;
-	return 0;
-}
-
-/*
- *	Warning to any non GPL module writers out there.. these functions are
- *	GPL'd
- */
- 
-extern __inline__ int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n)
-{
-	while((*nl)!=NULL)
-	{
-		if((*nl)==n)
-		{
-			*nl=n->next;
-			return 0;
-		}
-		nl=&((*nl)->next);
-	}
-	return -ENOENT;
-}
-
-/*
- *	This is one of these things that is generally shorter inline
- */
- 
-extern __inline__ int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
-{
-	int ret=NOTIFY_DONE;
-	struct notifier_block *nb = *n;
-	while(nb)
-	{
-		ret=nb->notifier_call(nb,val,v);
-		if(ret&NOTIFY_STOP_MASK)
-			return ret;
-		nb=nb->next;
-	}
-	return ret;
-}
-
-
 /*
  *	Declared notifiers so far. I can imagine quite a few more chains
  *	over time (eg laptop power reset chains, reboot chain (to clean 
@@ -105,11 +58,5 @@
 #define SYS_HALT	0x0002	/* Notify of system halt */
 #define SYS_POWER_OFF	0x0003	/* Notify of system power off */
 
-/*
- *	Publically visible notifier objects
- */
- 
-extern struct notifier_block *boot_notifier_list;
- 
-#endif
-#endif
+#endif /* __KERNEL__ */
+#endif /* _LINUX_NOTIFIER_H */
diff -ur vanilla/linux-2.4.0-test1-ac10/kernel/Makefile linux_2_3/kernel/Makefile
--- vanilla/linux-2.4.0-test1-ac10/kernel/Makefile	Wed Mar 22 12:39:11 2000
+++ linux_2_3/kernel/Makefile	Wed Jun  7 06:14:32 2000
@@ -8,11 +8,11 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := kernel.o
-O_OBJS    = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \
+O_OBJS    = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
 	    sysctl.o acct.o capability.o ptrace.o timer.o
 
-OX_OBJS  += signal.o
+OX_OBJS  += signal.o sys.o
 
 ifeq ($(CONFIG_UID16),y)
 O_OBJS += uid16.o
diff -ur vanilla/linux-2.4.0-test1-ac10/kernel/ksyms.c linux_2_3/kernel/ksyms.c
--- vanilla/linux-2.4.0-test1-ac10/kernel/ksyms.c	Tue Jun  6 14:44:31 2000
+++ linux_2_3/kernel/ksyms.c	Wed Jun  7 06:14:32 2000
@@ -129,7 +129,6 @@
 
 /* filesystem internal functions */
 EXPORT_SYMBOL(def_blk_fops);
-EXPORT_SYMBOL(in_group_p);
 EXPORT_SYMBOL(update_atime);
 EXPORT_SYMBOL(get_super);
 EXPORT_SYMBOL(get_empty_super);
@@ -446,8 +445,6 @@
 EXPORT_SYMBOL(machine_restart);
 EXPORT_SYMBOL(machine_halt);
 EXPORT_SYMBOL(machine_power_off);
-EXPORT_SYMBOL(register_reboot_notifier);
-EXPORT_SYMBOL(unregister_reboot_notifier);
 EXPORT_SYMBOL(_ctype);
 EXPORT_SYMBOL(secure_tcp_sequence_number);
 EXPORT_SYMBOL(get_random_bytes);
diff -ur vanilla/linux-2.4.0-test1-ac10/kernel/sys.c linux_2_3/kernel/sys.c
--- vanilla/linux-2.4.0-test1-ac10/kernel/sys.c	Tue Jun  6 14:44:31 2000
+++ linux_2_3/kernel/sys.c	Wed Jun  7 06:14:32 2000
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/utsname.h>
 #include <linux/mman.h>
@@ -47,17 +48,160 @@
  */
 
 static struct notifier_block *reboot_notifier_list = NULL;
+struct notifier_block *freemem_notifier_list = NULL;
+static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED;
 
+/**
+ *	notifier_chain_register	- Add notifier to a notifier chain
+ *	@list: Pointer to root list pointer
+ *	@n: New entry in notifier chain
+ *
+ *	Adds a notifier to a notifier chain.
+ *
+ *	Currently always returns zero.
+ */
+ 
+int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
+{
+	spin_lock(&notifier_lock);
+	while(*list)
+	{
+		if(n->priority > (*list)->priority)
+			break;
+		list= &((*list)->next);
+	}
+	n->next = *list;
+	*list=n;
+	spin_unlock(&notifier_lock);
+	return 0;
+}
+
+/**
+ *	notifier_chain_unregister - Remove notifier from a notifier chain
+ *	@nl: Pointer to root list pointer
+ *	@n: New entry in notifier chain
+ *
+ *	Removes a notifier from a notifier chain.
+ *
+ *	Returns zero on success, or %-ENOENT on failure.
+ */
+ 
+int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n)
+{
+	spin_lock(&notifier_lock);
+	while((*nl)!=NULL)
+	{
+		if((*nl)==n)
+		{
+			*nl=n->next;
+			spin_unlock(&notifier_lock);
+			return 0;
+		}
+		nl=&((*nl)->next);
+	}
+	spin_unlock(&notifier_lock);
+	return -ENOENT;
+}
+
+/**
+ *	notifier_call_chain - Call functions in a notifier chain
+ *	@n: Pointer to root pointer of notifier chain
+ *	@val: Value passed unmodified to notifier function
+ *	@v: Pointer passed unmodified to notifier function
+ *
+ *	Calls each function in a notifier chain in turn.
+ *
+ *	If the return value of the notifier can be and'd
+ *	with %NOTIFY_STOP_MASK, then notifier_call_chain
+ *	will return immediately, with the return value of
+ *	the notifier function which halted execution.
+ *	Otherwise, the return value is the return value
+ *	of the last notifier function called.
+ */
+ 
+int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
+{
+	int ret=NOTIFY_DONE;
+	struct notifier_block *nb = *n;
+
+	spin_lock(&notifier_lock);
+	while(nb)
+	{
+		ret=nb->notifier_call(nb,val,v);
+		if(ret&NOTIFY_STOP_MASK)
+		{
+			spin_unlock(&notifier_lock);
+			return ret;
+		}
+		nb=nb->next;
+	}
+	spin_unlock(&notifier_lock);
+	return ret;
+}
+
+/**
+ *	register_reboot_notifier - Register function to be called at reboot time
+ *	@nb: Info about notifier function to be called
+ *
+ *	Registers a function with the list of functions
+ *	to be called at reboot time.
+ *
+ *	Currently always returns zero, as notifier_chain_register
+ *	always returns zero.
+ */
+ 
 int register_reboot_notifier(struct notifier_block * nb)
 {
 	return notifier_chain_register(&reboot_notifier_list, nb);
 }
 
+/**
+ *	unregister_reboot_notifier - Unregister previously registered reboot notifier
+ *	@nb: Hook to be unregistered
+ *
+ *	Unregisters a previously registered reboot
+ *	notifier function.
+ *
+ *	Returns zero on success, or %-ENOENT on failure.
+ */
+ 
 int unregister_reboot_notifier(struct notifier_block * nb)
 {
 	return notifier_chain_unregister(&reboot_notifier_list, nb);
 }
 
+/**
+ *	register_freemem_notifier - Register function to be called at memory pressure time
+ *	@nb: Info about notifier function to be called
+ *
+ *	Registers a function with the list of functions
+ *	to be called whenever the system attempts to
+ *	free some pages, prior to swapping out pages.
+ *
+ *	Currently always returns zero, as notifier_chain_register
+ *	always returns zero.
+ */
+ 
+int register_freemem_notifier(struct notifier_block * nb)
+{
+	return notifier_chain_register(&freemem_notifier_list, nb);
+}
+
+/**
+ *	unregister_freemem_notifier - Unregister previously registered mem pressure notifier
+ *	@nb: Hook to be unregistered
+ *
+ *	Unregisters a previously registered mem pressure
+ *	notifier function.
+ *
+ *	Returns zero on success, or %-ENOENT on failure.
+ */
+ 
+int unregister_freemem_notifier(struct notifier_block * nb)
+{
+	return notifier_chain_unregister(&freemem_notifier_list, nb);
+}
+
 asmlinkage long sys_ni_syscall(void)
 {
 	return -ENOSYS;
@@ -1102,3 +1246,12 @@
 	return error;
 }
 
+EXPORT_SYMBOL(notifier_chain_register);
+EXPORT_SYMBOL(notifier_chain_unregister);
+EXPORT_SYMBOL(notifier_call_chain);
+EXPORT_SYMBOL(register_reboot_notifier);
+EXPORT_SYMBOL(unregister_reboot_notifier);
+EXPORT_SYMBOL(register_freemem_notifier);
+EXPORT_SYMBOL(unregister_freemem_notifier);
+EXPORT_SYMBOL(in_group_p);
+EXPORT_SYMBOL(in_egroup_p);

      parent reply	other threads:[~2000-06-07 10:25 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2000-06-07  7:34 PATCH 2.4.0.1.ac10: a KISS memory pressure callback Jeff Garzik
     [not found] ` <oupln0hkgag.fsf@pigdrop.muc.suse.de>
2000-06-07 10:25   ` Jeff Garzik [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=393E22FC.2EDB1124@mandrakesoft.com \
    --to=jgarzik@mandrakesoft.com \
    --cc=linux-kernel@vger.rutgers.edu \
    --cc=linux-mm@kvack.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox