[Codefragments-commits] bryce commits r5 - in trunk: . bufferheads fragment-slab

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Mon Nov 14 11:13:06 CST 2005


Author: bryce
Date: 2005-11-14 11:13:03 -0600 (Mon, 14 Nov 2005)
New Revision: 5

Added:
   trunk/bufferheads/
   trunk/bufferheads/Makefile
   trunk/bufferheads/README
   trunk/bufferheads/buffer.c
   trunk/fragment-slab/
   trunk/fragment-slab/Makefile
   trunk/fragment-slab/README
   trunk/fragment-slab/fragment.c
Log:
Initial

Added: trunk/bufferheads/Makefile
===================================================================
--- trunk/bufferheads/Makefile	2004-04-15 23:14:10 UTC (rev 4)
+++ trunk/bufferheads/Makefile	2005-11-14 17:13:03 UTC (rev 5)
@@ -0,0 +1,11 @@
+obj-m := buffer.o
+
+KERNEL=`uname -r`-i686
+
+all:
+	V=1 make -C /usr/src/kernels/$(KERNEL) SUBDIRS=$(PWD) modules
+
+clean:
+	V=1 make -C /usr/src/kernels/$(KERNEL) SUBDIRS=$(PWD) clean
+
+

Added: trunk/bufferheads/README
===================================================================
--- trunk/bufferheads/README	2004-04-15 23:14:10 UTC (rev 4)
+++ trunk/bufferheads/README	2005-11-14 17:13:03 UTC (rev 5)
@@ -0,0 +1,44 @@
+This is a test module that makes successive calls to alloc_buffer_head()
+in an attempt to starve the system of bufferheads
+
+Generally this simply results in a memory starvation issue.
+
+You can dynamically change the number of buffers used on the fly
+by echoing a number into /proc/test
+
+eg
+[root at emerald ~]# echo "1024" > /proc/test
+[root at emerald ~]# echo "2048" > /proc/test
+[root at emerald ~]# echo "1024" > /proc/test
+
+which will yield the following dmesg output
+buffer: Kernel test module loaded
+buffer: Settings
+buffer: --------
+buffer: Buffer_heads assigned: 0
+buffer: ---
+buffer: There are currently 0 elements in list
+buffer: Recieved request to make the list 1024 elements long
+buffer: list is now composed of 1024 elements
+buffer: ---
+buffer: There are currently 1024 elements in list
+buffer: Recieved request to make the list 2048 elements long
+buffer: list is now composed of 2048 elements
+buffer: ---
+buffer: There are currently 2048 elements in list
+buffer: Recieved request to make the list 1024 elements long
+buffer: list is now composed of 1024 elements
+
+The module will clean up and remove all the memory allocated after
+unloading
+
+[root at emerald ~]# rmmod buffer
+buffer: /proc file removed
+buffer: freed up 1024 list elements
+
+
+If you request more buffer elements than there is memory to allocate, the
+module will allocate what it can then tell you via a kernel message how
+many elements it was able to create. (typically, use dmesg to view the
+kernel message log)
+

