diff -ur linux-2.4.6.uc0pre0.orig/include/linux/swap.h linux-2.4.6.uc0pre0.actiontec/include/linux/swap.h
--- linux-2.4.6.uc0pre0.orig/include/linux/swap.h	2004-12-06 19:34:59.000000000 +0100
+++ linux-2.4.6.uc0pre0.actiontec/include/linux/swap.h	2004-12-06 19:35:49.000000000 +0100
@@ -77,6 +77,11 @@
 extern atomic_t buffermem_pages;
 extern spinlock_t pagecache_lock;
 extern void __remove_inode_page(struct page *);
+extern int areainfo_read_proc (char *page, char **start, off_t off,
+				 int count, int *eof, void *data);
+extern int areainfo_write_proc (struct file *file, const char *buffer,
+				unsigned long count, void *data) ;
+
 
 /* Incomplete types for prototype declarations: */
 struct task_struct;
diff -ur linux-2.4.6.uc0pre0.orig/mmnommu/page_alloc.c linux-2.4.6.uc0pre0.actiontec/mmnommu/page_alloc.c
--- linux-2.4.6.uc0pre0.orig/mmnommu/page_alloc.c	2004-12-06 19:34:59.000000000 +0100
+++ linux-2.4.6.uc0pre0.actiontec/mmnommu/page_alloc.c	2004-12-06 19:35:49.000000000 +0100
@@ -19,6 +19,7 @@
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
 #include <linux/slab.h>
+#include <linux/module.h>
 
 int nr_swap_pages;
 int nr_active_pages;
@@ -650,21 +651,29 @@
 }
 #endif
 
-/*
- * Show free area list (used inside shift_scroll-lock stuff)
- * We also calculate the percentage fragmentation. We do this by counting the
- * memory on each free list with the exception of the first item on the list.
- */
-void show_free_areas_core(pg_data_t *pgdat)
+#define FIXUP(t)				\
+	do {					\
+		if (len <= off) {		\
+			off -= len;		\
+			len = 0;		\
+		} else {			\
+			if (len-off > count)	\
+				goto t;		\
+		}				\
+	} while (0)
+
+static int show_free_areas_getdata(pg_data_t *pgdat, char*page, char**start, off_t off, int count)
 {
+	int len = 0 ;
  	unsigned long order;
 	unsigned type;
 
-	printk("Free pages:      %6dkB (%6dkB HighMem)\n",
+	len +=sprintf(page+len, "Free pages:      %6dkB (%6dkB HighMem)\n",
 		nr_free_pages() << (PAGE_SHIFT-10),
 		nr_free_highpages() << (PAGE_SHIFT-10));
+	FIXUP(got_data);
 
-	printk("( Active: %d, inactive_dirty: %d, inactive_clean: %d, free: %d (%d %d %d) )\n",
+	len +=sprintf(page+len, "( Active: %d, inactive_dirty: %d, inactive_clean: %d, free: %d (%d %d %d) )\n",
 		nr_active_pages,
 		nr_inactive_dirty_pages,
 		nr_inactive_clean_pages(),
@@ -672,6 +681,7 @@
 		freepages.min,
 		freepages.low,
 		freepages.high);
+	FIXUP(got_data);
 
 	for (type = 0; type < MAX_NR_ZONES; type++) {
 		struct list_head *head, *curr;
@@ -692,14 +702,45 @@
 					nr++;
 				}
 				total += nr * (1 << order);
-				printk("%lu*%lukB ", nr,
+				len +=sprintf(page+len, "%lu*%lukB ", nr,
 						(unsigned long)((PAGE_SIZE>>10) << order));
 			}
 			spin_unlock_irqrestore(&zone->lock, flags);
+			len +=sprintf(page+len, "= %lukB)\n", total * (PAGE_SIZE>>10));
 		}
-		printk("= %lukB)\n", total * (PAGE_SIZE>>10));
 	}
+	FIXUP(got_data);
+
+got_data:
+	*start = page+off;
+	return len;
+}
+
 
