[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