Added: trunk/bufferheads/buffer.c
===================================================================
--- trunk/bufferheads/buffer.c	2004-04-15 23:14:10 UTC (rev 4)
+++ trunk/bufferheads/buffer.c	2005-11-14 17:13:03 UTC (rev 5)
@@ -0,0 +1,324 @@
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <asm/uaccess.h>
+#include <linux/list.h>
+
+// This is where we get alloc_buffer_head from
+#include <linux/buffer_head.h>
+
+
+#define MODULE_NAME   "buffer"
+#define DRIVER_AUTHOR "Philip Copeland <Philip.Copeland at oracle.com>"
+#define DRIVER_DESC   "Generic frame for a module"
+
+
+#define PROC_FNAME	"test"
+#define PROCFS_MAX_SIZE 1024
+
+
+// This structure hold information about the /proc file */
+struct proc_dir_entry *module_procfile;
+
+
+// procfs buf stuff
+static char procfs_buffer[PROCFS_MAX_SIZE] = "";
+static unsigned long procfs_buffer_size = 0;
+
+
+// externally presented variables
+int debug = 0;			// output debug messages (1 on 0 off)
+int buffers = 0;		// allocate X bufferheads
+
+
+// structure thats going to be burried in linked list hell
+typedef struct node *node_p;
+
+struct node
+{
+  int idx;			// node number
+  struct buffer_head *new_bh;	// some memory allocated by alloc_buffer_head
+  struct list_head list;	// kernel's list structure
+} node;
+
+struct list_head *pos, *q;
+
+
+// Prototypes for some functions 
+int allocation (int requested);
+static int kernel_atoi (const char *name);
+
+
+/* module_param(foo, int, 0000)
+   The first param is the parameters name
+   The second param is it's data type
+   The final argument is the permissions bits, 
+   for exposing parameters in sysfs (if non-zero) at a later stage.
+*/
+module_param (buffers, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC (buffers, " Allocate X amount of buffer_heads.\n"
+		  "\t\tIf an impossibly large number is passed, the module\n"
+		  "\t\twill allocate as much as it can before bailing out\n"
+		  "\t\tat which point it will tell you how many elements it\n"
+		  "\t\twas able to assign in the dmesg output\n"
+		  "\t\tNote: you can change this on the fly as follows\n"
+		  "\t\techo \"1024\" > /proc/test");
+
+module_param (debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC (debug,
+		  " Show debug info as module code executes (0 off, 1 on)");
+
+
+/* /proc file ------------------------------------ */
+
+int
+procfile_read (char *buffer,
+	       char **buffer_location,
+	       off_t offset, int buffer_length, int *eof, void *data)
+{
+  int ret;
+
+  if (debug)
+    printk ("%s: procfile_read (/proc/%s) called\n", MODULE_NAME, PROC_FNAME);
+
+  if (offset > 0)
+    {
+      // we have finished to read, return 0
+      ret = 0;
+    }
+  else
+    {
+      // fill the buffer, return the buffer size
+      ret = sprintf (buffer, procfs_buffer);
+    }
+
+  return ret;
+}
+
+
+int
+procfile_write (struct file *file, const char *buffer, unsigned long count,
+		void *data)
+{
+  int value = 0;
+  /* get buffer size */
+  procfs_buffer_size = count;
+  if (procfs_buffer_size > PROCFS_MAX_SIZE)
+    {
+      procfs_buffer_size = PROCFS_MAX_SIZE;
+    }
+
+  // write data to the buffer
+  if (copy_from_user (procfs_buffer, buffer, procfs_buffer_size))
+    {
+      return -EFAULT;
+    }
+
+  if (debug)
+    printk ("%s: procfile_write(/proc/%s) called\n", MODULE_NAME, PROC_FNAME);
+
+
+  value = kernel_atoi (buffer);
+  allocation (value);
+
+  return procfs_buffer_size;
+}
+
+
+/* atoi in kernel space -------------------------- */
+
+
+static int
+kernel_atoi (const char *name)
+{
+  int val = 0;
+
+  for (;; name++)
+    {
+      switch (*name)
+	{
+	case '0'...'9':
+	  val = 10 * val + (*name - '0');
+	  break;
+	default:
+	  return val;
+	}
+    }
+}
+
+
+/* Allocate buffer_head stuff -------------------- */
+
+
+int
+allocation (int requested)
+{
+  // Note: we don't care about taking note of tracking the nodes
+  // all we care about is that alloc_buffer_head() is called and stored
+
+  int x = 0;
+  int loop = 0;
+  int diff = 0;
+  struct node *tmp = NULL;
+
+  // how many items are there in the list?
+  list_for_each (pos, &node.list) loop++;
+
+  printk ("%s: ---\n", MODULE_NAME);
+  printk ("%s: There are currently %d elements in list\n", MODULE_NAME, loop);
+  printk ("%s: Recieved request to make the list %d elements long\n",
+	  MODULE_NAME, requested);
+
+  if (debug)
+    printk ("%s: diff = %d\n", MODULE_NAME, requested - loop);
+
+  // do we need to add more records?
+  if (loop < requested)
+    {
+      // how many more do we need?
+      diff = (requested - loop);
+      for (x = 0; x < diff; x++)
+	{
+	  // malloc some space for the struct
+	  // to prevent this from invoking the oom killer we add two
+	  // __GPF flags,  NORETRY and NORECLAIM
+	  // add | GFP_NOWARN if you dont like the memory stats dump when
+	  // kmalloc fails
+	  tmp =
+	    (struct node *) kmalloc (sizeof (struct node),
+				     GFP_KERNEL | __GFP_NORETRY |
+				     __GFP_NORECLAIM);
+	  if (tmp == NULL)
+	    {
+	      printk
+		("%s: WHOA! kmalloc failed. no memory left?"
+		 " bailing out having only created %d elements\n",
+		 MODULE_NAME, (loop + x));
+	      return (loop + x);	// abandon routine
+	    }
+
+	  // track what number this node is
+	  // (not really needed except for debugging purposes)
+	  tmp->idx = loop + x;
+
+	  // Finally we get to do the one line of code we actually
+	  // truely care about...
+	  tmp->new_bh = alloc_buffer_head (GFP_NOFS | __GFP_NOFAIL);
+
+	  if ((tmp->new_bh) == NULL)
+	    {
+	      printk
+		("%s: WHOA! kmalloc failed. no memory left?"
+		 " bailing out having only created %d elements\n",
+		 MODULE_NAME, (loop + x));
+	      return (loop + x);	// abandon routine
+	    }
+
+	  // add to the end of the list
+	  list_add_tail (&(tmp->list), &(node.list));
+	}
+      if (debug)
+	printk ("%s: created %d new elements in list\n", MODULE_NAME, x);
+    }
+
+  // do we need to delete records?
+  if (loop > requested)
+    {
+      diff = (loop - requested);
+      list_for_each_safe (pos, q, &node.list)
+      {
+	tmp = list_entry (pos, struct node, list);
+	list_del (pos);
+	kfree (tmp->new_bh);
+	kfree (tmp);
+	diff--;
+	if (diff == 0)
+	  break;		// jump out of this list_for_each() macro loop
+      }
+      if (debug)
+	printk ("%s: destroyed %d elements in list\n", MODULE_NAME, x);
+    }
+  printk ("%s: list is now composed of %d elements\n", MODULE_NAME,
+	  requested);
+  return (diff);
+}
+
+
+/* Entry and Exit -------------------------------- */
+
+
+static int __init
+test_init (void)
+{
+  printk (KERN_ALERT "%s: Kernel test module loaded\n", MODULE_NAME);
+  printk (KERN_ALERT "%s: Settings\n", MODULE_NAME);
+  printk (KERN_ALERT "%s: --------\n", MODULE_NAME);
+  printk (KERN_ALERT "%s: Buffer_heads assigned: %d\n", MODULE_NAME, buffers);
+
+
+  // Create a start record
+  INIT_LIST_HEAD (&node.list);
+
+  /* Create /proc/test */
+  module_procfile = create_proc_entry (PROC_FNAME, 0644, NULL);
+
+  if (module_procfile == NULL)
+    {
+      remove_proc_entry (PROC_FNAME, &proc_root);
+      printk (KERN_ALERT "Error: Could not initialize /proc/%s\n",
+	      PROC_FNAME);
+      return -ENOMEM;
+    }
+
+  module_procfile->read_proc = procfile_read;
+  module_procfile->write_proc = procfile_write;
+  module_procfile->owner = THIS_MODULE;
+  module_procfile->mode = S_IFREG | S_IRUGO;
+  module_procfile->uid = 0;
+  module_procfile->gid = 0;
+  module_procfile->size = 37;
+
+  if (debug)
+    printk (KERN_INFO "/proc/%s created\n", PROC_FNAME);
+
+  return 0;
+}
+
+
+static void __exit
+test_exit (void)
+{
+  struct node *tmp;
+  int loop = 0;
+  // Clean up /proc
+  remove_proc_entry (PROC_FNAME, NULL);
+
+  // Clear out the list
+
+  list_for_each_safe (pos, q, &node.list)
+  {
+    tmp = list_entry (pos, struct node, list);
+    list_del (pos);
+    kfree(tmp->new_bh);
+    kfree (tmp);
+    loop++;
+  }
+  printk ("%s: /proc file removed\n", MODULE_NAME);
+  printk ("%s: freed up %d list elements\n", MODULE_NAME, loop);
+}
+
+
+module_init (test_init);
+module_exit (test_exit);
+
+
+MODULE_LICENSE ("GPL");		// Get rid of taint message by declaring code as GPL.
+MODULE_AUTHOR (DRIVER_AUTHOR);	// Who wrote this module?
+MODULE_DESCRIPTION (DRIVER_DESC);	// What does this module do?

Added: trunk/fragment-slab/Makefile
===================================================================
--- trunk/fragment-slab/Makefile	2004-04-15 23:14:10 UTC (rev 4)
+++ trunk/fragment-slab/Makefile	2005-11-14 17:13:03 UTC (rev 5)
@@ -0,0 +1,11 @@
+obj-m := fragment.o
+
+KERNEL=`uname -r`-i686
+
+all:
+	V=1 make -C /usr/src/kernels/$(KERNEL) SUBDIRS=$(PWD) modules
+
+clean:
+	V=1 make -C /usr/src/kernels/$(KERNEL) SUBDIRS=$(PWD) clean
+
+

Added: trunk/fragment-slab/README
===================================================================
--- trunk/fragment-slab/README	2004-04-15 23:14:10 UTC (rev 4)
+++ trunk/fragment-slab/README	2005-11-14 17:13:03 UTC (rev 5)
@@ -0,0 +1,14 @@
+This modeule is used to fragment the slab as much as possible
+
+insmod fragment.ko (debug=1 for noisy debug)
+
+echo 8192 > /proc/test
+
+wait a minute (there will be what seems like a hang for a moment)
+then 
+
+cat /proc/slabinfo  | grep -v DMA | grep size
+
+Phil
+=--=
+

Added: trunk/fragment-slab/fragment.c
===================================================================
--- trunk/fragment-slab/fragment.c	2004-04-15 23:14:10 UTC (rev 4)
+++ trunk/fragment-slab/fragment.c	2005-11-14 17:13:03 UTC (rev 5)
@@ -0,0 +1,415 @@
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <asm/uaccess.h>
+#include <linux/list.h>
+
+// This is where we get alloc_buffer_head from
+#include <linux/buffer_head.h>
+
+
+#define MODULE_NAME   "fragment"
+#define DRIVER_AUTHOR "Philip Copeland <Philip.Copeland at oracle.com>"
+#define DRIVER_DESC   "Generic frame for a module"
+
+
+#define PROC_FNAME	"test"
+#define PROCFS_MAX_SIZE 1024
+
+
+// This structure hold information about the /proc file */
+struct proc_dir_entry *module_procfile;
+
+
+// procfs buf stuff
+static char procfs_buffer[PROCFS_MAX_SIZE] = "";
+static unsigned long procfs_buffer_size = 0;
+
+
+// externally presented variables
+int debug = 0;			// output debug messages (1 on 0 off)
+int buffers = 0;		// allocate X bufferheads
+
+
+// structure thats going to be burried in linked list hell
+typedef struct node *node_p;
+
+struct node
+{
+  int idx;			// node number
+  int chunksize;		// node represents X amount of memory
+  long location;		// mem address
+  char *page;			// a memory chunk
+  struct list_head list;	// kernel's list structure
+} node;
+
+struct list_head *pos, *q;
+
+
+// Prototypes for some functions 
+int allocation (int requested);
+static int kernel_atoi (const char *name);
+char *malloc_slab_slice (int chunk, int *chunksize);
+
+
+/* module_param(foo, int, 0000)
+   The first param is the parameters name
+   The second param is it's data type
+   The final argument is the permissions bits, 
+   for exposing parameters in sysfs (if non-zero) at a later stage.
+*/
+module_param (buffers, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC (buffers, " Allocate X amount of memory buffers.\n"
+		  "\t\tIf an impossibly large number is passed, the module\n"
+		  "\t\twill allocate as much as it can before bailing out\n"
+		  "\t\tat which point it will tell you how many elements it\n"
+		  "\t\twas able to assign in the dmesg output\n"
+		  "\t\tNote: you can change this on the fly as follows\n"
+		  "\t\techo \"1024\" > /proc/test");
+
+module_param (debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC (debug,
+		  " Show debug info as module code executes (0 off, 1 on)");
+
+
+/* /proc file ------------------------------------ */
+
+int
+procfile_read (char *buffer,
+	       char **buffer_location,
+	       off_t offset, int buffer_length, int *eof, void *data)
+{
+  int ret;
+
+  if (debug)
+    printk ("%s: procfile_read (/proc/%s) called\n", MODULE_NAME, PROC_FNAME);
+
+  if (offset > 0)
+    {
+      // we have finished to read, return 0
+      ret = 0;
+    }
+  else
+    {
+      // fill the buffer, return the buffer size
+      ret = sprintf (buffer, procfs_buffer);
+    }
+
+  return ret;
+}
+
+
+int
+procfile_write (struct file *file, const char *buffer, unsigned long count,
+		void *data)
+{
+  int value = 0;
+  /* get buffer size */
+  procfs_buffer_size = count;
+  if (procfs_buffer_size > PROCFS_MAX_SIZE)
+    {
+      procfs_buffer_size = PROCFS_MAX_SIZE;
+    }
+
+  // write data to the buffer
+  if (copy_from_user (procfs_buffer, buffer, procfs_buffer_size))
+    {
+      return -EFAULT;
+    }
+
+  if (debug)
+    printk ("%s: procfile_write(/proc/%s) called\n", MODULE_NAME, PROC_FNAME);
+
+
+  value = kernel_atoi (buffer);
+  allocation (value);
+
+  return procfs_buffer_size;
+}
+
+
+/* atoi in kernel space -------------------------- */
+
+
+static int
+kernel_atoi (const char *name)
+{
+  int val = 0;
+
+  for (;; name++)
+    {
+      switch (*name)
+	{
+	case '0'...'9':
+	  val = 10 * val + (*name - '0');
+	  break;
+	default:
+	  return val;
+	}
+    }
+}
+
+
+/* Allocate buffer_head stuff -------------------- */
+
+
+int
+allocation (int requested)
+{
+  // Note: we don't care about taking note of tracking the nodes
+  // all we care about is that alloc_buffer_head() is called and stored
+
+  int x = 0;
+  int loop = 0;
+  int diff = 0;
+  int *ptr=NULL;
+  struct node *tmp = NULL;
+
+  // how many items are there in the list?
+  list_for_each (pos, &node.list) loop++;
+
+  printk ("%s: ---\n", MODULE_NAME);
+  printk ("%s: There are currently %d elements in list\n", MODULE_NAME, loop);
+  printk ("%s: Recieved request to make the list %d elements long\n",
+	  MODULE_NAME, requested);
+
+  if (debug)
+    printk ("%s: diff = %d\n", MODULE_NAME, requested - loop);
+
+  // do we need to add more records?
+  if (loop < requested)
+    {
+      // how many more do we need?
+      diff = (requested - loop);
+      for (x = 0; x < diff; x++)
+	{
+	  // malloc some space for the struct
+	  // to prevent this from invoking the oom killer we add two
+	  // __GPF flags,  NORETRY and NORECLAIM
+	  // add | GFP_NOWARN if you dont like the memory stats dump when
+	  // kmalloc fails
+	  tmp =
+	    (struct node *) kmalloc (sizeof (struct node),
+				     GFP_KERNEL | __GFP_NORETRY |
+				     __GFP_NORECLAIM);
+	  if (tmp == NULL)
+	    {
+	      printk
+		("%s: WHOA! kmalloc failed. no memory left?"
+		 " bailing out having only created %d elements\n",
+		 MODULE_NAME, (loop + x));
+	      goto interleave;	// abandon loop, we've all the memory
+	      // we can handle so before 'dying' we should
+	      // try freeing up holes rather than skipping through and
+	      // trying malloc again in the next bit of code
+	    }
+
+	  // track what number this node is
+	  tmp->idx = loop + x;
+
+	  // Finally we get to do the one line of code we actually
+	  // truely care about... Note, PAGE_SIZE is defined in linux/a.out.h
+	  ptr = &(tmp->chunksize);
+	  tmp->page = malloc_slab_slice (131072, ptr);
+
+//        tmp->page =
+//          kmalloc (32, GFP_KERNEL | __GFP_NORETRY | __GFP_NORECLAIM);
+	  if (debug) {
+	    printk ("tmp->page = %p\n", tmp->page);
+	    printk ("tmp->chunksize = %d\n", tmp->chunksize);
+	    printk ("tmp->chunksize = %d\n", tmp->chunksize);
+	  }
+
+	  if ((tmp->page) == NULL)
+	    {
+	      printk
+		("%s: WHOA! kmalloc failed. no memory left?"
+		 " bailing out having only created %d elements\n",
+		 MODULE_NAME, (loop + x));
+	      goto interleave;	// abandon routine and recover some memory
+	    }
+
+	  // keep track of where this allocation was in memory
+	  tmp->location = (long) tmp->page;
+
+	  // add to the end of the list
+	  list_add_tail (&(tmp->list), &(node.list));
+	  if (debug)
+	    printk
+	      ("%s: Element %d allocated page of memory from %p (stored as %lx)\n",
+	       MODULE_NAME, tmp->idx, tmp->page, tmp->location);
+	}
+
+    interleave:
+      // excellent, we've now consumed all available memory
+      // next up, lets delete every other page
+
+      list_for_each_safe (pos, q, &node.list)
+      {
+	tmp = list_entry (pos, struct node, list);
+	// Assume we have equal numbers of 'even' and 'odd' memory pages
+	// we get even/odd by using PAGE_SIZE*2
+	if (debug)
+	  printk ("%s: Element %d  is at address %p\n", MODULE_NAME, tmp->idx,
+		  tmp->page);
+
+	if (tmp->location % ((tmp->chunksize) * 2) == 0)
+	  {
+	    list_del (pos);
+	    kfree (tmp->page);
+	    kfree (tmp);
+	    if (debug) 
+	      printk
+		("%s: deleted element %d in list from holding a %d byte page of memory at %p\n",
+		 MODULE_NAME, x, tmp->chunksize,  tmp->page);
+	  }
+      }
+      if (debug)
+	printk ("%s: created %d new elements in list\n", MODULE_NAME, x);
+    }
+
+  // do we need to delete records?
+  // This is because we may be asked to free up a bit of memory
+  // ie 'echo 1024 > /proc/test' then trimmed by 'echo 512 > /proc/test'
+  if (loop > requested)
+    {
+      diff = (loop - requested);
+      list_for_each_safe (pos, q, &node.list)
+      {
+	tmp = list_entry (pos, struct node, list);
+	list_del (pos);
+	kfree (tmp->page);
+	kfree (tmp);
+	diff--;
+	if (diff == 0)
+	  break;		// jump out of this list_for_each() macro loop
+      }
+      if (debug)
+	printk ("%s: destroyed %d elements in list\n", MODULE_NAME, x);
+    }
+
+  // how many items are there in the list?
+  // Just so Joe Bloggs gets an idea this is actually working
+  loop = 0;
+  list_for_each (pos, &node.list) loop++;
+  printk ("%s: list request of %d elements is now composed of %d elements\n",
+	  MODULE_NAME, requested, loop);
+  return (diff);
+}
+
+char *
+malloc_slab_slice (int chunk, int *chunksize)
+{
+  char *tmp = NULL;
+
+  // Stride down from 'chunk' by power of 2, trying to wedge in a malloc
+  // aggressively try to hammer in the big slices as much as possible
+
+  while (chunk >= 32)		// don't try anything below 32
+    {
+      // malloc some space for the struct
+      // to prevent this from invoking the oom killer we add two
+      // __GPF flags,  NORETRY and NORECLAIM
+      // add | GFP_NOWARN if you dont like the memory stats dump when
+      // kmalloc fails
+      tmp = kmalloc (chunk,
+		     GFP_KERNEL | __GFP_NORETRY | __GFP_NORECLAIM |
+		     __GFP_NOWARN);
+
+      if (tmp == NULL)		// if we cant get a malloc, try at 1/2 the size
+	{
+	  chunk = (chunk >> 1);	// 131072 -> 65536 -> ... -> 128 -> 64 -> 32
+	}
+      else
+	{
+	  break;		// we got what we wanted, lets barge out of the while loop
+	}
+    }
+  if (debug)
+    printk ("Chunk size = %d\n", chunk);
+
+  // make a note of how big this chunk was
+  *chunksize = chunk;
+
+  return (tmp);
+}
+
+
+/* Entry and Exit -------------------------------- */
+
+
+static int __init
+test_init (void)
+{
+  printk (KERN_ALERT "%s: Kernel test module loaded\n", MODULE_NAME);
+  printk (KERN_ALERT "%s: Settings\n", MODULE_NAME);
+  printk (KERN_ALERT "%s: --------\n", MODULE_NAME);
+  printk (KERN_ALERT "%s: Buffer_heads assigned: %d\n", MODULE_NAME, buffers);
+
+
+  // Create a start record
+  INIT_LIST_HEAD (&node.list);
+
+  /* Create /proc/test */
+  module_procfile = create_proc_entry (PROC_FNAME, 0644, NULL);
+
+  if (module_procfile == NULL)
+    {
+      remove_proc_entry (PROC_FNAME, &proc_root);
+      printk (KERN_ALERT "Error: Could not initialize /proc/%s\n",
+	      PROC_FNAME);
+      return -ENOMEM;
+    }
+
+  module_procfile->read_proc = procfile_read;
+  module_procfile->write_proc = procfile_write;
+  module_procfile->owner = THIS_MODULE;
+  module_procfile->mode = S_IFREG | S_IRUGO;
+  module_procfile->uid = 0;
+  module_procfile->gid = 0;
+  module_procfile->size = 37;
+
+  if (debug)
+    printk (KERN_INFO "/proc/%s created\n", PROC_FNAME);
+
+  return 0;
+}
+
+
+static void __exit
+test_exit (void)
+{
+  struct node *tmp;
+  int loop = 0;
+  // Clean up /proc
+  remove_proc_entry (PROC_FNAME, NULL);
+
+  // Clear out the list
+
+  list_for_each_safe (pos, q, &node.list)
+  {
+    tmp = list_entry (pos, struct node, list);
+    list_del (pos);
+    kfree (tmp->page);
+    kfree (tmp);
+    loop++;
+  }
+  printk ("%s: /proc file removed\n", MODULE_NAME);
+  printk ("%s: freed up %d list elements\n", MODULE_NAME, loop);
+}
+
+
+module_init (test_init);
+module_exit (test_exit);
+
+
+MODULE_LICENSE ("GPL");		// Get rid of taint message by declaring code as GPL.
+MODULE_AUTHOR (DRIVER_AUTHOR);	// Who wrote this module?
+MODULE_DESCRIPTION (DRIVER_DESC);	// What does this module do?



More information about the Codefragments-commits mailing list