+
+/*
+ * Show free area list (used inside shift_scroll-lock stuff)
+ * We also calculate the percentage fragmentation. We do this by counting the
+ * memory on each free list with the exception of the first item on the list.
+ */
+#define LINE_LEN 80
+#define LONGEST (63+7*10)	//longest format string + 7 fields of len 10
+char free_areas_buffer[LINE_LEN + LONGEST + 20]; // and a little extra in case format strings are lengthened later
+void show_free_areas_core(pg_data_t *pgdat)
+{
+	int len ;
+	char *start;
+	off_t off = 0 ;
+
+	do
+	{
+		len = show_free_areas_getdata (pgdat, free_areas_buffer, &start, off, LINE_LEN ) ;
+		off += len ;
+		if (len)	
+			printk ( start ); 
+	}
+	while (len);
+	
 #ifdef SWAP_CACHE_INFO
 	show_swap_cache_info();
 #endif	
@@ -922,3 +963,82 @@
 }
 
 __setup("memfrac=", setup_mem_frac);
+
+
+
+#ifdef CONFIG_PROC_FS
+/**
+ * areainfo_read_proc - generates /proc/areainfo
+ * @page: scratch area, one page long
+ * @start: pointer to the pointer to the output buffer
+ * @off: offset within /proc/slabinfo the caller is interested in
+ * @count: requested len in bytes
+ * @eof: eof marker
+ * @data: unused
+ */
+int areainfo_read_proc (char *page, char **start, off_t off,
+				 int count, int *eof, void *data)
+{
+	int len ;
+
+	len = show_free_areas_getdata(pgdat_list, page, start, off, count);
+	len -= (*start-page);		 
+	if (len <= count)
+		*eof = 1;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+#define MAX_SLABINFO_WRITE 128
+/**
+ * areainfo_write_proc - tuning
+ * @file: unused
+ * @buffer: user buffer
+ * @count: data len
+ * @data: unused
+ */
+int areainfo_write_proc (struct file *file, const char *buffer,
+				unsigned long count, void *data)
+{
+	char *tmp;
+	
+	{
+		int i ;
+		struct
+		{
+			const char *pname ;
+			int *pvar ;
+		} vartbl [] =
+		{
+			{NULL,			NULL}
+		} ;
+		
+		if (buffer[0]!='\n')
+		{
+			for (i=0; vartbl[i].pname!=NULL ;i++ )
+			{
+				if ( ( strncmp(buffer, vartbl[i].pname, strlen(vartbl[i].pname)) == 0)
+				  && ( buffer[strlen(vartbl[i].pname)] =='=' ))
+				{
+					tmp = strchr(buffer, '=');
+					if (!tmp)
+						return -EINVAL;
+					tmp++;
+					*(vartbl[i].pvar) = simple_strtol(tmp, &tmp, 10);
+					printk ( "%s set to %d\n", vartbl[i].pname, *(vartbl[i].pvar) ) ;
+					return count ;
+				}
+			}
+			printk ( "\"%s\" is unrecognized\n", buffer ) ;
+			printk ( "Format is: \"var=n\"\n" ) ;
+			printk ( "Recoginized variables are:\n" ) ;
+			for (i=0; vartbl[i].pname!=NULL ;i++ )
+			{
+				printk ( "  %s\n", vartbl[i].pname ) ;
+			}
+		}
+	}
+	return 0 ;
+}
+#endif
diff -ur linux-2.4.6.uc0pre0.orig/fs/proc/proc_misc.c linux-2.4.6.uc0pre0.actiontec/fs/proc/proc_misc.c
--- linux-2.4.6.uc0pre0.orig/fs/proc/proc_misc.c	2001-04-14 05:26:07.000000000 +0200
+++ linux-2.4.6.uc0pre0.actiontec/fs/proc/proc_misc.c	2004-12-06 19:35:49.000000000 +0100
@@ -583,4 +583,9 @@
 				       slabinfo_read_proc, NULL);
 	if (entry)
 		entry->write_proc = slabinfo_write_proc;
+
+	entry = create_proc_read_entry("areainfo", S_IWUSR | S_IRUGO, NULL,
+				       areainfo_read_proc, NULL);
+	if (entry)
+		entry->write_proc = areainfo_write_proc;
 }

