diff -Naur a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
--- a/include/asm-i386/unistd.h	Tue Jul 15 12:42:43 EDT 2003
+++ b/include/asm-i386/unistd.h	Tue Jul 15 12:42:43 EDT 2003
277c277,282
< #define NR_syscalls 268
---
> #ifdef CONFIG_MEMORY_DIFF
>   #define __NR_memdiffctrl (__NR_clock_nanosleep+1)
>   #define NR_syscalls 269
> #else
>   #define NR_syscalls 268
> #endif
diff -Naur a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Tue Jul 15 12:42:43 EDT 2003
+++ b/include/linux/mm.h	Tue Jul 15 12:42:43 EDT 2003
175a176,183
> #ifdef CONFIG_MEMORY_DIFF
> 	/*
> 	 * We borrow the pte_chain's lock to protect the following 'class'.
> 	 */
> 	struct diff_mem_class* class;
>   pid_t pid;
> #endif
> 	
197a206,238
> #ifdef CONFIG_MEMORY_DIFF
> 	/*
> 	 * We borrow the pte_chain's lock to protect the following page->class.
> 	 * The following two functions are copied from rmap_locking.h
> 	 */
> #define PG_classlock          PG_chainlock
> static inline void page_class_lock(struct page *page)
> {
> 	/*
> 	 * Assuming the lock is uncontended, this never enters
> 	 * the body of the outer loop. If it is contended, then
> 	 * within the inner loop a non-atomic test is used to
> 	 * busywait with less bus contention for a good time to
> 	 * attempt to acquire the lock bit.
> 	 */
> 	preempt_disable();
> #ifdef CONFIG_SMP
> 	while (test_and_set_bit(PG_classlock, &page->flags)) {
> 		while (test_bit(PG_classlock, &page->flags))
> 			cpu_relax();
> 	}
> #endif
> }
> static inline void page_class_unlock(struct page *page)
> {
> #ifdef CONFIG_SMP
> 	smp_mb__before_clear_bit();
> 	clear_bit(PG_classlock, &page->flags);
> #endif
> 	preempt_enable();
> }
> #endif
> 
diff -Naur a/include/linux/mm_inline.h b/include/linux/mm_inline.h
--- a/include/linux/mm_inline.h	Tue Jul 15 12:42:44 EDT 2003
+++ b/include/linux/mm_inline.h	Tue Jul 15 12:42:44 EDT 2003
6a7,18
> #ifdef CONFIG_MEMORY_DIFF
> 	if(page->class) {
> 		atomic_inc(&page->class->nr_active);
> #if defined(CONFIG_MDIFF_CLASS_RECLAIM) && defined (CONFIG_MDIFF_CLASS_NEGATIVE)
> 		atomic_inc(&page->class->nr_positivemove);
> #endif
> 	}
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> 	else
> 		atomic_inc(&missact);  
> #endif
> #endif
13a26,43
> #ifdef CONFIG_MEMORY_DIFF
> 	if(page->class) {
> 		atomic_inc(&page->class->nr_inactive);
> #if defined(CONFIG_MDIFF_CLASS_RECLAIM) && defined (CONFIG_MDIFF_CLASS_NEGATIVE)
> 		/*
> 		 * page may move from swap to inactive. this movement should
> 		 * count for positive move,
> 		 * and active to inactive should count for negative. But it will
> 		 * not reach here since it operates on the list directly
> 		 */
> 		atomic_inc(&page->class->nr_positivemove);
> #endif
> 	}
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> 	else
> 		atomic_inc(&missinact);  
> #endif
> #endif
20a51,59
> #ifdef CONFIG_MEMORY_DIFF
> 	if(page->class) {
> 		atomic_dec(&page->class->nr_active);
> 	}
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> 	else
> 		atomic_inc(&missactsub);  
> #endif
> #endif
27a67,74
> #ifdef CONFIG_MEMORY_DIFF
> 	if(page->class)
> 		atomic_dec(&page->class->nr_inactive);
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> 	else
> 		atomic_inc(&missinactsub);  
> #endif
> #endif
36a84,92
> #ifdef CONFIG_MEMORY_DIFF
> 		if(page->class) {
> 			atomic_dec(&page->class->nr_active);
> 		}
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> 		else
> 			atomic_inc(&missactsub);  
> #endif
> #endif
38a95,102
> #ifdef CONFIG_MEMORY_DIFF
> 		if(page->class)
> 			atomic_dec(&page->class->nr_inactive);
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> 		else
> 			atomic_inc(&missinactsub);  
> #endif
> #endif
diff -Naur a/include/linux/pagemap.h b/include/linux/pagemap.h
--- a/include/linux/pagemap.h	Tue Jul 15 12:42:44 EDT 2003
+++ b/include/linux/pagemap.h	Tue Jul 15 12:42:44 EDT 2003
127a128,175
> #ifdef CONFIG_MEMORY_DIFF
> 	page_class_lock(page);
> 	if (!page_mapped(page)) {
> /*
> #ifdef CONFIG_MDIFF_PAGECACHE_CLASS
>                 if (page->class) {
> 		  printk("page has class information already, mapping=%p:%p\n",
> 		  	mapping, &swapper_space);
> 		  goto endit;	
> 		}
> 		else
> 			page->class = &pgcache_mem_class;      
> #else
> */
> 		void* cls = page->class;
> 		if (!current->class) {
> 			printk("current thread has no class!,mp=%p,sw=%p\n",mapping,&swapper_space);
> 			page->class = &def_mem_class;
> 		}
> 		else {
> 			page->class = current->class;
> 			page->pid = current->pid;      
>     }  
> /*
> #endif	
> */
> 		mem_class_get(page->class);
> 		atomic_inc(&page->class->nr_total);
> 		
> 
> 		if (0) {// (!cls) {
> 			/* check whether the page is already in LRU, then we may miss it */
> 			/* Wrong, we didn't hold the lock, so somebody else may ..., but temporarily before we find
> 			 * why it is added without setting class, ... , we should hold the zone LRU lock.*/
> 			printk("repair for leak page(type:%s)\n", PageActive(page) ? "Active":"Inactive"); 
> 			if (PageLRU(page)){
> 				if (PageActive(page))
> 					atomic_inc(&page->class->nr_active);
> 				else	
> 					atomic_inc(&page->class->nr_inactive);
> 				
> 			}
> 		}
> 
> 	}
> endit:	
> 	page_class_unlock(page);
> #endif
diff -Naur a/include/linux/proc_fs.h b/include/linux/proc_fs.h
--- a/include/linux/proc_fs.h	Tue Jul 15 12:42:44 EDT 2003
+++ b/include/linux/proc_fs.h	Tue Jul 15 12:42:44 EDT 2003
226a227,230
> #ifdef CONFIG_MEMORY_DIFF
> extern void proc_memclass_init(void);
> #endif
> 
diff -Naur a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Tue Jul 15 12:42:44 EDT 2003
+++ b/include/linux/sched.h	Tue Jul 15 12:42:44 EDT 2003
218a219,229
> #ifdef CONFIG_MEMORY_DIFF
> 	/* we will chain all tasks who share this active mm_struct
> 	 * into a list, so that we can do reverse mapping from
> 	 * mm_struct to tasks
> 	 * and this list should be protected by per mm_struct's
> 	 * peertask_lock;
> 	 */
> 	struct list_head       tasklist;
> 	spinlock_t             peertask_lock;
> 	struct diff_mem_class* class;
> #endif
314a326,425
> #ifdef CONFIG_MEMORY_DIFF
> 
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> extern atomic_t missact;
> extern atomic_t missinact;
> extern atomic_t missactsub;
> extern atomic_t missinactsub;
> #endif
>     
> extern spinlock_t       mem_class_lock;
> extern struct list_head diff_mem_list;
> 
> /* All processes who are not assigned class explicitly belong 
>  * to this default memory class. Refer to its initilization in
>  * init/main.c
>  */
> extern struct diff_mem_class   def_mem_class;
> 
> #ifdef CONFIG_MDIFF_PAGECACHE_CLASS
> extern struct diff_mem_class   pgcache_mem_class;
> #endif
> 
> #define mem_class_get(cls) do{ atomic_inc(&((cls)->count));}while(0)
> #define mem_class_put(cls) \
>    do{ if (atomic_dec_and_test(&((cls)->count))) if((cls)->classid) kfree(cls);}while(0)
> 
> #define mem_class_free(cls) mem_class_put(cls)
> 
>   /* whether the page reclaimable */
>   /* determined after shrink_list based on nr_shrinkscan/nr_posistive move as well as pgfault */
> #define MCLS_READY_SHRINK         1
>   /* whether counts for refill_inactive */
>   /* determined before call refill_inactive based on memory share threshold
>    * and maybe MCLS_READY_SHRINK.
>    */
> #define MCLS_READY_REFILL         2
>   /* whether be selected as reclaimable candidate for reference check */
>   /* determined after refill_inactive based on nr_active/nr_inactive */
> #define MCLS_READY_SCAN           3
> 
> #define MCLS_readyshrink(cls) test_bit(MCLS_READY_SHRINK, &(cls)->flags)
> #define MCLS_readyrefill(cls) test_bit(MCLS_READY_REFILL, &(cls)->flags)
> #define MCLS_readyscan(cls) test_bit(MCLS_READY_SCAN, &(cls)->flags)
> 
> #define MCLS_set_readyshrink(cls) set_bit(MCLS_READY_SHRINK, &(cls)->flags)
> #define MCLS_set_readyrefill(cls) set_bit(MCLS_READY_REFILL, &(cls)->flags)
> #define MCLS_set_readyscan(cls) set_bit(MCLS_READY_SCAN, &(cls)->flags)
> 
> #define MCLS_reset_readyshrink(cls) clear_bit(MCLS_READY_SHRINK, &(cls)->flags)
> #define MCLS_reset_readyrefill(cls) clear_bit(MCLS_READY_REFILL, &(cls)->flags)
> #define MCLS_reset_readyscan(cls) clear_bit(MCLS_READY_SCAN, &(cls)->flags)
> 
> struct diff_mem_class {
> 	/* suppose we link all diff_mem_class together */
> 	struct list_head list;
> 
> 	unsigned long flags;
> 
> 	/*
> 	 * It seems that the nr_active/nr_inactive per class should be
> 	 * maintained per-zone/per-node, but it will makes the structure
> 	 * too complex. Since there is only one node right now, and the
> 	 * concept of zone may disappear in the future, we only maintain
> 	 * a global nr_active/nr_inactive.
> 	 * Note that the total of nr_active of all class should equal to
> 	 * the sum of all nr_active in all zones. We use atomic_t type to
> 	 * avoid lock. It is impossible to use the per zone LRU lock unless
> 	 * we maintain per zone value later.
> 	 */
> 	atomic_t nr_total;
> 	atomic_t nr_active;
> 	atomic_t nr_inactive;
> 
> 	/*
> 	 * We don't want to do complex calculation to determine how
> 	 * many pages to reclaim from each class every time we need to
> 	 * shrink the cache. We calculate a threshold based on memory
> 	 * share for each class, then if nr_total exceeds this value,
> 	 * the pages belonging to this class are candidates for reclaim.
> 	 * If no class exceeds the threashold (the value diffs for every
> 	 * class), all pages are candidates. But this should not happen
> 	 * often, since in that case, most likely there is no need to
> 	 * shrink cache.
> 	 * MCLS_READY_SRHINK bit in flag is used for this purpose.
> 	 * Note that there are still some physical pages we not count
> 	 * (kernel resources, socket buffer etc.), it is possible.
> 	 * One of our work is to determine a proper threshold based all
> 	 * these factors.
> 	 */
> 	unsigned long shrink_threshold;
> 
> 	atomic_t count;
> 	int      classid;
> };
> 
> #if defined(CONFIG_MDIFF_CLASS_RECLAIM) && \
>     defined(CONFIG_MDIFF_CLASS_NEGATIVE)
> void mem_class_priority_adjust_temp(struct diff_mem_class* cls);
> void mem_class_priority_adjust(struct diff_mem_class* cls);
> #endif
315a427
> #endif
340a453,460
> #ifdef CONFIG_MEMORY_DIFF
> 	/*
> 	 * list of all tasks sharing ownership of mm.
> 	 */
> 	struct list_head peertask_list;
> 	struct diff_mem_class* class;
> #endif
> 
diff -Naur a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Tue Jul 15 12:42:44 EDT 2003
+++ b/fs/exec.c	Tue Jul 15 12:42:44 EDT 2003
521a522,541
> 
> #ifdef CONFIG_MEMORY_DIFF
> 	spin_lock(&mm->peertask_lock);
> 	list_add_tail(&tsk->peertask_list, &mm->tasklist);
> 
> 	if (!tsk->class)
> 		BUG();
> 
> 	if (!mm->class) {
> 		mem_class_get(tsk->class);
> 		mm->class=tsk->class;
> 	}
> 	else{
> 		if (mm->class != tsk->class) {
> 			printk("Mismatch of class for virtual memory space and task\n");
> 		}
> 	}
> 	spin_unlock(&mm->peertask_lock);
> #endif
> 
776a797,800
> #ifdef CONFIG_MEMORY_DIFF
> extern int idx_cls;
> #endif
> 
1049a1074,1200
> #ifdef CONFIG_MEMORY_DIFF
> /*
>  * the following 2 functions are from dcache.c to get the current directory inside of kernel
>  */
> /**
>  * d_path - return the path of a dentry
>  * @dentry: dentry to report
>  * @vfsmnt: vfsmnt to which the dentry belongs
>  * @root: root dentry
>  * @rootmnt: vfsmnt to which the root dentry belongs
>  * @buffer: buffer to return value in
>  * @buflen: buffer length
>  *
>  * Convert a dentry into an ASCII path name. If the entry has been deleted
>  * the string " (deleted)" is appended. Note that this is ambiguous. Returns
>  * the buffer.
>  *
>  * "buflen" should be %PAGE_SIZE or more. Caller holds the dcache_lock.
>  */
> static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
> 			struct dentry *root, struct vfsmount *rootmnt,
> 			char *buffer, int buflen)
> {
> 	char * end = buffer+buflen;
> 	char * retval;
> 	int namelen;
> 
> 	*--end = '\0';
> 	buflen--;
> 	if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
> 		buflen -= 10;
> 		end -= 10;
> 		memcpy(end, " (deleted)", 10);
> 	}
> 
> 	/* Get '/' right */
> 	retval = end-1;
> 	*retval = '/';
> 
> 	for (;;) {
> 		struct dentry * parent;
> 
> 		if (dentry == root && vfsmnt == rootmnt)
> 			break;
> 		if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
> 			/* Global root? */
> 			if (vfsmnt->mnt_parent == vfsmnt)
> 				goto global_root;
> 			dentry = vfsmnt->mnt_mountpoint;
> 			vfsmnt = vfsmnt->mnt_parent;
> 			continue;
> 		}
> 		parent = dentry->d_parent;
> 		prefetch(parent);
> 		namelen = dentry->d_name.len;
> 		buflen -= namelen + 1;
> 		if (buflen < 0)
> 			return ERR_PTR(-ENAMETOOLONG);
> 		end -= namelen;
> 		memcpy(end, dentry->d_name.name, namelen);
> 		*--end = '/';
> 		retval = end;
> 		dentry = parent;
> 	}
> 
> 	return retval;
> 
> global_root:
> 	namelen = dentry->d_name.len;
> 	buflen -= namelen;
> 	if (buflen >= 0) {
> 		retval -= namelen-1;	/* hit the slash */
> 		memcpy(retval, dentry->d_name.name, namelen);
> 	} else
> 		retval = ERR_PTR(-ENAMETOOLONG);
> 	return retval;
> }
> static long kgetcwd(char *buf, unsigned long size)
> {
> 	int error;
> 	struct vfsmount *pwdmnt, *rootmnt;
> 	struct dentry *pwd, *root;
> 	char *page = (char *) __get_free_page(GFP_USER);
> 
> 	if (!page)
> 		return -ENOMEM;
> 
> 	read_lock(&current->fs->lock);
> 	pwdmnt = mntget(current->fs->pwdmnt);
> 	pwd = dget(current->fs->pwd);
> 	rootmnt = mntget(current->fs->rootmnt);
> 	root = dget(current->fs->root);
> 	read_unlock(&current->fs->lock);
> 
> 	error = -ENOENT;
> 	/* Has the current directory has been unlinked? */
> 	spin_lock(&dcache_lock);
> 	if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
> 		unsigned long len;
> 		char * cwd;
> 
> 		cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE);
> 		spin_unlock(&dcache_lock);
> 
> 		error = PTR_ERR(cwd);
> 		if (IS_ERR(cwd))
> 			goto out;
> 
> 		error = -ERANGE;
> 		len = PAGE_SIZE + page - cwd;
> 		if (len <= size) {
> 			error = len;
> 			strcpy(buf,cwd);
> 		}
> 	} else
> 		spin_unlock(&dcache_lock);
> 
> out:
> 	dput(pwd);
> 	mntput(pwdmnt);
> 	dput(root);
> 	mntput(rootmnt);
> 	free_page((unsigned long) page);
> 	return error;
> }
> 
> #endif
1063c1214,1251
< 	sched_balance_exec();
---
> #ifdef CONFIG_MEMORY_DIFF
> 	char* cwd;	
> 	
> 	if (filename[0]=='/') {
> 		cwd = filename;
> 	}	
> 	else{
> 		cwd = __getname();
> 		if (cwd) 
> 			kgetcwd(cwd,PATH_MAX);
> 	}	
> 	
> 	if (cwd[0]=='/') {
> 		if (!strncmp(cwd+1,"class",5) ){
> 			int clsid = cwd[6]-'0';
> 			if (clsid>=0 && clsid<idx_cls) {
> 				struct diff_mem_class* cls=NULL;
> 				spin_lock(&mem_class_lock);
> 				list_for_each_entry(cls, &diff_mem_list, list) {
> 					if (cls->classid==clsid)
> 						goto found_cls;
> 				}
> 				cls = NULL;
> found_cls:				
> 				if (cls && cls!=current->class) {
> 					if (current->class) {
> 						// printk("put memclass classid=%d, count=%d\n",
> 						//	current->class->classid,
> 						//	atomic_read(&current->class->count));
> 						mem_class_put(current->class);	
> 					}	
> 					mem_class_get(cls);	
> 					current->class = cls;
> 				}	
> 				spin_unlock(&mem_class_lock);
> 			}
> 		}
> 	}
1064a1253,1258
> 	if (filename[0]!='/' && cwd) 
> 		putname(cwd);
> 		
> #endif	
> 	sched_balance_exec();
> 	
diff -Naur a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Tue Jul 15 12:42:44 EDT 2003
+++ b/fs/proc/proc_misc.c	Tue Jul 15 12:42:44 EDT 2003
689a690,1209
> 
> #ifdef CONFIG_MEMORY_DIFF
> 
> int shared_vars[0x10];
> 
> extern int idx_cls;
> extern int sys_memdiffctrl(int type, int arg);
> extern int memdiff_redefine(int clsid, int arg);
> 
> #define MAX_PIN_MEM  400
> int  num_pinmem = 0;
> void* pinmem[MAX_PIN_MEM];
> 
> static int shared_vars_write_proc(struct file* file, const char* buffer, unsigned long count, void* data)
> {
> 	int index = (int)data;
> 	if (index<0 || index>=sizeof(shared_vars)/sizeof(shared_vars[0])) {
> 		return 0;
> 	}
> 	if (count>0)
> 		sscanf(buffer, "%d", shared_vars+index);
> 	return count;
> }
> 
> int shared_vars_read_proc(char* page, char**start, off_t off, int count, int *eof, void* data)
> {
> 	int index = (int)data;
> 
> 	if (index<0 || index>=sizeof(shared_vars)/sizeof(shared_vars[0])) 
> 		return 0;
> 	
> 	if (off>0 || count<0x10) {
> 		*eof=1;
> 		*start=page;
> 		return 0;
> 	}
> 
> 	count = sprintf(page, "%d", shared_vars[index]);
> 	*eof = 1;
> 	*start = page;
> 	return count;
> }
> 
> static int memeat_write_proc(struct file*file, const char* buffer, 
> 			unsigned long count, void* data)
> {
> 	char info[0x20];
> 	int i, pin;
> 	
> 	if (count>sizeof(info)-1) 
> 		return -EINVAL;
> 		
> 	if (copy_from_user(info, buffer, count))
> 		return -EFAULT;
> 		
> 	sscanf(info, "%d\n",&pin);
> 	if (pin<0) {
> 		 printk("invalid value write to memory pindown request\n");
> 		 return -EINVAL;  
> 	}
> 	if (pin>MAX_PIN_MEM)
> 		pin = MAX_PIN_MEM;
> 
> 	if (pin<num_pinmem) {
> 		for (i=pin;i<num_pinmem;i++) {
> 			vfree(pinmem[i]);
> 			pinmem[i]=NULL;
> 		}
> 		num_pinmem=pin;
> 	}
> 	else {
> 		for (i=num_pinmem; i<pin; i++) {
> 			pinmem[i]=vmalloc(1<<20);
> 			if (!pinmem[i])
> 				break;
> 		}
> 		num_pinmem=i;
> 	}
> 
> 	printk("Current pindown memory size: %d(MBytes)\n", num_pinmem);
> 	
> 	return count;
> }
> 
> int memeat_read_proc(char* page, char**start, off_t off, int count, 
> 			int *eof, void* data)
> {
> 	int n;
> 	char* ptr;
> 	struct list_head* l;
> 
> 	ptr = page;
> 	if ( count<10) {
> 		*eof=1;
> 		*start=page;
> 		return 0;
> 	}
> 	memset(ptr,0x20,count);
> 
> 	n = sprintf(ptr, "%d", num_pinmem);
> 	if (off>=n) {
> 		*eof=1;
> 		*start=page;
> 		return 0;
> 	}
> 	*start = page+off;
> 	*eof=1;
>   
>   printk("actmis:%d,%d  inactmis:%d,%d\n", missact, missactsub, missinact, missinactsub);
> 
> if (0)	
> //if (atomic_read(&cls->nr_active)<0 || atomic_read(&cls->nr_inactive)<0)
> {
>   int i, c;
>   int cnt[idx_cls+1];
>   int act[4], inact[4];
> 
>   spin_lock(&mem_class_lock);
> /* calc the number of classes */
>   list_for_each(l, &diff_mem_list) {
>     	struct diff_mem_class* cls;
> 	cls = list_entry(l, struct diff_mem_class, list );
> 	if ( cls->classid<4 ) {
> 	   act[cls->classid] = atomic_read(&cls->nr_active);
> 	   inact[cls->classid] = atomic_read(&cls->nr_inactive);
> 	}
>   }
>   spin_unlock(&mem_class_lock);
>   printk("Act/Inact 0:%d,%d 2:%d,%d 3:%d,%d\n", act[0], inact[0], act[2], inact[2], act[3], inact[3]);
>   
>   for (c=0; c<2; c++) {
>    
>     struct page* pg;
>     struct zone* zone = &(contig_page_data.node_zones[c]);
>     if (!spin_trylock(&zone->lru_lock)) {
>       printk("fail to lock zone'lru\n");
>       continue;
>     }
> 
>     memset(cnt, 0, sizeof(cnt));  
>     printk("class active number =");
>     list_for_each_entry(pg, &zone->active_list, lru)
>     {
>       if (pg->class) {
>         if(pg->class->classid>=idx_cls)
>           cnt[idx_cls]++;
> 	else
>           cnt[pg->class->classid]++;
>       }
>       else {
>         cnt[idx_cls]++;
>       }  
>     }
>     for (i=0; i<idx_cls+1; i++)
>      printk("%d ", cnt[i]);
>     printk("\n");
> 
>     memset(cnt, 0, sizeof(cnt));  
>     printk("class inactive number =");
>     list_for_each_entry(pg, &zone->inactive_list, lru)
>     {
>       if (pg->class) {
>         if(pg->class->classid>=idx_cls)
>           cnt[idx_cls]++;
> 	else
>           cnt[pg->class->classid]++;
>       }
>       else {
>         cnt[idx_cls]++;
>       }  
>     }
>     for (i=0; i<idx_cls+1; i++)
>      printk("%d ", cnt[i]);
>     printk("\n");
>   
>     spin_unlock(&zone->lru_lock);
>   }
> }
> 	return n-off;	
> }
> 
> /*
>  * class definition write in the format of
>    classid, maxshare, minshare
> */
> static int clsdef_write_proc( struct file *file,
> 		const char *buffer, unsigned long count, void *data)
> {
> 	char info[0x20];
> 	int classid, softmaxshare;
> 	
> 	if (count>sizeof(info)-1) 
> 		return -EINVAL;
> 		
> 	if (copy_from_user(info, buffer, count))
> 		return -EFAULT;
> 		
> 	sscanf(info, "%d%d\n",&classid, &softmaxshare);
> 	if (classid>idx_cls || classid<0) {
> 		 printk("invalid value write to memory class definition\n");
> 		 return -EINVAL;  
> 	}
> 	if (classid==idx_cls) {
> 		// create new clas
> 		sys_memdiffctrl(3,softmaxshare);
> 	}
> 	else {
> 		// redefine the threshold
> 		memdiff_redefine( classid, softmaxshare);
> 	}
> 	
> 	printk("define class %d, %d\n", classid, softmaxshare);
> 	
> 	return count;
> }
> 
> #define MDIFF_CLSDEF_ENTRY_LEN    48
> #define MDIFF_CLSDEF_ENTRY_FORMAT "%5d    %10lu    %10d    %10d\n"
> 
> int clsdef_read_proc_ex(char* page, char**start, off_t off, int count, int *eof, void* data)
> {
> 	int n;
> 	struct list_head* l;
> 	char* buf;
> 	char* ptr;
> 	char  entry[MDIFF_CLSDEF_ENTRY_LEN+16];
> 
> 	buf = kmalloc(idx_cls*MDIFF_CLSDEF_ENTRY_LEN, GFP_KERNEL);
> 	if (!buf) {
> 		*eof=1;
> 		*start=page;
> 		return 0;
> 	}
> 	
> 	ptr = buf;
> 	memset(buf,0x20,idx_cls*MDIFF_CLSDEF_ENTRY_LEN);
> 	
> 	spin_lock(&mem_class_lock);
> 	/* calc the number of classes */
> 	list_for_each(l, &diff_mem_list) {
> 		struct diff_mem_class* cls;
> 		
> 		if (ptr+MDIFF_CLSDEF_ENTRY_LEN> buf+idx_cls*MDIFF_CLSDEF_ENTRY_LEN)
> 			break;
> 		
> 		cls = list_entry(l, struct diff_mem_class, list );
> 		n = sprintf(entry, MDIFF_CLSDEF_ENTRY_FORMAT,
> 				cls->classid, 
> 				cls->shrink_threshold,
> 				atomic_read(&cls->nr_active),
> 				atomic_read(&cls->nr_inactive));
> 		memcpy(ptr+(MDIFF_CLSDEF_ENTRY_LEN-n), entry, n);
> 		ptr += MDIFF_CLSDEF_ENTRY_LEN;
> 	}
> 	spin_unlock(&mem_class_lock);
> 	
> 	if (off>=(ptr-buf)) {
> 		*eof=1;
> 		*start=page;
> 		kfree(buf);
> 		return 0;
> 	}
> 	
> 	if (count>(ptr-buf)-off) {
> 		*eof=1;
> 		memcpy(page,buf,(ptr-buf)-off);
> 		*start=page;
> 		kfree(buf);
> 		return (ptr-buf)-off;
> 	}
> 	else {
> 		*eof=0;
> 		memcpy(page,buf,count);
> 		*start=page;
> 		kfree(buf);
> 		return count;
> 	}
> 	
> }
> 
> int clsdef_read_proc(char* page, char**start, off_t off, int count, int *eof, void* data)
> {
> 	int n;
> 	struct list_head* l;
> 	char* ptr;
> 	char  entry[MDIFF_CLSDEF_ENTRY_LEN+16];
> 
> 	ptr = page;
> 	if ( count<idx_cls*MDIFF_CLSDEF_ENTRY_LEN) {
> 		*eof=1;
> 		*start=page;
> 		return 0;
> 	}
> 	memset(ptr,0x20,count);
> 	
> 	spin_lock(&mem_class_lock);
> 	/* calc the number of classes */
> 	list_for_each(l, &diff_mem_list) {
> 		struct diff_mem_class* cls;
> 		
> 		if (ptr+MDIFF_CLSDEF_ENTRY_LEN>page+count)
> 			break;
> 		
> 		cls = list_entry(l, struct diff_mem_class, list );
> 		n = sprintf(entry, MDIFF_CLSDEF_ENTRY_FORMAT,
> 				cls->classid, 
> 				cls->shrink_threshold,
> 				atomic_read(&cls->nr_active),
> 				atomic_read(&cls->nr_inactive));
> 
> 		if (n>MDIFF_CLSDEF_ENTRY_LEN) {
> 			printk("not enough len for memdiff/classdef-entry\n");
> 			memcpy(ptr, entry, MDIFF_CLSDEF_ENTRY_LEN);
> 		}	
> 		else
> 			memcpy(ptr+(MDIFF_CLSDEF_ENTRY_LEN-n), entry, n);
> 		ptr += MDIFF_CLSDEF_ENTRY_LEN;
> 	}
> 	spin_unlock(&mem_class_lock);
> 
> 	if (off>=(ptr-page)) {
> 		*eof=1;
> 		*start=page;
> 		return 0;
> 	}
> 
> 	*start = page+off;
> 	*eof=1;
> 	return ptr-page-off;	
> }
> 
> //temporarily count pid < 4096
> #define COUNTPID_MAXIDX	8192
> int countall[COUNTPID_MAXIDX];
> #define MYMAXPID  COUNTPID_MAXIDX-4
> #define MYLGPID  COUNTPID_MAXIDX-3
> #define MYNOCLSPID  COUNTPID_MAXIDX-2
> #define MYNOTSKPID  COUNTPID_MAXIDX-1
> 
> int pgcount_read_proc(char* page, char**start, off_t off, int count, int *eof, void* data)
> {
>   struct page* pg;
>   int cls = (int)data;
>   struct zone* zone = &(contig_page_data.node_zones[cls]);
>   char entry[0x20];
> 
>   char * ptr = page;
>   int    done=0;
>   int  i, t;
> 
>   if (off>0) {
>     *eof = 1;
>     *start=page;
>     return 0;
>   } 
> 
>   if (!spin_trylock(&zone->lru_lock)) {
>     *eof = 1;
>     *start=page;
>     return 0;
>   }
> 
>   memset(countall, 0, sizeof(countall));
> 
>   list_for_each_entry(pg, &zone->active_list, lru)
>   {
>     if (pg->class) {
>       if (pg->pid>MYMAXPID)
>         countall[MYLGPID]++;
>       else if (pg->pid<0)
>         countall[MYNOTSKPID]++;
>       else
>         countall[pg->pid]++;
>     }
>     else {
>       countall[MYNOCLSPID]++;
>     }
>   }
>   list_for_each_entry(pg, &zone->inactive_list, lru)
>   {
>     if (pg->class) {
>       if (pg->pid>MYMAXPID)
>         countall[MYLGPID]++;
>       else if (pg->pid<0)
>         countall[MYNOTSKPID]++;
>       else
>         countall[pg->pid]++;
>     }
>     else {
>       countall[MYNOCLSPID]++;
>     }
>   }
>   
>   spin_unlock(&zone->lru_lock);
> 
>   for (i=0; i<=MYMAXPID; i++) {
>     if (countall[i]>0) {
>       struct task_struct *tsk = find_task_by_pid(i);
>       if ( tsk ) {
>         t = sprintf(entry, "%d %s\n",countall[i], tsk->comm);
>         if ( done+t <= count) {
>           memcpy(ptr, entry, t);
>           ptr += t;
>           done+= t;
>         }
>         else
>           goto finishit;
>       }
>       else
>         countall[MYNOTSKPID] += countall[i];
>     }
>   }
> 
>   t = sprintf(entry, "%d noclass\n", countall[MYNOCLSPID]);
>   if ( done+t <= count) {
>     memcpy(ptr, entry, t);
>     ptr += t;
>     done+= t;
>   }
>   else
>     goto finishit;  
> 
>   t = sprintf(entry, "%d notask\n", countall[MYNOTSKPID]);
>   if ( done+t <= count) {
>     memcpy(ptr, entry, t);
>     ptr += t;
>     done+= t;
>   }
>   else
>     goto finishit;
> 
>   t = sprintf(entry, "%d toolarge\n", countall[MYLGPID]);
>   if ( done+t <= count) {
>     memcpy(ptr, entry, t);
>     ptr += t;
>     done+= t;
>   }
>   else
>     goto finishit;
>         
> finishit:
> 
>   *start = page;
>   *eof = 1;
>   return done;
> }
> 
> void __init proc_memclass_init(void)
> {
> 	/*
> 	 * prepare proc entries
> 	 */
> 	int i;
> 	struct proc_dir_entry* res;
> 	struct proc_dir_entry* mdiff_entry;
>   
> 	res = proc_mkdir("memdiff", NULL);
> 	if (!res) {
> 		printk("make proc directory fail\n");
> 		return;
> 	}
> 	mdiff_entry = res;
> 	
> 	res = create_proc_entry("classdef",0, mdiff_entry);
> 	if (!res) {
> 		printk("make proc entry fail\n");
> 		return;
> 	}
> 	res->data = NULL;
> 	res->read_proc = clsdef_read_proc;
> 	res->write_proc = clsdef_write_proc;
> 
> 	for (i=0; i<sizeof(shared_vars)/sizeof(shared_vars[0]); i++) {
> 		char name[0x10];
> 		sprintf(name,"sharedvars%d", i);
> 		res = create_proc_entry(name,0, mdiff_entry);
> 		if (!res) {
> 			printk("make proc entry fail\n");
> 			return;
> 		}
> 		res->data = (void*)i;
> 		res->read_proc = shared_vars_read_proc;
> 		res->write_proc = shared_vars_write_proc;
> 	}
> 
> 	res = create_proc_entry("pagecount0",0, mdiff_entry);
> 	if (!res) {
> 		printk("make proc entry fail\n");
> 		return;
> 	}
> 	res->data = (void*)0;
> 	res->read_proc = pgcount_read_proc;
> 
> 	res = create_proc_entry("pagecount1",0, mdiff_entry);
> 	if (!res) {
> 		printk("make proc entry fail\n");
> 		return;
> 	}
> 	res->data = (void*)1;
> 	res->read_proc = pgcount_read_proc;
> 
> 	res = create_proc_entry("pagecount2",0, mdiff_entry);
> 	if (!res) {
> 		printk("make proc entry fail\n");
> 		return;
> 	}
> 	res->data = (void*)2;
> 	res->read_proc = pgcount_read_proc;
> 
> 	res = create_proc_entry("memeat",0, mdiff_entry);
> 	if (!res) {
> 		printk("make proc entry fail\n");
> 		return;
> 	}
> 	res->data = NULL;
> 	res->read_proc = memeat_read_proc;
> 	res->write_proc = memeat_write_proc;
> }
> 
> #endif
diff -Naur a/fs/proc/root.c b/fs/proc/root.c
--- a/fs/proc/root.c	Tue Jul 15 12:42:44 EDT 2003
+++ b/fs/proc/root.c	Tue Jul 15 12:42:44 EDT 2003
79a80,83
> 
> #ifdef CONFIG_MEMORY_DIFF
> 	proc_memclass_init();
> #endif
diff -Naur a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig	Tue Jul 15 12:42:44 EDT 2003
+++ b/init/Kconfig	Tue Jul 15 12:42:44 EDT 2003
184a185,216
> menu "differentiated memory service"
> 
> config MEMORY_DIFF
> 	bool "differentiated memory basic"
> 	default y
> 	help
> 	  provide class based memory control
> 
> config MDIFF_DEBUG_BEANCOUNTING
> 	bool "debug the beancounting"
> 	default y
> 	depends on MEMORY_DIFF
> 	help
> 	  debug the bean counting of class memory
> 
> config MDIFF_PAGECACHE_CLASS
> 	bool "pagecache class"
> 	default y
> 	depends on MEMORY_DIFF
> 	help
> 	  assign all pages belonging to page cache one special class
> 
> config MDIFF_CLASS_RECLAIM
> 	bool "class based reclaim"
> 	default y
> 	depends on MEMORY_DIFF
> 	help
> 	  reclaim pages baed on class memory share
> 
> endmenu
> 
> 
diff -Naur a/init/main.c b/init/main.c
--- a/init/main.c	Tue Jul 15 12:42:44 EDT 2003
+++ b/init/main.c	Tue Jul 15 12:42:44 EDT 2003
117a118,155
> #ifdef CONFIG_MEMORY_DIFF
> 
> 	/* 
> 	 * The diff_mem_list is protected by mem_class_lock. This
> 	 * list may be accessed by regular processes or the timer
> 	 * function which monitor the activeness of class possibly 
> 	 * running in interrupt context.
> 	 * The spinlock is enough to protect concurrently accesses
> 	 * from multiple processes on SMP, but it should disable BH
> 	 * if want to protected it from interrupt context. To 
> 	 * save time, we don't disable BH, instead, we use 
> 	 * !!!spin_trylock!!! in the timer function. If fail to lock, 
> 	 * schedule itself again in future. 
> 	 */
> spinlock_t              mem_class_lock = SPIN_LOCK_UNLOCKED;
> struct list_head        diff_mem_list = LIST_HEAD_INIT(diff_mem_list);
> 
> struct diff_mem_class   def_mem_class;
> #ifdef CONFIG_MDIFF_PAGECACHE_CLASS
> struct diff_mem_class   pgcache_mem_class;
> #endif
> 
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> atomic_t missact        = ATOMIC_INIT(0);
> atomic_t missinact      = ATOMIC_INIT(0);
> atomic_t missactsub     = ATOMIC_INIT(0);
> atomic_t missinactsub   = ATOMIC_INIT(0);
> #endif
> 
> #ifdef CONFIG_MDIFF_CLASS_NEGATIVE
> 	/* set monitor interval as 1 second */
> int mmcls_monitor_interval   = 1*HZ; 
> struct timer_list mmcls_monitor;
> void class_memory_monitor(unsigned long arg);
> #endif
> 
> #endif
> 
383a422,455
> 
> #ifdef CONFIG_MEMORY_DIFF
> 	/*
> 	* No need to hold the lock since we are at the the very beginning
> 	*/
> 	memset(&def_mem_class, 0, sizeof(struct diff_mem_class)); 
> 	def_mem_class.classid = 0;
> 
> 	/* make sure we will not do kfree for def class */
> 	atomic_set(&(def_mem_class.count),1);
> 	list_add(&def_mem_class.list, &diff_mem_list);
> 
> 	/*
> 	 * this one should be the 1st process.
> 	 * Does any other process will go through the "do_fork"?
> 	 */
> 	mem_class_get( &def_mem_class ); 
> 	current->class = &def_mem_class;
> 
> #ifdef CONFIG_MDIFF_PAGECACHE_CLASS
> 	memset(&pgcache_mem_class, 0, sizeof(struct diff_mem_class));
> 	pgcache_mem_class.classid=1;
> 	/* make sure we will not do kfree for pgcache class */
> 	atomic_set(&(pgcache_mem_class.count),1);
> 	list_add(&pgcache_mem_class.list, &diff_mem_list);
> 
> 	/*
> 	 * this one should be the 1st process.
> 	 * Does any other process will go through the "do_fork"?
> 	 */
> 	mem_class_get(&pgcache_mem_class);
> #endif
> #endif
> 
436a509,512
> #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM)
> 	/* we believe here the max_mapnr has already been set; */
> 	def_mem_class.shrink_threshold = max_mapnr*10/100;
> #endif
586a663,676
> #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM) && defined (CONFIG_MDIFF_CLASS_NEGATIVE)
> 	/*
> 	 * start the timer function to monitor class activeness.
> 	 * The code should be moved to a module later.
> 	 */
> 	do {
> 		struct timer_list* w = &mmcls_monitor;
> 		init_timer(w);
> 		w->expires = jiffies + mmcls_monitor_interval;
> 		w->data = 0;
> 		w->function = class_memory_monitor;
> 		add_timer(w);
> 	}while(0);	
> #endif
602a693,800
> 
> #if defined (CONFIG_MEMORY_DIFF) && defined(CONFIG_MDIFF_CLASS_RECLAIM) && defined(CONFIG_MDIFF_CLASS_NEGATIVE)
> 
> /*
>  * This priority is related to the priority of shrink_cache
>  * Refer mm/vmscan.c
>  */
> #define MAX_SHRINK_PRIORITY   12
> 
> 
> #define _INTERVAL_    2
> #define _MINSCAN_     8
> #define _MAXLAMDA_    5
> 
> /* static inline */
> void mem_class_priority_adjust_temp(struct diff_mem_class* cls)
> {
> 	int lamda, mr;
> 	int scan = atomic_read(&cls->nr_shrinkscan);
> 
> 	atomic_add( scan, &cls->nr_totalscan);
> 
> 	mr= atomic_read(&cls->nr_positivemove)*100/(atomic_read(&cls->nr_totalscan)|1);
> 
> 	atomic_set(&cls->nr_shrinkscan,0);
> 	
> 	lamda = scan/_MINSCAN_;
> 	if (lamda>_MAXLAMDA_)
> 		lamda = _MAXLAMDA_;
> 		
> 	atomic_set( &cls->shrink_priority_adjust, -((mr*lamda)/(_MAXLAMDA_*_INTERVAL_)) );
> }
> 
> /* static inline */
> void mem_class_priority_adjust(struct diff_mem_class* cls)
> {
> 	int lamda, mr;
> 	int pt = atomic_read(&cls->shrink_priority);
> 	int scan = atomic_read(&cls->nr_totalscan);
> 	int pmove=atomic_read(&cls->nr_positivemove);
> 
> 	if (scan>_MINSCAN_) {
> 		
> 		mr= pmove*100/(scan);
> 		
> 		lamda = scan/_MINSCAN_;
> 		if (lamda>_MAXLAMDA_)
> 			lamda = _MAXLAMDA_;
> 			
> 		atomic_add( 1-((mr*lamda)/(_MAXLAMDA_*_INTERVAL_)),
> 							 &cls->shrink_priority);
> 		
> 		if ( atomic_read(&cls->shrink_priority)>MAX_SHRINK_PRIORITY)
> 			atomic_set(&cls->shrink_priority,MAX_SHRINK_PRIORITY);
> 		else if ( atomic_read(&cls->shrink_priority)<-1)
> 			atomic_set(&cls->shrink_priority,-1);
> 	}
> 	else {
> 		/* if there is no page or too less pages scaned,
> 		 * the positive move may from pgfault etc.
> 		 * which makes it also important, since the pgfault is
> 		 * considered in the positive
> 		 * move, we will not add it seperately.
> 		 */
> 		if (pmove>scan){
> 			atomic_dec(&cls->shrink_priority);
> 			if ( atomic_read(&cls->shrink_priority)<-1)
> 				atomic_set(&cls->shrink_priority,-1);
> 		}
> 	}
> 
> 	atomic_set(&cls->nr_totalscan,0);
> 	atomic_set(&cls->nr_positivemove,0);
> 		
> printk("[%d]%d,%d(pmove%d,scan%d,%d->%d) ",cls->classid,
> 		atomic_read(&cls->nr_active),atomic_read(&cls->nr_inactive),
> 		pmove, scan, pt,atomic_read(&cls->shrink_priority));
> }
> 
> void class_memory_monitor(unsigned long arg)
> {
> 	struct timer_list* w = &mmcls_monitor;
> 	struct diff_mem_class* cls;
> 
> 	if (!spin_trylock(&mem_class_lock)) {
> 		/* somebody hold the lock, let's schedule ourselves in future */
> 		init_timer(w);
> 		w->expires = jiffies + 10;
> 		w->data = arg+10;
> 		w->function = class_memory_monitor;
> 		add_timer(w);
> 	}
> 
> 	/* Now we hold the lock. */
> 	list_for_each_entry( cls, &diff_mem_list, list) {
> 		mem_class_priority_adjust(cls);
> 	}
> 	spin_unlock(&mem_class_lock);
> 
> printk("\n");
> 	init_timer(w);
> 	w->expires = jiffies + mmcls_monitor_interval;
> 	w->data = mmcls_monitor_interval;
> 	w->function = class_memory_monitor;
> 	add_timer(w);
> }
> 
> #endif
diff -Naur a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Tue Jul 15 12:42:44 EDT 2003
+++ b/kernel/exit.c	Tue Jul 15 12:42:44 EDT 2003
458a459,478
> 
> #ifdef CONFIG_MEMORY_DIFF
> 	spin_lock(&mm->peertask_lock);
> 	list_del(&tsk->peertask_list);
> 	if (tsk->class){
> 		mem_class_put(tsk->class);
> 		tsk->class=NULL;
> 	}  
> 
> 	/* 
> 	 * Even the tasklist is empty now for this memory,
> 	 * there may be page cache associated with this mm
> 	 */    
> 	if (list_empty(&mm->tasklist)) {
> 		mem_class_get(&def_mem_class);
> 		mm->class=&def_mem_class;
> 	}  
> 	spin_unlock(&mm->peertask_lock);
> #endif  
> 
diff -Naur a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Tue Jul 15 12:42:44 EDT 2003
+++ b/kernel/fork.c	Tue Jul 15 12:42:44 EDT 2003
64a65,75
> #ifdef CONFIG_MEMORY_DIFF
> 	/*
> 	 * Record reserved memory share for class creation
> 	 */
> spinlock_t idx_cls_lock = SPIN_LOCK_UNLOCKED;
> 	/* 0 is for default, and 1 is for page cache class */
> int idx_cls             = 2; 
> 	/* already reserved 10% for default mem class */
> static int mem_reserved = 10; 
> #endif
> 
243a255,266
> #ifdef CONFIG_MEMORY_DIFF
> 	INIT_LIST_HEAD(&tsk->peertask_list);
> 
> 	if (orig->class) {
> 		mem_class_get(orig->class);
> 		tsk->class=orig->class;
> 	}
> 	else {
> 		printk("unexpected null class for process\n");
> 		tsk->class=NULL;
> 	}  
> #endif
373a397,403
> #ifdef CONFIG_MEMORY_DIFF
> 	INIT_LIST_HEAD(&mm->tasklist);
> 	if (current->class)
> 		mem_class_get(current->class);
> 	mm->class=current->class;
> 	mm->peertask_lock = SPIN_LOCK_UNLOCKED;
> #endif
408a439,448
> #ifdef CONFIG_MEMORY_DIFF
> 	/*
> 	 * mm->class can be null and mm->tasklist can be empty
> 	 * BUG_ON( !mm->class||!list_empty(&mm->tasklist));
> 	 */
> 	if (mm->class) { 
> 		mem_class_put(mm->class);
> 		mm->class = NULL;
> 	}
> #endif
518a559,576
> #ifdef CONFIG_MEMORY_DIFF
> 	spin_lock(&mm->peertask_lock);
> 	list_add_tail(&tsk->peertask_list, &mm->tasklist);
> 
> 	if (!tsk->class)
> 		BUG();
>     
> 	if (!mm->class) {
> 		mem_class_get(tsk->class);
> 		mm->class=tsk->class;
> 	}
> 	else {
> 		if (mm->class != tsk->class) {
> 			printk("Mismatch of class for virtual memory space and task\n");
> 		}
> 	}
> 	spin_unlock(&mm->peertask_lock);
> #endif    
1182a1241,1388
> 
> #ifdef CONFIG_MEMORY_DIFF
> 
> int memdiff_redefine(int clsid, int arg)
> {
> 	struct diff_mem_class* cls;
> 	
> 	spin_lock(&mem_class_lock);
> 	cls=NULL;
> 	list_for_each_entry(cls, &diff_mem_list, list) {
> 		if (cls->classid==clsid)
> 		goto found_cls_4;;
> 	}
> 	spin_unlock(&mem_class_lock);		
> 	return -EINVAL;
> 		
> found_cls_4:    
> 	spin_unlock(&mem_class_lock);		
> 	if (arg<=0)
> 		return -EINVAL;
> #ifdef CONFIG_MDIFF_CLASS_RECLAIM
> 	cls->shrink_threshold = arg;;
> #endif		
> 	return 0;
> }
>  /*
>   * Because I have no way to build modules in UML, I hardcode the new 
>   * system call here
>   */
> asmlinkage int sys_memdiffctrl(int type, int arg)
> {
> 	int totalpages;
> 	struct diff_mem_class* cls;
> 	unsigned long active, inactive, free;
> 	int* ret;
> 
> 	printk("systemcall %d, %d\n", type, arg);
> 	switch (type) {
> 	case 0: /* reserve memory for class */
> 	case 3:	 
> 		if (type==0) {
> 			if (arg<=0)
> 				return -EINVAL;
> 			if (arg+mem_reserved>100) {
> 				return -EINVAL;
> 			} 
> 			mem_reserved += arg;
> 			totalpages = max_mapnr;
> 			arg = totalpages * arg /100;
> 		}	
> 		if (arg<=0)
> 			return -EINVAL;
> 		
> 		spin_lock(&idx_cls_lock);
> 		cls = kmalloc(sizeof(struct diff_mem_class), GFP_KERNEL);
> 		if (!cls) {
> 			spin_unlock(&idx_cls_lock);
> 			return -ENOMEM;
> 		}  
> 		memset(cls, 0, sizeof(struct diff_mem_class));
> 
> 		cls->classid = idx_cls;
> 		idx_cls++;
> 		
> 		spin_unlock(&idx_cls_lock);
> 
> 		atomic_set(&(def_mem_class.count),1);
> 
> 		/*
> 		 * because some pages are not counted in our page-classes,
> 		 * the actual threshold should be lower,
> 		 * Here, we simply assume that 10% of the pages must be for
> 		 * other resources like slab, socket etcs.
> 		 */
> #ifdef CONFIG_MDIFF_CLASS_RECLAIM
> 		cls->shrink_threshold = arg;;
> #endif		
> 
> 		spin_lock(&mem_class_lock);
> 		list_add(&cls->list, &diff_mem_list);
> 		spin_unlock(&mem_class_lock);
> 		return cls->classid;
> 	case 1: /* set class for task */
> 		if (arg<0 || arg>=idx_cls)
> 			return -EINVAL;
> 		spin_lock(&mem_class_lock);
> 		cls=NULL;
> 		list_for_each_entry(cls, &diff_mem_list, list) {
> 			if (cls->classid==arg)
> 			goto found_cls_1;
> 		}
> 		spin_unlock(&mem_class_lock);
> 		return -EINVAL;
> found_cls_1:    
> 		spin_unlock(&mem_class_lock);
> 		if (cls==current->class)
> 			return 0;
> 
> 		if (current->class)
> 			mem_class_put(current->class);
> 		spin_lock(&current->active_mm->peertask_lock);
> 
> 		mem_class_get(cls);
> 		current->class = cls;
> 
> 		if (current->active_mm->class!=cls) {
> 			mem_class_put(current->active_mm->class);
> 			mem_class_get(cls);
> 			current->active_mm->class=cls;
> 		}
> 		spin_unlock(&(current->active_mm->peertask_lock));
> 		return 0;
> 	case 2:
> 		/*
> 		 * Retrieve class info, assume the buffer is enough to
> 		 * to hold the data. No buffer boundary check at this moment.
> 		 */
> 		ret = (int*)arg;
> 
> 		get_zone_counts(&active, &inactive,&free);
> 		put_user(active, ret);
> 		ret++;
> 		put_user(inactive, ret);
> 		ret++;
> 		put_user(free, ret);
> 		ret++;
> 
> 		spin_lock(&mem_class_lock);
> 		cls=NULL;
> 		list_for_each_entry(cls, &diff_mem_list, list) {
> 			put_user(cls->classid,ret);
> 			ret++;
> 			put_user(atomic_read(&cls->nr_total),ret);
> 			ret++;
> 			put_user(atomic_read(&cls->nr_active),ret);
> 			ret++;
> 			put_user(atomic_read(&cls->nr_inactive),ret);
> 			ret++;
> 		}
> 		spin_unlock(&mem_class_lock);
> 		return (ret-(int*)arg);
> 	default:
> 		return -EINVAL;
> 	}
> 	return 0; 
> }
>   
> #endif
diff -Naur a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Tue Jul 15 12:42:44 EDT 2003
+++ b/mm/memory.c	Tue Jul 15 12:42:44 EDT 2003
diff -Naur a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Tue Jul 15 12:42:45 EDT 2003
+++ b/mm/page_alloc.c	Tue Jul 15 12:42:45 EDT 2003
447a448,464
> #ifdef CONFIG_MEMORY_DIFF
> 	/*
> 	 * At this moment, the page is not in any list so we can
> 	 * safely remove its class info.
> 	 * We cannot do this job at the moment of page_remove_rmap
> 	 * or remove_from_page_cache since the page may still be in
> 	 * LRU list at that moment.
> 	 */
> 	page_class_lock(page);
> 	if (page->class) {
> 		atomic_dec(&page->class->nr_total);
> 		mem_class_put(page->class);
> 	}
> 	page->class=NULL;
> 	page_class_unlock(page);
> #endif
> 
diff -Naur a/mm/rmap.c b/mm/rmap.c
--- a/mm/rmap.c	Tue Jul 15 12:42:45 EDT 2003
+++ b/mm/rmap.c	Tue Jul 15 12:42:45 EDT 2003
181a182,248
> #ifdef CONFIG_MEMORY_DIFF
> 		do{
> 			struct mm_struct* mm =ptep_to_mm(ptep);
> 			/*
> 			 * At the beginning, I think that mm must be associated with a
> 			 * task at this moment, but it is not!
> 			 * I have not investigated the reason.
> 			 * if (list_empty(&mm->tasklist)) 
> 			 *	printk("mm has no task associated with it mm=%p\n",mm);
> 		         */
>   
> 			/*
> 			 * If the task terminates, the exit_mm will remove it from
> 			 * the mm->tasklist. We can reset page->task only at the time of
> 			 * page_remove_rmap. But it is possible that the task is not
> 			 * in the list but the page_remove_rmap is not called yet.
> 			 * (because multiple tasks share mm_struct)
> 			 * That's the reason we can associate mm_struct instead of 
> 			 * task_struct with stryct page. (Currently not provided yet)
> 			 */
> 			
> 			BUG_ON(!mm->class);
> 			
> 			/*
> 			 * Notice we borrow the pte_chain_lock bit to protect the page's
> 			 * class, so we should not call page_class_lock here.
> 			 */
> 			if (page->class != mm->class) {
> 				if (!page->class) {
> 					atomic_inc(&mm->class->nr_total);
> 					/* Here , we have not checked the Zone'lru lock, so we can still miss or overact */
> 					if (PageActive(page)) {
> 						atomic_inc(&mm->class->nr_active);
> 						//printk("rmap: repair active page\n");
> 					}	
> 					else if(PageLRU(page)) {
> 						atomic_inc(&mm->class->nr_inactive);
> 						//printk("rmap: repair inactive page\n");
> 					}	
> 						
> 				}
> 			        else {
> 					atomic_dec(&page->class->nr_total);
> 					atomic_inc(&mm->class->nr_total);
> 					if (PageActive(page)) {
> 						atomic_dec(&page->class->nr_active);
> 						atomic_inc(&mm->class->nr_active);
> 					}
> 					else if(PageLRU(page)) {
> 						atomic_dec(&page->class->nr_inactive);
> 						atomic_inc(&mm->class->nr_inactive);
> 					}	
> 					mem_class_put(page->class);
> 				}
> 				page->class = mm->class;
> 				spin_lock(&mm->peertask_lock);
> 				if (!list_empty(&mm->tasklist)) {
> 					struct task_struct* tsk = list_entry(mm->tasklist.next,struct task_struct, peertask_list);
> 					page->pid = tsk->pid;
> 				}
> 				else
> 					page->pid = -1;
> 				spin_unlock(&mm->peertask_lock);
> 				mem_class_get(page->class);
> 			}  
> 		}while(0);   
> #endif
268a336,399
> #ifdef CONFIG_MEMORY_DIFF
> 				/*
> 				 * All ptep for one page are organized as a list of "pte_chain".
> 				 * each pte_chain includes #NRPTE entries. Entries are
> 				 * filled from the end to the beginning so simply checking
> 				 * the first entry can show whether there is still space
> 				 * in this pte_chain.
> 				 * Our algorithm try to make sure that the page->mm always
> 				 * corresponding to the last entry of the last item of the
> 				 * pte_chain list (or pte.direct. notes that when pte.direct
> 				 * is convert to chain list, it will be the last entry of the
> 				 * only pte_chain)
> 				 * Notice we borrow the pte_chain_lock bit to protect the page's
> 				 * class, so we should not call page_class_lock here.
> 				 */
> 				if ( page->pte.chain  /* there are still some mm maps this page */
> 					/* last entry of last item */
> 				    && (pc!=start && !pte_chain_next(pc)) && i==NRPTE-1 ){
> 					pte_t * ptep;
> 					struct mm_struct* mm;
> 
> 					BUG_ON(!pc->ptes[i]);
> 					ptep = rmap_ptep_map(pc->ptes[i]);
> 					mm =ptep_to_mm(ptep);
> 					BUG_ON(!mm->class);
> 					if (page->class != mm->class) {
> 						if (!page->class) {
> 							atomic_inc(&mm->class->nr_total);
> 							if (PageActive(page)) {
> 								atomic_inc(&mm->class->nr_active);
> 								//printk("rmap: repair inactive page\n");
> 							}	
> 							else if(PageLRU(page)) {
> 								atomic_inc(&mm->class->nr_inactive);
> 								//printk("rmap: repair active page\n");
> 							}	
> 						}
> 					        else {
> 							atomic_dec(&page->class->nr_total);
> 							atomic_inc(&mm->class->nr_total);
> 							if (PageActive(page)) {
> 								atomic_dec(&page->class->nr_active);
> 								atomic_inc(&mm->class->nr_active);
> 							}
> 							else if(PageLRU(page)) {
> 								atomic_dec(&page->class->nr_inactive);
> 								atomic_inc(&mm->class->nr_inactive);
> 							}	
> 							mem_class_put(page->class);
> 						}
> 						page->class = mm->class;
>             spin_lock(&mm->peertask_lock);
>             if (!list_empty(&mm->tasklist)) {
>               struct task_struct* tsk = list_entry(mm->tasklist.next,struct task_struct, peertask_list);
>               page->pid = tsk->pid;
>             }
>             else
>               page->pid = -1;
>             spin_unlock(&mm->peertask_lock);
> 						mem_class_get(page->class);
> 					}
> 					rmap_ptep_unmap(ptep);
> 				}  
> #endif
diff -Naur a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Tue Jul 15 12:42:45 EDT 2003
+++ b/mm/vmscan.c	Tue Jul 15 12:42:45 EDT 2003
262a263,270
> #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM)
> 		if (!MCLS_readyshrink(page->class)) {
> 			pte_chain_unlock(page);
> 			/* should we throw it back to the active list?*/
> 			goto keep_locked;
> 		}
> #endif		
> 
455a464
> 	LIST_HEAD(hold);
458a468,470
> #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM)
> 	int nr_pass;
> #endif
476a489,494
> #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM)
> 		nr_pass = zone->nr_inactive;
> 		while (nr_pass>0 && nr_scan<nr_to_process &&
> 				!list_empty(&zone->inactive_list)) {
> 			nr_pass--;
> #else
478a497
> #endif
487a507,519
> #if defined  (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM)
> 			if (page->class && !MCLS_readyscan(page->class) && !MCLS_readyshrink(page->class)) {
> 				/*
> 				 * instead of add back to inactive list, which add it to the head, we may leave it here at the tail				
> 				 *
> 				 * SetPageLRU(page);
> 				 * list_add(&page->lru, &zone->inactive_list);
> 				 */				
> 				list_add(&page->lru, &hold);
> 				continue;
> 			}
> 			nr_scan++;
> #endif
496a529,537
> #ifdef CONFIG_MEMORY_DIFF
> 			if (page->class) {
> 				atomic_dec(&page->class->nr_inactive);
> 			}
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING        
> 			else
> 				atomic_inc(&missinactsub);
> #endif        
> #endif
499a541,549
> #if defined  (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM)
> 		while (!list_empty(&hold)) {
> 			page = list_entry(hold.next, struct page, lru);
> 			if (TestSetPageLRU(page))
> 				BUG();
> 			list_del(&page->lru);
> 			list_add_tail(&page->lru, &zone->inactive_list);
> 		}
> #endif
501c551
< 
---
> 		
525a576
> 				
571a623,625
> #if defined (CONFIG_MEMORY_DIFF) && defined(CONFIG_MDIFF_CLASS_RECLAIM)
> 	int nr_pass;
> #endif
575a630,648
> #if defined (CONFIG_MEMORY_DIFF) && defined(CONFIG_MDIFF_CLASS_RECLAIM)
> 	/*
> 	 *It seems that the pass number here will cause gread number of
> 	 * pages of underutilzied class be moved while at the same time,
> 	 * not enough pages of overutilzed class refill
> 	 */
> 	/* 
> 		nr_pass = zone->nr_active >> priority;
> 		if (nr_pass < nr_pages)
> 			nr_pass = nr_pages;
> 	 */
> 	nr_pass = zone->nr_active; 
> 	/*
> 	 * Because nr_pass <= listlength of zone->active_list, there
> 	 * is no need to check list_empty. Note nr_pass is assigned after
> 	 * the lru lock hold.
> 	 */
> 	while (nr_pages && nr_pass>0 && !list_empty(&zone->active_list)) {
> #else
576a650
> #endif
589a664,672
> #ifdef CONFIG_MEMORY_DIFF
> 			if(page->class) {
> 				atomic_dec(&page->class->nr_active);
> 			}
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> 			else
> 				atomic_inc(&missactsub);
> #endif
> #endif
590a674,685
> #if defined (CONFIG_MEMORY_DIFF) && defined(CONFIG_MDIFF_CLASS_RECLAIM)
> 		/*
> 		 * If we still only use nr_pages and the list emptiness as indicators
> 		 * for while loop, then if the page_count of some page !=0 => list
> 		 * will never empty, and nr_pages may never reach zero.
> 		 * So we need other mechanisms which is the nr_pass.
> 		 */
> 		nr_pass--;
> 		if (MCLS_readyrefill(page->class)) {
> 			nr_pages--;
> 		}
> #else
591a687
> #endif
666a763,771
> #ifdef CONFIG_MEMORY_DIFF
> 		if(page->class) {
> 			atomic_inc(&page->class->nr_inactive);
> 		}	
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> 		else
> 			atomic_inc(&missinact);
> #endif
> #endif
694a800,808
> #ifdef CONFIG_MEMORY_DIFF
> 		if(page->class) {
> 			atomic_inc(&page->class->nr_active);
> 		}
> #ifdef CONFIG_MDIFF_DEBUG_BEANCOUNTING
> 		else
> 			atomic_inc(&missinact);
> #endif
> #endif
720a835,845
> #if defined  (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM)
> 	/*
> 	 * The purpose of this code is to set the shrink/refill bits for
> 	 * each memory class
> 	 */
> 	int nr_active = 0;
> 	int nr_inactive=0;
> 	int nr_candidates=0;
> 	int adjustratio;
> 	struct diff_mem_class* cls;
> #endif
734a860,901
> 
> #if defined (CONFIG_MEMORY_DIFF) && defined (CONFIG_MDIFF_CLASS_RECLAIM)
> 	/*
> 	 * Go through all classes to determine which class's pages are
> 	 * candidate for refill/reclaim
> 	 */
> 	spin_lock(&mem_class_lock);
> 
> 	list_for_each_entry( cls, &diff_mem_list, list) {	
> 		if (atomic_read(&cls->nr_total)>cls->shrink_threshold ) {
> 		/* there is a bug which causes the cls->nr_inactive is negative */
> 			if (atomic_read(&cls->nr_active)>0)
> 				nr_active += atomic_read(&cls->nr_active);
> 			if ( atomic_read(&cls->nr_inactive)>0)
> 				nr_inactive += atomic_read(&cls->nr_inactive);
> 			nr_candidates=1;
> 			MCLS_set_readyrefill(cls);
> 			MCLS_set_readyshrink(cls);
> 			MCLS_set_readyscan(cls);
> 		}
> 		else {
> 			MCLS_reset_readyrefill(cls);
> 			MCLS_reset_readyshrink(cls);
> 			MCLS_reset_readyscan(cls);
> 		}
> 	}
> 	 /* If nobody exceeds threshold and nobody negative enough for shrink */
> 	if (!nr_candidates) {
> 		list_for_each_entry( cls, &diff_mem_list, list) {
> 			MCLS_set_readyrefill(cls);
> 			MCLS_set_readyshrink(cls);
> 			MCLS_set_readyscan(cls);
> 		}
> 	}
> 	else {
> 		adjustratio = (unsigned long)nr_pages * nr_active /
> 				((nr_inactive | 1) * 2);
> 		atomic_add(adjustratio-ratio-1, &zone->refill_counter);
> 	}
> 	spin_unlock(&mem_class_lock);
> #endif
>