diff -Nur -x.svn linux-2.6.16-orig/arch/sh/mm/init.c linux-2.6.16/arch/sh/mm/init.c --- linux-2.6.16-orig/arch/sh/mm/init.c 2008-01-23 15:01:04.000000000 +0900 +++ linux-2.6.16/arch/sh/mm/init.c 2008-01-08 09:52:36.000000000 +0900 @@ -230,6 +230,11 @@ int codesize, reservedpages, datasize, initsize; int tmp; extern unsigned long memory_start; +#ifdef CONFIG_CABI_MEM + extern unsigned int cabi_mem_total_mem_kb; + extern unsigned int cabi_mem_total_page; + extern unsigned int cabi_mem_reserved_pages; +#endif #ifdef CONFIG_MMU high_memory = (void *)__va(MAX_LOW_PFN * PAGE_SIZE); @@ -274,6 +279,12 @@ datasize >> 10, initsize >> 10); +#ifdef CONFIG_CABI_MEM + cabi_mem_total_mem_kb = max_mapnr << (PAGE_SHIFT-10); + cabi_mem_total_page = max_mapnr; + cabi_mem_reserved_pages = reservedpages; +#endif + p3_cache_init(); } diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/examples/mem/cb_bind.c linux-2.6.16/drivers/cabi/examples/mem/cb_bind.c --- linux-2.6.16-orig/drivers/cabi/examples/mem/cb_bind.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/examples/mem/cb_bind.c 2007-11-08 11:06:41.000000000 +0900 @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +void usage(void) { + printf ("Usage: cabi_bind [object_id] [pid]\n"); + printf ("--------------------------------------------------\n"); + printf (" [object_id] : cabi object id\n"); + printf (" [pid] : bind process id\n"); +} + +int main (int argc, char *argv[]) +{ + int ret; + pid_t pid; + + unsigned long cabi_id; + + if (argc != 3) { + usage(); + return 0; + } + + /* set accounting object id */ + cabi_id = atol (argv[1]); + pid = (pid_t) atoi (argv[2]); + + switch (cabi_id) { + case 0: + printf ("object id is 0.\n"); + return 1; + case 1: + printf ("[object_id]=1 is only for overload."); + return 1; + default: + printf ("cabi bind pid\n"); + break; + } + + // Attach this process to the resource set + if ((ret = cabi_account_bind_pid(cabi_id, pid)) != CABI_SUCCESS) { + printf ("cabi_account_bind_pid() faild.(%d)\n", ret); + } else { + printf ("cabi_account_bind_pid: object_id(%d) pid[%d]\n", + (int)cabi_id, pid); + } + + return 0; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/examples/mem/cb_bind_pgid.c linux-2.6.16/drivers/cabi/examples/mem/cb_bind_pgid.c --- linux-2.6.16-orig/drivers/cabi/examples/mem/cb_bind_pgid.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/examples/mem/cb_bind_pgid.c 2007-12-19 16:54:24.000000000 +0900 @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +void usage(void) { + printf ("Usage: cabi_bind [object_id] [pgid]\n"); + printf ("--------------------------------------------------\n"); + printf (" [object_id] : cabi object id\n"); + printf (" [pgid] : bind process group id\n"); +} + +int main (int argc, char *argv[]) +{ + int ret; + pid_t pgid; + + unsigned long cabi_id; + + if (argc != 3) { + usage(); + return 0; + } + + /* set accounting object id */ + cabi_id = atol (argv[1]); + pgid = (pid_t) atoi (argv[2]); + + switch (cabi_id) { + case 0: + printf ("object id is 0.\n"); + return 1; + case 1: + printf ("[object_id]=1 is only for overload."); + return 1; + default: + printf ("cabi bind pid\n"); + break; + } + + // Attach this process to the resource set + if ((ret = cabi_account_bind_pgid(cabi_id, pgid)) != CABI_SUCCESS) { + printf ("cabi_account_bind_pid() faild.(%d)\n", ret); + } else { + printf ("cabi_account_bind_pid: object_id(%d) pid[%d]\n", + (int)cabi_id, pgid); + } + + return 0; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/examples/mem/cb_create.c linux-2.6.16/drivers/cabi/examples/mem/cb_create.c --- linux-2.6.16-orig/drivers/cabi/examples/mem/cb_create.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/examples/mem/cb_create.c 2007-12-05 12:59:11.000000000 +0900 @@ -0,0 +1,67 @@ +/* + * This is sample program for CABI system. + * create memory accounting object. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define CABI_DEBUG +#include +#include +#include + +void usage(void) { + printf ("cabi_create:\n"); + printf (" Usage: cabi_mem_create unit limit\n"); + printf ("--------------------------------------------------\n"); + printf (" unit : unit of memory size \n"); + printf (" 1:%% 2:BYTE 3:KB 4:MB 5:GB \n"); + printf (" limit : max allocatable memory size \n"); +} + +int main (int argc, char *argv[]) +{ + int ret; + struct cabi_uaccount ucabi; + struct mem_uaccount umcabi; + + printf ("Create CABI object...\n"); + + memset(&ucabi, 0x00, sizeof(struct cabi_uaccount)); + memset(&umcabi, 0x00, sizeof(struct mem_uaccount)); + + ucabi.type = CABI_MEM; + ucabi.res.mem = &umcabi; + + /* set accounting object id */ + switch (argc) { + case 3: + umcabi.mem_unit = atoi (argv[1]); + umcabi.user_limit = atoi (argv[2]); + break; + default: + usage(); + return 1; + } + + + if ((ret = cabi_account_create (&ucabi)) == CABI_SUCCESS) { + printf ("account create. object_id [%d]\n", + (int)ucabi.cabi_id); + } else { + printf ("cabi_account_create failed.(%d)\n", ret); + } + + if (ucabi.cabi_id == 0) { + printf ("cabi_account_create faild\n"); + return 1; + } + + return 0; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/examples/mem/cb_destroy.c linux-2.6.16/drivers/cabi/examples/mem/cb_destroy.c --- linux-2.6.16-orig/drivers/cabi/examples/mem/cb_destroy.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/examples/mem/cb_destroy.c 2007-11-05 15:11:13.000000000 +0900 @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +void usage(void) { + printf ("Usage: cabi_destroy [object_id]\n"); + printf ("--------------------------------------------------\n"); + printf (" [object_id] : cabi object id\n"); +} + +int main (int argc, char *argv[]) +{ + int ret; + unsigned long cabi_id; + + if (argc != 2) { + usage(); + return 0; + } + + /* set the object id */ + cabi_id = atol (argv[1]); + + if ((ret = cabi_account_destroy(cabi_id)) != CABI_SUCCESS) { + printf ("destroy faild.(%d)\n", ret); + } else { + printf ("destroy succeed.\n"); + } + + return 1; + + +} + + diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/examples/mem/cb_exec_bind.c linux-2.6.16/drivers/cabi/examples/mem/cb_exec_bind.c --- linux-2.6.16-orig/drivers/cabi/examples/mem/cb_exec_bind.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/examples/mem/cb_exec_bind.c 2007-11-05 15:11:13.000000000 +0900 @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +extern int errno; + +void usage(void) { + printf ("Usage: cabi_exec_bind [object_id] [program...]\n"); + printf ("--------------------------------------------------\n"); + printf (" [object_id] : cabi object id\n"); + printf (" [program...] : execute program\n"); +} + +int main (int argc, char *argv[]) +{ + unsigned long cabi_id; + pid_t pid; + int status; + int ret; + + if (argc < 3) { + usage(); + return 0; + } + + cabi_id = atoi (argv[1]); + + if ((pid = fork()) == -1) { + perror("fork()"); + return 1; + } else if (pid > 0) { + if ((ret = cabi_account_bind_pid(cabi_id, pid)) != CABI_SUCCESS) { + printf("exec_bind : cabi_account_bind_pid: faild. (%d)\n", ret); + return 1; + } else { + printf("exec_bind : cabi_account_bind_pid: Account ID(%d)[%d]\n", + (int)cabi_id, pid); + } + waitpid(-1, &status, WNOHANG); + } else { + if (execvp(argv[2], &argv[2]) == -1) { + perror("execv"); + return 1; + } + } + + return 0; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/examples/mem/cb_get.c linux-2.6.16/drivers/cabi/examples/mem/cb_get.c --- linux-2.6.16-orig/drivers/cabi/examples/mem/cb_get.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/examples/mem/cb_get.c 2007-11-28 19:18:13.000000000 +0900 @@ -0,0 +1,68 @@ +/* + * This is sample program for CABI system. + * create accounting object. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +void usage(void) { + printf ("Usage: cabi_get [object_id]\n"); + printf ("--------------------------------------------------\n"); + printf (" [object_id] : cabi object id\n"); +} + +int main (int argc, char *argv[]) +{ + struct cabi_uaccount ucabi; + struct mem_uaccount umcabi; + unsigned long cabi_id; + int ret; + + if (argc != 2) { + usage(); + return 0; + } + + /* set accounting object id */ + cabi_id = atoi (argv[1]); + if (cabi_id == 0) { + printf("object id is 0\n"); + return 1; + } + + memset(&ucabi, 0x00, sizeof(struct cabi_uaccount)); + memset(&umcabi, 0x00, sizeof(struct mem_uaccount)); + ucabi.res.mem = &umcabi; + + if ((ret = cabi_account_get (cabi_id, &ucabi)) != CABI_SUCCESS) { + if (ret == CABI_ENOEXIST) { + printf("object id(%ld) not found.\n", cabi_id); + } else { + printf("cabi_account_get failed.(%d)\n", ret); + } + return 1; + } + + printf ("id: %d\n", (int)ucabi.cabi_id); + printf ("op_flag: %x\n", umcabi.op_flag); + printf ("obj_flag: %x\n", umcabi.obj_flag); + printf ("mem_unit: %x\n", umcabi.mem_unit); + printf ("ulimit: %ld\n", umcabi.user_limit); + printf ("uwarn: %ld\n", umcabi.user_warn); + printf ("flimit: %ld\n", umcabi.file_limit); + printf ("fwarn: %ld\n", umcabi.file_warn); + printf ("reclaim_pages: %ld\n", umcabi.reclaim_pages); + printf ("sig_pid: %d\n", (int)umcabi.signal.pid); + + return 0; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/examples/mem/cb_set.c linux-2.6.16/drivers/cabi/examples/mem/cb_set.c --- linux-2.6.16-orig/drivers/cabi/examples/mem/cb_set.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/examples/mem/cb_set.c 2007-12-11 14:44:51.000000000 +0900 @@ -0,0 +1,99 @@ +/* + * This is sample program for CABI system. + * create accounting object. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +void usage(void) { + printf ("cabi_set:\n"); + printf (" Usage: cabi_set id opflag objflag ulimit uwarn flimit fwarn [reclaim sig_pid sig_no]\n"); + printf ("--------------------------------------------------\n"); + printf (" id : cabi object id\n"); + printf (" opflag : operation flag\n"); + printf (" 1:NONE 2:SIGNAL 4:SELECT 8:RECLAIM\n"); + printf (" objflag : AO flag 1:Allow force binding\n"); + printf (" unit : unit of memory size\n"); + printf (" 1:%% 2:BYTE 3:KB 4:MB 5:GB\n"); + printf (" ulimit : user memory limitation (kbyte)\n"); + printf (" uwarn : user memory warnning (kbyte)\n"); + printf (" flimit : file cache limitation (kbyte)\n"); + printf (" fwarn : file cache warnning (kbyte)\n"); + printf (" reclaim : reclaiming pages\n"); + printf (" sig_pid : PID for sending signal\n"); + printf (" sig_no : signal number\n"); +} + +int main (int argc, char *argv[]) +{ + int ret; + struct cabi_uaccount ucabi; + struct mem_uaccount umcabi; + unsigned long cabi_id, opflag, objflag, unit, ulimit, uwarn, + flimit, fwarn; + unsigned long reclaim = 0, sig_pid = 0, sig_no = 0; + pid_t pid; + + pid = 0; + /* set accounting object id */ + switch (argc) { + case 12: + reclaim = atoi (argv[9]); + sig_pid = atoi (argv[10]); + sig_no = atoi (argv[11]); + /* fall through */ + case 9: + cabi_id = atoi (argv[1]); + opflag = atol (argv[2]); + objflag = atol (argv[3]); + unit = atol (argv[4]); + ulimit = atol (argv[5]); + uwarn = atol (argv[6]); + flimit = atol (argv[7]); + fwarn = atol (argv[8]); + break; + default: + usage(); + return 1; + } + printf ("Setting...\n"); + + memset(&ucabi, 0x00, sizeof(struct cabi_uaccount)); + memset(&umcabi, 0x00, sizeof(struct mem_uaccount)); + ucabi.res.mem = &umcabi; + + ucabi.type = CABI_MEM; + umcabi.op_flag = opflag; + umcabi.obj_flag = objflag; + umcabi.mem_unit = unit; + umcabi.user_limit = ulimit; + umcabi.user_warn = uwarn; + umcabi.file_limit = flimit; + umcabi.file_warn = fwarn; + + if (reclaim) + umcabi.reclaim_pages = reclaim; + if (sig_pid) + umcabi.signal.pid = sig_pid; + if (sig_no) + umcabi.signal.sig = sig_no; + + if ((ret = cabi_account_set (cabi_id, &ucabi)) == CABI_SUCCESS) { + printf ("account set. object_id (%d)\n", (int)cabi_id); + } else { + printf ("cabi_id = %ld : cabi_account_set failed. (%d)\n", cabi_id, ret); + return 1; + } + + return 0; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/examples/mem/cb_unbind.c linux-2.6.16/drivers/cabi/examples/mem/cb_unbind.c --- linux-2.6.16-orig/drivers/cabi/examples/mem/cb_unbind.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/examples/mem/cb_unbind.c 2007-11-05 15:11:13.000000000 +0900 @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +void usage(void) { + printf ("Usage: cabi_unbind [pid]\n"); + printf ("--------------------------------------------------\n"); + printf (" [pid] : unbind process id\n"); +} + +int main (int argc, char *argv[]) +{ + int ret; + pid_t pid; + + if (argc != 2) { + usage(); + return 0; + } + + pid = (pid_t) atoi (argv[1]); + printf ("cabi unbind pid: %d\n", pid); + + // Dettach this process from accounting obiect + if ((ret = cabi_account_unbind(pid)) != CABI_SUCCESS) { + printf ("unbind faild.(%d)\n", ret); + } else { + printf ("unbaind succeed.\n"); + } + + return 0; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/examples/mem/Makefile linux-2.6.16/drivers/cabi/examples/mem/Makefile --- linux-2.6.16-orig/drivers/cabi/examples/mem/Makefile 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/examples/mem/Makefile 2008-01-23 16:46:12.000000000 +0900 @@ -0,0 +1,19 @@ +KERNELDIR = ../../../.. +CC = $(CROSS_COMPILE)gcc -g +CFLAGS = -O2 -Wall +LIBS = -L$(KERNELDIR)/drivers/cabi/lib -lcabi +INCLUDES = -I$(KERNELDIR)/include + +SOURCES = $(wildcard *.c) +OBJS = $(SOURCES:.c=.o) +PROGS = $(subst cb_,cabi_,$(basename $(OBJS))) + +all: $(OBJS) + rename cb_ cabi_ cb_*.o + rename .o '' *.o + +%.o : %.c + $(CC) -o $@ $< $(CFLAGS) $(INCLUDES) $(LIBS) + +clean: + rm -rf $(OBJS) $(PROGS) *~ diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/mem/Makefile linux-2.6.16/drivers/cabi/mem/Makefile --- linux-2.6.16-orig/drivers/cabi/mem/Makefile 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/mem/Makefile 2007-11-02 17:02:30.000000000 +0900 @@ -0,0 +1,16 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +obj-$(CONFIG_CABI_MEM) += mem_account.o +obj-$(CONFIG_CABI_MEM) += mem_debug.o +obj-$(CONFIG_CABI_MEM) += mem_drv.o +obj-$(CONFIG_CABI_MEM) += mem_mng.o +obj-$(CONFIG_CABI_MEM) += mem_ops.o +obj-$(CONFIG_CABI_MEM) += mem_procfs.o +obj-$(CONFIG_CABI_MEM) += mem_reclaim.o diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/mem/mem_account.c linux-2.6.16/drivers/cabi/mem/mem_account.c --- linux-2.6.16-orig/drivers/cabi/mem/mem_account.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/mem/mem_account.c 2008-01-23 10:41:18.000000000 +0900 @@ -0,0 +1,450 @@ +/* + * drivers/cabi/mem/mem_account.c + * + * CABI -- Common Accounting and Blocking Interfaces. + * + * Copyright (C) Lineo solutions, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +#include +#include +#include +#else +#include +#include +#include +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#endif + +#include +#include +#include + +unsigned int cabi_mem_total_mem_kb; +unsigned int cabi_mem_total_page; +unsigned int cabi_mem_reserved_pages; + +static unsigned long +conv_to_pfn(cabi_mem_unit_t mem_unit, unsigned long val) +{ + unsigned long coef; + + if (mem_unit == CABI_MEM_UNIT_PFN) + return val; + + if (mem_unit == CABI_MEM_UNIT_PERCENT) + return (cabi_mem_total_page * val / 100); + + switch (mem_unit) { + case CABI_MEM_UNIT_BYTE: + coef = 1; + break; + case CABI_MEM_UNIT_KBYTE: + coef = 1 << 10; + break; + case CABI_MEM_UNIT_MBYTE: + coef = 1 << 20; + break; + case CABI_MEM_UNIT_GBYTE: + coef = 1 << 30; + break; + default: + return 0; + } + + return PFN_UP(val * coef); +} + +/* + * Set parameters to the memory account. + * Some parameters are set default value automatically, + * when these are omitted. + */ +static int +mem_set (cabi_account_t cabi, cabi_uaccount_t ucabi) +{ + struct mem_uaccount umem; + struct mem_param pm; + unsigned long pfn; + + ENTER; + + /* parameter copy */ + if (copy_from_user(&umem, ucabi->res.mem, sizeof (umem))) + return CABI_EINVAL; + + /* Default operation is reclaiming. */ + if (!umem.op_flag) + pm.op_flag = CABI_MEM_OP_RECLAIM; + else if (umem.op_flag & CABI_MEM_OP_NONE) + pm.op_flag = CABI_MEM_OP_NONE; + else + pm.op_flag = umem.op_flag & CABI_MEM_OPS_MASK; + + /* Set object flag */ + if (umem.obj_flag) + pm.obj_flag = umem.obj_flag & CABI_MEM_OBJ_MASK; + else + pm.obj_flag = 0; + + /* Set user memory limitation */ + pfn = conv_to_pfn(umem.mem_unit, umem.user_limit); + if(!pfn) + return CABI_EINVAL; + pm.user_limit = pfn; + + /* Set file cache limitation */ + if (!umem.file_limit) + pm.file_limit = pm.user_limit; + else { + pfn = conv_to_pfn(umem.mem_unit, umem.file_limit); + if (!pfn) + return CABI_EINVAL; + pm.file_limit = pfn; + } + + /* Set user memory threshold */ + if (!umem.user_warn) + pm.user_warn = pm.user_limit * DEF_WARNING_RATIO / 100; + else { + pfn = conv_to_pfn(umem.mem_unit, umem.user_warn); + if (!pfn) + return CABI_EINVAL; + pm.user_warn = pfn; + } + + /* Set file cache threshold */ + if (!umem.file_warn) + pm.file_warn = pm.file_limit * DEF_WARNING_RATIO / 100; + else { + pfn = conv_to_pfn(umem.mem_unit, umem.file_warn); + if (!pfn) + return CABI_EINVAL; + pm.file_warn = pfn; + } + + if (!umem.reclaim_pages) + pm.reclaim_pages = DEF_RECLAIM_PAGES; + else + pm.reclaim_pages = umem.reclaim_pages; + + /* Set signal parameter */ + if (umem.op_flag & CABI_MEM_OP_SIGNAL) + memcpy(&pm.signal, &umem.signal, sizeof(pm.signal)); + else + memset(&pm.signal, 0x00, sizeof(pm.signal)); + + cabi_debug ("mem_param\n" \ + "op_flag %d\n" \ + "obj_flag %d\n" \ + "u_limit %ld u_warn %ld\n" \ + "f_limit %ld f_warn %ld\n" \ + "reclaim_pages %ld\n" \ + "sig_pid %d sig_nr %d sig_flag %d\n", + pm.op_flag, + pm.obj_flag, + pm.user_limit, + pm.user_warn, + pm.file_limit, + pm.file_warn, + pm.reclaim_pages, + pm.signal.pid, + pm.signal.sig, + pm.signal.flag + ); + + memcpy(cabi->res.mem->pm, &pm, sizeof(pm)); + + /* reset peak value */ + cabi->res.mem->user_max = 0; + cabi->res.mem->file_max = 0; + + EXIT; + + return CABI_SUCCESS; /* success */ +} + + +/* + * Get parameters from the memory account + */ +static int +mem_get (cabi_account_t cabi, cabi_uaccount_t ucabi) +{ + struct mem_uaccount umem; + mem_param_t pm = cabi->res.mem->pm; + + ENTER; + + umem.mem_unit = CABI_MEM_UNIT_PFN; + umem.op_flag = pm->op_flag; + umem.obj_flag = pm->obj_flag; + umem.user_limit = pm->user_limit; + umem.file_limit = pm->file_limit; + umem.user_warn = pm->user_warn; + umem.file_warn = pm->file_warn; + umem.reclaim_pages = pm->reclaim_pages; + umem.signal.pid = pm->signal.pid; + umem.signal.sig = pm->signal.sig; + umem.signal.flag = pm->signal.flag; + + /* parameter copy */ + if (copy_to_user(ucabi->res.mem, &umem, sizeof (umem))) + return CABI_EINVAL; + + EXIT; + + return CABI_SUCCESS; +} + +unsigned long +map_to_pfn(struct vm_area_struct *vma, unsigned long address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + struct page *page; + + pgd = pgd_offset(vma->vm_mm, address); + if (!pgd_present(*pgd)) + return 0; + + pud = pud_offset(pgd, address); + if (!pud_present(*pud)) + return 0; + + pmd = pmd_offset(pud, address); + if (!pmd_present(*pmd)) + return 0; + + pte = pte_offset_map(pmd, address); + /* Make a quick check before getting the lock */ + if (!pte_present(*pte)) { + pte_unmap(pte); + return 0; + } + + page = vm_normal_page(vma, address, *pte); + if(!page) + return 0; + + return page_to_pfn(page); +} + +/* + * Start management of the accounted process + */ +static int +mem_start (struct task_struct *tsk) +{ + cabi_account_t cabi = tsk->cabi_info; + struct mm_struct * mm = tsk->mm; + struct vm_area_struct * vma; + struct rs_proc_list *rs_proc; + struct mem_process_data *data; + + ENTER; + + rs_proc = pid_to_rs_proc(tsk->pid, tsk->cabi_info); + + /* Threads accounting by the parent process. */ + if(tsk->pid != tsk->tgid) { + rs_proc->private_data = NULL; + return 0; + } + + data = kzalloc(sizeof(struct mem_process_data), SLAB_KERNEL); + /* Init radix tree for page cache management */ + INIT_RADIX_TREE(&data->file_pages_tree, GFP_ATOMIC); + + /* Count number of pages the process has already used. */ + for(vma = mm->mmap; vma != NULL; vma = vma->vm_next) { + unsigned long pfn; + unsigned long map; + struct page * page; + + /* skip an anonymous vma */ + if (vma->anon_vma) + continue; + + for (map = vma->vm_start; map < vma->vm_end; map += PAGE_SIZE) { + pfn = map_to_pfn(vma, map); + if(!pfn) + continue; + page = pfn_to_page(pfn); + /* The page must be a page-cache */ + BUG_ON(PageAnon(page)); + + if(page_mapcount(page) == 1) { + radix_tree_insert(&data->file_pages_tree, + (int)page, page); + data->nr_file_pages++; + + radix_tree_tag_set(&data->file_pages_tree, + (int)page, CABI_PAGECACHE_TAG_MAPPED); + data->nr_file_mapped++; + } + } + } + + rs_proc->private_data = data; + + if ((cabi_mem_check_limit(cabi) & CABI_MEM_CHK_OVER_USER_LIMIT) && + !(cabi->res.mem->pm->obj_flag & CABI_MEM_OBJ_FBIND)) { + printk(KERN_INFO "Warning: This process has already used many memory.\n"); + goto error_return; + } + + cabi_mem_update_max(cabi); + +#ifdef CONFIG_PROC_FS + cabi_mem_proc_account_attach(cabi->cabi_id, rs_proc); +#endif + + return 0; + +error_return: + CABI_DBG; + kfree(data); + rs_proc->private_data = NULL; + return CABI_ERROR; + +} + +/* + * Stop management of the accounted process + */ +static int +mem_end (struct task_struct *tsk) +{ + cabi_account_t cabi = tsk->cabi_info; + struct rs_proc_list *rs_proc; + + /* Threads have no private data. */ + if(tsk->pid != tsk->tgid) + return 0; + + rs_proc = pid_to_rs_proc(tsk->pid, tsk->cabi_info); + +#ifdef CONFIG_PROC_FS + cabi_mem_proc_account_detach(cabi->cabi_id, rs_proc); +#endif + kfree(rs_proc->private_data); + + return 0; +} + +static int +mem_proc_create (cabi_account_t cabi) +{ + ENTER; + + cabi_mem_proc_account_create(cabi); + return 0; +} + +static int +mem_proc_destroy (cabi_account_t cabi) +{ + ENTER; + + cabi_mem_proc_account_destroy(cabi); + return 0; +} + +/* + * allocate memory to the memory account + */ +int +setup_mem_account (struct cabi_account *cabi, struct cabi_uaccount *ucabi) +{ + mem_account_t mem; + mem_param_t pm; + + ENTER; + + /* init mem_account methods and property */ + cabi->create = mem_set; + cabi->set = mem_set; + cabi->get = mem_get; + cabi->start = mem_start; + cabi->end = mem_end; + cabi->proc_create = mem_proc_create; + cabi->proc_destroy = mem_proc_destroy; + + if ((mem = kzalloc (sizeof (struct mem_account), SLAB_KERNEL)) == NULL) + return CABI_ENOMEM; + cabi->res.mem = mem; + cabi->res.mem->user_max = 0; + cabi->res.mem->file_max = 0; + cabi->res.mem->sig_stop = 0; + + if ((pm = kzalloc (sizeof (struct mem_param), SLAB_KERNEL)) == NULL) { + kfree(mem); + return CABI_ENOMEM; + } + cabi->res.mem->pm = pm; + + EXIT; + + return CABI_SUCCESS; +} + +/* + * free the memory account + */ +int +exit_mem_account (cabi_account_t cabi) +{ + ENTER; + + kfree(cabi->res.mem->pm); + kfree(cabi->res.mem); + return 0; +} + +/* + * Name : enable_mem_account + * + * If CONFIG_CABI_MEM is selected, this function start the memory + * accounting service. + */ +void +enable_mem_account (void) +{ + ENTER; + +#ifdef CONFIG_PROC_FS + cabi_mem_proc_init(); +#endif + + EXIT; +} + + +/* + * Name : disable_mem_account + * + * It is the main function to disable cpu resouce account functions. + */ + +void +disable_mem_account (void) +{ + ENTER; + EXIT; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/mem/mem_debug.c linux-2.6.16/drivers/cabi/mem/mem_debug.c --- linux-2.6.16-orig/drivers/cabi/mem/mem_debug.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/mem/mem_debug.c 2007-12-06 17:17:43.000000000 +0900 @@ -0,0 +1,115 @@ +/* + * linux/drivers/cabi/mem/mem_debug.c + * + * CABI -- Common Accounting and Blocking Interfaces. + * + * Copyright (C) Lineo solutions, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +#include +#include +#include +#include + +extern unsigned int cabi_mem_total_page; + +static int +check_mem_size(cabi_mem_unit_t mem_unit, unsigned long mem_size) +{ + int totalram = cabi_mem_total_page << PAGE_SHIFT; + + if (!mem_size) + return 0; + + switch (mem_unit) { + case CABI_MEM_UNIT_PERCENT: + if ((mem_size < 1) || (mem_size > 99)) + return CABI_EINVAL; + break; + case CABI_MEM_UNIT_PFN: + if (mem_size > cabi_mem_total_page) + return CABI_EINVAL; + break; + case CABI_MEM_UNIT_BYTE: + if (mem_size > totalram) + return CABI_EINVAL; + break; + case CABI_MEM_UNIT_KBYTE: + if (mem_size > (totalram >> 10)) + return CABI_EINVAL; + break; + case CABI_MEM_UNIT_MBYTE: + if (mem_size > (totalram >> 20)) + return CABI_EINVAL; + break; + case CABI_MEM_UNIT_GBYTE: + if (mem_size > (totalram >> 30)) + return CABI_EINVAL; + break; + default: + cabi_debug("mem_unit %08x\n", mem_unit); + return CABI_EINVAL; + } + + return 0; +} + +int +check_mem_params (struct cabi_uaccount *ucabi) +{ + struct mem_uaccount mem; + + ENTER; + + /* parameter copy */ + if (copy_from_user(&mem, ucabi->res.mem, sizeof (mem))) + return CABI_EINVAL; + + CABI_DBG; + if (mem.op_flag & ~CABI_MEM_OPS_MASK) { + cabi_debug("op_flag %#08x\n", mem.op_flag); + return CABI_EINVAL; + } + + /* Check the limit and the thresold */ + CABI_DBG; + if (mem.user_limit == 0 || + check_mem_size(mem.mem_unit, mem.user_limit)) + return CABI_EINVAL; + if (check_mem_size(mem.mem_unit, mem.file_limit) || + (mem.file_limit > mem.user_limit)) + return CABI_EINVAL; + if (check_mem_size(mem.mem_unit, mem.user_warn) || + (mem.user_warn > mem.user_limit)) + return CABI_EINVAL; + if (check_mem_size(mem.mem_unit, mem.file_warn) || + (mem.file_warn > mem.file_limit)) + return CABI_EINVAL; + + /* The number of pages to reclaim must be fewer than the total ram size */ + CABI_DBG; + if (check_mem_size(CABI_MEM_UNIT_BYTE, mem.reclaim_pages << PAGE_SHIFT)) + return CABI_EINVAL; + + /* Check signal parameters */ + if (mem.op_flag & CABI_MEM_OP_SIGNAL) { + CABI_DBG; + if (mem.signal.pid < 0) + return CABI_EINVAL; + if (mem.signal.sig < 0 || + mem.signal.sig > 32) + return CABI_EINVAL; + } + + EXIT; + return CABI_SUCCESS; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/mem/mem_drv.c linux-2.6.16/drivers/cabi/mem/mem_drv.c --- linux-2.6.16-orig/drivers/cabi/mem/mem_drv.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/mem/mem_drv.c 2007-11-02 17:02:30.000000000 +0900 @@ -0,0 +1,106 @@ +/* + * linux/drivers/cabi/mem/mem_drv.c + * + * CABI -- Common Accounting and Blocking Interfaces. + * + * Copyright (C) Lineo solutions, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVNAME "cabi_mem" +#define CABI_MEM_DRV_MINOR_NUMS 32 + +static int major; +module_param(major, int, 0); +MODULE_PARM_DESC(major, "Major device number"); + +DECLARE_WAIT_QUEUE_HEAD(cabi_warnq); +extern int cabi_poll; +extern cabi_object_t warn_cabi_id; + +static int cabi_mem_drv_open(struct inode *inode, struct file * filp) +{ + cabi_poll = 0; + return 0; +} + +static unsigned int cabi_mem_drv_poll(struct file * filp, poll_table * wait) +{ + int mask = 0; + + /* set next wait queue */ + poll_wait(filp, &cabi_warnq, wait); + + if(cabi_poll) { + mask |= POLLIN; + cabi_poll = 0; + } + + return mask; +} + +static ssize_t cabi_mem_drv_read(struct file *filp, char *buff, size_t count, loff_t *offp) +{ + if (copy_to_user(buff, &warn_cabi_id, sizeof(cabi_object_t))) + return -EIO; + + return sizeof(cabi_object_t); +} + +static const struct file_operations cabi_mem_drv_fops = { + .owner = THIS_MODULE, + .open = cabi_mem_drv_open, + .poll = cabi_mem_drv_poll, + .read = cabi_mem_drv_read, +}; + +static struct cdev cabi_mem_drv_cdev; + +static int __init cabi_mem_drv_init(void) +{ + dev_t devno; + + if (major) { + devno = MKDEV(major, 0); + register_chrdev_region(devno, CABI_MEM_DRV_MINOR_NUMS, DEVNAME); + } else { + alloc_chrdev_region(&devno, 0, CABI_MEM_DRV_MINOR_NUMS, DEVNAME); + major = MAJOR(devno); + } + printk(KERN_NOTICE DEVNAME ":major=%d\n",major); + + cdev_init(&cabi_mem_drv_cdev, &cabi_mem_drv_fops); + cabi_mem_drv_cdev.owner = THIS_MODULE; + cdev_add(&cabi_mem_drv_cdev, devno, 1); + + return 0; +} + +static void __exit cabi_mem_drv_cleanup(void) +{ + dev_t devno = MKDEV(major, 0); + + cdev_del(&cabi_mem_drv_cdev); + unregister_chrdev_region(devno, CABI_MEM_DRV_MINOR_NUMS); +} + +module_init(cabi_mem_drv_init); +module_exit(cabi_mem_drv_cleanup); diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/mem/mem_mng.c linux-2.6.16/drivers/cabi/mem/mem_mng.c --- linux-2.6.16-orig/drivers/cabi/mem/mem_mng.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/mem/mem_mng.c 2008-01-23 10:41:39.000000000 +0900 @@ -0,0 +1,281 @@ +/* + * linux/drivers/cabi/mem/mem_mng.c + * + * CABI -- Common Accounting and Blocking Interfaces. + * + * Copyright (C) Lineo solutions, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +#include +#include +#include + +#ifdef CABI_MEM_TIME_EVAL +time_eval_t time_eval[FUNC_INDEX_END]; +#endif + +void +cabi_mem_total_used(cabi_account_t cabi, mem_total_page_t total) +{ + struct rs_proc_list *rs_proc = NULL; + struct mem_process_data *data = NULL; + + memset(total, 0, sizeof(struct mem_total_page)); + list_for_each_entry(rs_proc, &cabi->proc_list, rs_proc_list) { + /* Skip thread */ + if(rs_proc->rs_proc_task->pid != rs_proc->rs_proc_task->tgid) + continue; + data = rs_proc->private_data; + total->user_page += + (get_mm_counter(rs_proc->rs_proc_task->mm, anon_rss) + + data->nr_file_pages); + total->file_cache += data->nr_file_pages; + total->file_unmapped += + (data->nr_file_pages - data->nr_file_mapped); + } + + return; +} + +void +cabi_mem_update_max(cabi_account_t cabi) +{ + struct mem_total_page total; + + cabi_mem_total_used(cabi, &total); + if (total.user_page > cabi->res.mem->user_max) + cabi->res.mem->user_max = total.user_page; + if (total.file_unmapped > cabi->res.mem->file_max) + cabi->res.mem->file_max = total.file_unmapped; +} + +cabi_mem_check_t +cabi_mem_check_limit(cabi_account_t cabi) +{ + struct mem_total_page total; + mem_param_t pm = cabi->res.mem->pm; + cabi_mem_check_t ret = CABI_MEM_CHK_VACANT; + + cabi_mem_total_used(cabi, &total); + + if (total.file_unmapped >= pm->file_limit) + ret |= CABI_MEM_CHK_OVER_FILE_LIMIT; + else if (total.file_unmapped >= pm->file_warn) + ret |= CABI_MEM_CHK_OVER_FILE_WARN; + + if (total.user_page >= pm->user_limit) + ret |= CABI_MEM_CHK_OVER_USER_LIMIT; + else if (total.user_page >= pm->user_warn) + ret |= CABI_MEM_CHK_OVER_USER_WARN; + + if(ret == CABI_MEM_CHK_VACANT) + cabi->res.mem->sig_stop = 0; + + return ret; +} + +int +cabi_mem_regist_file_pages(cabi_account_t cabi, struct page *page) +{ + struct rs_proc_list *rs_proc = NULL; + struct mem_process_data *data; + + list_for_each_entry(rs_proc, &cabi->proc_list, rs_proc_list) { + if (rs_proc->rs_proc_pid == current->tgid) { + data = rs_proc->private_data; + if (!radix_tree_insert(&data->file_pages_tree, + page_to_pfn(page), + page)) + data->nr_file_pages++; + cabi_mem_update_max(cabi); + + break; + } + } + + return 0; +} + +int +cabi_mem_unregist_file_pages(struct page *page) +{ + cabi_account_t cabi; + struct rs_proc_list *rs_proc = NULL; + struct mem_process_data *data; + + cabi_debug_time_st(UNREG_FILE_PAGES,0); + /* Search for a page cache from AO accounts. */ + list_for_each_entry(cabi, &cabi_account_head, cabi_link) { + list_for_each_entry(rs_proc, &cabi->proc_list, + rs_proc_list) { + /* Skip thread */ + if(rs_proc->rs_proc_task->pid != + rs_proc->rs_proc_task->tgid) + continue; + data = rs_proc->private_data; + if (radix_tree_delete(&data->file_pages_tree, + page_to_pfn(page))) + data->nr_file_pages--; + } + } + cabi_debug_time_ed(UNREG_FILE_PAGES,0); + cabi_debug_time_ave(UNREG_FILE_PAGES); + + return 0; +} + +int +cabi_mem_regist_file_mapped(cabi_account_t cabi, struct page *page) +{ + struct rs_proc_list *rs_proc = NULL; + struct mem_process_data *data; + + cabi_debug_time_st(REG_FILE_MAPPED,0); + list_for_each_entry(rs_proc, &cabi->proc_list, rs_proc_list) { + if (rs_proc->rs_proc_pid == current->tgid) { + + data = rs_proc->private_data; + if (!radix_tree_lookup(&data->file_pages_tree, + page_to_pfn(page))) { + if(!radix_tree_insert(&data->file_pages_tree, + page_to_pfn(page), page)) + data->nr_file_pages++; + } + radix_tree_tag_set(&data->file_pages_tree, + page_to_pfn(page), + CABI_PAGECACHE_TAG_MAPPED); + data->nr_file_mapped++; + + cabi_mem_update_max(cabi); + break; + } + } + cabi_debug_time_ed(REG_FILE_MAPPED,0); + cabi_debug_time_ave(REG_FILE_MAPPED); + + return 0; +} + +int +cabi_mem_unregist_file_mapped(struct page *page) +{ + cabi_account_t cabi; + struct rs_proc_list *rs_proc = NULL; + struct mem_process_data *data; + int result; + + cabi_debug_time_st(UNREG_FILE_MAPPED,0); + /* Search for a page cache from AO accounts. */ + list_for_each_entry(cabi, &cabi_account_head, cabi_link) { + list_for_each_entry(rs_proc, &cabi->proc_list, + rs_proc_list) { + /* Skip thread */ + if(rs_proc->rs_proc_task->pid != + rs_proc->rs_proc_task->tgid) + continue; + + data = rs_proc->private_data; + if (radix_tree_tag_clear( + &data->file_pages_tree, + page_to_pfn(page), + CABI_PAGECACHE_TAG_MAPPED)) { + data->nr_file_mapped--; + + result = cabi_mem_check_limit(cabi); + if (result & CABI_MEM_CHK_OVER_FILE_LIMIT) + cabi_mem_file_limit_operation(cabi); + else if (result & CABI_MEM_CHK_OVER_FILE_WARN) + cabi_mem_file_warn_operation(cabi); + + cabi_mem_update_max(cabi); + } + } + } + cabi_debug_time_ed(UNREG_FILE_MAPPED,0); + cabi_debug_time_ave(UNREG_FILE_MAPPED); + + return 0; +} + +struct page * +cabi_mem_cache_alloc(gfp_t gfp_mask) +{ + cabi_account_t cabi = TGLEADER_ACCOUNT(current); + struct page * page; + int result; + + cabi_debug_time_st(REG_FILE_PAGES,0); + result = cabi_mem_check_limit(cabi); + if (result != CABI_MEM_CHK_VACANT) { + if (result & CABI_MEM_CHK_OVER_USER_LIMIT) + return NULL; + else if (result & CABI_MEM_CHK_OVER_USER_WARN) { + cabi_mem_user_warn_operation(cabi); + result = cabi_mem_check_limit(cabi); + } + + if (result & CABI_MEM_CHK_OVER_FILE_WARN) + cabi_mem_file_warn_operation(cabi); + else if (result & CABI_MEM_CHK_OVER_FILE_LIMIT) + cabi_mem_file_limit_operation(cabi); + } + cabi_debug_time_ed(REG_FILE_PAGES,0); + + page = alloc_pages(gfp_mask, 0); + if(!page) + return NULL; + + cabi_debug_time_st(REG_FILE_PAGES,1); + if (cabi_mem_regist_file_pages(cabi, page)) + return NULL; + cabi_debug_time_ed(REG_FILE_PAGES,1); + cabi_debug_time_ave(REG_FILE_PAGES); + + return page; +} + +int +cabi_mem_handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long address, int write_access) +{ + cabi_account_t cabi = TGLEADER_ACCOUNT(current); + cabi_mem_check_t result; + int fault; + + cabi_debug_time_st(HANDLE_MM_FAULT,0); + result = cabi_mem_check_limit(cabi); + if (result != CABI_MEM_CHK_VACANT) { + + if (result & CABI_MEM_CHK_OVER_USER_LIMIT) + return VM_FAULT_OOM; + else if (result & CABI_MEM_CHK_OVER_USER_WARN) { + cabi_mem_user_warn_operation(cabi); + result = cabi_mem_check_limit(cabi); + } + + if (result & CABI_MEM_CHK_OVER_FILE_WARN) + cabi_mem_file_warn_operation(cabi); + else if (result & CABI_MEM_CHK_OVER_FILE_LIMIT) + cabi_mem_file_limit_operation(cabi); + } + cabi_debug_time_ed(HANDLE_MM_FAULT,0); + + fault = __handle_mm_fault(mm, vma, address, write_access); + cabi_debug_time_st(HANDLE_MM_FAULT,1); + if ((fault != VM_FAULT_OOM) && (fault != VM_FAULT_SIGBUS)) + cabi_mem_update_max(cabi); + cabi_debug_time_ed(HANDLE_MM_FAULT,1); + cabi_debug_time_ave(HANDLE_MM_FAULT); + + return fault; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/mem/mem_ops.c linux-2.6.16/drivers/cabi/mem/mem_ops.c --- linux-2.6.16-orig/drivers/cabi/mem/mem_ops.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/mem/mem_ops.c 2007-12-27 19:59:57.000000000 +0900 @@ -0,0 +1,162 @@ +/* + * linux/drivers/cabi/mem/mem_ops.c + * + * CABI -- Common Accounting and Blocking Interfaces. + * + * Copyright (C) Lineo solutions, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +#include +#include + + +extern wait_queue_head_t cabi_warnq; +int cabi_poll = 0; +cabi_object_t warn_cabi_id = 0; + +void +cabi_mem_user_warn_operation (cabi_account_t cabi) +{ + mem_param_t pm = cabi->res.mem->pm; + struct mem_total_page total; + + ENTER; + + /* do nothing */ + if (pm->op_flag & CABI_MEM_OP_NONE) + return; + + /* reclaim page caches */ + if (pm->op_flag & CABI_MEM_OP_RECLAIM) { + + CABI_DBG; + + /* Reclaiming interval */ + if(cabi->res.mem->reclaim_int) { + cabi->res.mem->reclaim_int--; + } else { + /* + * If the number of page caches is less than the reclaiming + * parameter, the reclaiming function wouldn't be called. + */ + cabi_mem_total_used(cabi, &total); + if (total.file_cache >= pm->reclaim_pages) { + unsigned int reclaimed; + /* + * Reclaime page caches. + * If we could get free pages enough, return here. + */ + reclaimed = cabi_mem_try_to_free_cache(cabi, pm->reclaim_pages); + if(reclaimed < pm->reclaim_pages) + cabi->res.mem->reclaim_int = pm->reclaim_pages; + if (cabi_mem_check_limit(cabi) == CABI_MEM_CHK_VACANT) + return; + } + } + } + + if (!cabi->res.mem->sig_stop) { + /* send signal */ + if (pm->op_flag & CABI_MEM_OP_SIGNAL) { + CABI_DBG; + cabi_send_signal(cabi, pm->signal.pid, pm->signal.sig); + } + + /* wake up poll waiting */ + if (pm->op_flag & CABI_MEM_OP_POLL) { + CABI_DBG; + cabi_poll = 1; + warn_cabi_id = cabi->cabi_id; + cabi_debug("warn_cabi_id: %ld\n", warn_cabi_id); + wake_up_interruptible(&cabi_warnq); + } + + /* Avoid to send signel recursively. */ + cabi->res.mem->sig_stop = 1; + } + + EXIT; +} + +void +cabi_mem_file_warn_operation (cabi_account_t cabi) +{ + mem_param_t pm = cabi->res.mem->pm; + + ENTER; + + /* do nothing */ + if (pm->op_flag & CABI_MEM_OP_NONE) + return; + + if (!cabi->res.mem->sig_stop) { + /* send signal */ + if (pm->op_flag & CABI_MEM_OP_SIGNAL) { + CABI_DBG; + /* sending a signal */ + cabi_send_signal(cabi, pm->signal.pid, pm->signal.sig); + } + + /* wake up poll wating */ + if (pm->op_flag & CABI_MEM_OP_POLL) { + CABI_DBG; + cabi_poll = 1; + warn_cabi_id = cabi->cabi_id; + cabi_debug("warn_cabi_id: %ld\n", warn_cabi_id); + wake_up_interruptible(&cabi_warnq); + } + + /* Avoid to send signel recursively. */ + cabi->res.mem->sig_stop = 1; + } + + EXIT; +} + +void +cabi_mem_file_limit_operation (cabi_account_t cabi) +{ + mem_param_t pm = cabi->res.mem->pm; + struct mem_total_page total; + + ENTER; + + /* do nothing */ + if (pm->op_flag & CABI_MEM_OP_NONE) + return; + + /* reclaim page caches */ + if (pm->op_flag & CABI_MEM_OP_RECLAIM) { + + CABI_DBG; + + /* Reclaiming interval */ + if(cabi->res.mem->reclaim_int) { + cabi->res.mem->reclaim_int--; + } else { + /* + * If the number of page caches is less than the reclaiming + * parameter, the reclaiming function wouldn't be called. + */ + cabi_mem_total_used(cabi, &total); + if (total.file_cache >= pm->reclaim_pages) { + unsigned int reclaimed; + reclaimed = cabi_mem_try_to_free_cache(cabi, pm->reclaim_pages); + if(reclaimed < pm->reclaim_pages) + cabi->res.mem->reclaim_int = pm->reclaim_pages; + } + } + } + + EXIT; +} diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/mem/mem_procfs.c linux-2.6.16/drivers/cabi/mem/mem_procfs.c --- linux-2.6.16-orig/drivers/cabi/mem/mem_procfs.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/mem/mem_procfs.c 2007-12-27 19:59:57.000000000 +0900 @@ -0,0 +1,592 @@ +/* + * linux/drivers/cabi/mem/mem_procfs.c + * + * CABI -- Common Accounting and Blocking Interfaces. + * + * Copyright (C) Lineo solutions, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) +#include +#else +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define arch_vma_name(x) (NULL) +#define page_zone_id(x) (((x)->flags >> ZONETABLE_PGSHIFT) & ZONETABLE_MASK) +#endif + +#define MAX_LEN 10 +#define NR_CABI 1000 +#define ENTRIES 1 + +#ifdef CONFIG_PROC_FS + +extern struct proc_dir_entry *proc_cabi_dir; +static struct proc_dir_entry *proc_mem_dir; +extern unsigned int cabi_mem_total_mem_kb; +extern unsigned int cabi_mem_total_page; +extern unsigned int cabi_mem_reserved_pages; + +/* + * /proc/cabi/mem///pmaps + * Display physical address mapping of the process. + */ +#define PMAPS_HEADER_LINE 1 +#define PMAPS_HEADER_0 (0-PMAPS_HEADER_LINE) +#define PMAPS_COL_ITEMS 8 +#define PMAPS_FLAG_LAST_ITEM 0x0001 + +typedef struct { + struct vm_area_struct * vma; + int line; + unsigned int flag; +} pmaps_data_t; + +static pmaps_data_t pmaps_data; + +static void * +seq_pmaps_next(struct seq_file *m, void *v, loff_t *pos) +{ + pmaps_data_t *current_pmaps = v; + struct vm_area_struct *vma = current_pmaps->vma; + + (*pos)++; + + if (current_pmaps->flag & PMAPS_FLAG_LAST_ITEM) { + current_pmaps->vma = vma->vm_next; + current_pmaps->line = -PMAPS_HEADER_LINE; + current_pmaps->flag &= ~PMAPS_FLAG_LAST_ITEM; + if (!current_pmaps->vma) + return NULL; + } else + current_pmaps->line++; + + return current_pmaps; +} + +static void * +seq_pmaps_start(struct seq_file *m, loff_t *pos) +{ + struct rs_proc_list *rs_proc = (struct rs_proc_list *)m->private; + struct vm_area_struct *vma = rs_proc->rs_proc_task->mm->mmap; + loff_t line = *pos; + + for(; vma != NULL; vma = vma->vm_next) { + unsigned long vma_lines = + ((PFN_DOWN(vma->vm_end - vma->vm_start) - 1) / + PMAPS_COL_ITEMS) + 1; + if (line >= (vma_lines + PMAPS_HEADER_LINE)) { + line -= (vma_lines + PMAPS_HEADER_LINE); + continue; + } else { + line -= PMAPS_HEADER_LINE; + break; + } + } + + if(!vma) + return NULL; + + pmaps_data.vma = vma; + pmaps_data.line = line; + pmaps_data.flag = 0; + + return &pmaps_data; +} + +static void +seq_pmaps_stop(struct seq_file *m, void *v) +{ +} + +static int +seq_pmaps_show(struct seq_file *m, void *v) +{ + pmaps_data_t *current_pmaps = v; + struct vm_area_struct *vma = current_pmaps->vma; + struct page *zero_page = ZERO_PAGE(address); + struct mm_struct *mm = vma->vm_mm; + struct file *file = vma->vm_file; + int flags = vma->vm_flags; + + /* Display header */ + if (current_pmaps->line == PMAPS_HEADER_0) { + seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx ", + vma->vm_start, + vma->vm_end, + flags & VM_READ ? 'r' : '-', + flags & VM_WRITE ? 'w' : '-', + flags & VM_EXEC ? 'x' : '-', + flags & VM_MAYSHARE ? 's' : 'p', + vma->vm_pgoff << PAGE_SHIFT); + /* + * Print the dentry name for named mappings, and a + * special [heap] marker for the heap: + */ + if (file) { + seq_path(m, file->f_vfsmnt, file->f_dentry, "\n"); + } else { + const char *name = arch_vma_name(vma); + if (!name) { + if (mm) { + if (vma->vm_start <= mm->start_brk && + vma->vm_end >= mm->brk) { + name = "[heap]"; + } else if (vma->vm_start <= mm->start_stack && + vma->vm_end >= mm->start_stack) { + name = "[stack]"; + } + } else { + name = "[vdso]"; + } + } + if (name) { + seq_puts(m, name); + } + } + seq_putc(m, '\n'); + } else { + int i; + unsigned long pfn; + unsigned long map = vma->vm_start + current_pmaps->line * + PMAPS_COL_ITEMS * PAGE_SIZE; + unsigned int items = PMAPS_COL_ITEMS; + + seq_printf(m, "%4d |", current_pmaps->line * PMAPS_COL_ITEMS); + if ((map + PMAPS_COL_ITEMS * PAGE_SIZE) > vma->vm_end) { + items = (vma->vm_end - map) / PAGE_SIZE; + current_pmaps->flag |= PMAPS_FLAG_LAST_ITEM; + } + + for (i = 0; i < items; i++) { + pfn = map_to_pfn(vma, map + i * PAGE_SIZE); + if(pfn == page_to_pfn(zero_page)) + seq_printf(m, " [zero] "); + else if(pfn) + seq_printf(m, " 0x%05lx", pfn); + else + seq_printf(m, " -------"); + } + seq_printf(m, "\n"); + } + + return 0; +} + +struct seq_operations seq_pmaps_op = { + .start = seq_pmaps_start, + .next = seq_pmaps_next, + .stop = seq_pmaps_stop, + .show = seq_pmaps_show, +}; + +static int +proc_mem_pmaps_open(struct inode *inode, struct file *file) +{ + int err; + struct seq_file *seq; + struct proc_dir_entry * dp = PDE(inode); + + + err = seq_open(file, &seq_pmaps_op); + if (!err) { + seq = file->private_data; + seq->private = dp->data; + } + + return err; +} + +struct file_operations proc_mem_pmaps_operation = { + .open = proc_mem_pmaps_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + + +/* + * /proc/cabi/mem//status + * Display status of the accounting object. + */ +static int +proc_mem_status_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + cabi_account_t cabi = (cabi_account_t) data; + mem_account_t mem = cabi->res.mem; + struct mem_total_page total; + + ENTER; + + cabi_mem_total_used(cabi, &total); + + p += sprintf(p, "user_limit : %8ldkb\n", mem->pm->user_limit << 2); + p += sprintf(p, "user_warn : %8ldkb\n", mem->pm->user_warn << 2); + p += sprintf(p, "user_max : %8ldkb\n", mem->user_max << 2); + p += sprintf(p, "user_use : %8ldkb\n", total.user_page << 2); + p += sprintf(p, "file_limit : %8ldkb\n", mem->pm->file_limit << 2); + p += sprintf(p, "file_warn : %8ldkb\n", mem->pm->file_warn << 2); + p += sprintf(p, "file_max : %8ldkb\n", mem->file_max << 2); + p += sprintf(p, "file_use : %8ldkb\n", total.file_unmapped << 2); + p += sprintf(p, "signal pid : %8d\n", (int)mem->pm->signal.pid); + p += sprintf(p, "signal sig : %8d\n", mem->pm->signal.sig); + p += sprintf(p, "signal flag: 0x%06x\n", mem->pm->signal.flag); + + return (p - page); +} + + +/* + * /proc/cabi/mem/cmaps + * Display status of the all physical pages. + */ +#define PAGE_PER_LINE 64 + +static void * +seq_cmaps_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + if (*pos * PAGE_PER_LINE >= cabi_mem_total_page) + return NULL; + + return pos; +} + +static void * +seq_cmaps_start(struct seq_file *m, loff_t *pos) +{ + if (*pos * PAGE_PER_LINE >= cabi_mem_total_page) + return NULL; + + if (!*pos) { + /* Header */ + seq_printf(m, ".=Free, -=Cache, +=Dirty, B=Buddy, A=Anonymous, " + "R=Reserved, S=Slab, W=Swap\n"); + seq_printf(m, "N:Z:PFN--++-------+-------+-------+-------" + "+-------+-------+-------+-------\n"); + } + + return pos; +} + +static void +seq_cmaps_stop(struct seq_file *m, void *v) +{ +} + +static int +seq_cmaps_show(struct seq_file *m, void *v) +{ + struct page *page; + loff_t *pos = v; + int i; + +#ifdef CONFIG_CPU_SH4 + page = mem_map + (*pos * PAGE_PER_LINE); +#else + page = pfn_to_page(*pos * PAGE_PER_LINE); +#endif + + /* Show node number */ + seq_printf(m, "%ld:", page_to_nid(page)); + /* Show zone name */ + seq_printf(m, "%d:", page_zone_id(page)); + /* Show page number */ + seq_printf(m, "%05lx|", page_to_pfn(page)); + + for (i = 0; i < PAGE_PER_LINE; i++, page++) { + if (PageBuddy(page)) /* page is free */ + seq_printf(m, "B"); + else if (PageReserved(page)) + seq_printf(m, "R"); + else if (PageSlab(page)) + seq_printf(m, "S"); + else if (PageReclaim(page) | PageSwapCache(page)) + seq_printf(m, "W"); + else if (PageAnon(page)) + seq_printf(m, "A"); + else if (PageDirty(page)) + seq_printf(m, "+"); + else if (PageLRU(page)) + seq_printf(m, "-"); + else + seq_printf(m, "."); + } + /* Linefeed */ + seq_printf(m, "\n"); + + return 0; +} + +struct seq_operations seq_cmaps_op = { + .start = seq_cmaps_start, + .next = seq_cmaps_next, + .stop = seq_cmaps_stop, + .show = seq_cmaps_show, +}; + +static int +proc_mem_cmaps_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &seq_cmaps_op); +} + +struct file_operations proc_mem_cmaps_operation = { + .open = proc_mem_cmaps_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * /proc/cabi/mem/info + * Display memory information. + */ +static int +proc_mem_info_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + unsigned long size; + + p += sprintf(p, "Memory size information:\n"); + p += sprintf(p, " total memory: %8dkb\n", + cabi_mem_total_mem_kb); + p += sprintf(p, " total page frame: %8d\n", cabi_mem_total_page); + p += sprintf(p, " reserved page: %8d\n", + cabi_mem_reserved_pages); + p += sprintf(p, "\n"); + p += sprintf(p, "Liner address information:\n"); + p += sprintf(p, " process space: %08x-%08lx\n", + 0, PAGE_OFFSET - 1); + p += sprintf(p, " kernel straight map: %08lx-%p\n", + PAGE_OFFSET, high_memory - 1); + size = NODE_DATA(0)->node_zones[ZONE_DMA].spanned_pages * PAGE_SIZE; + p += sprintf(p, " zone_dma: %08lx-%08lx\n", + PAGE_OFFSET, PAGE_OFFSET + size - 1); + p += sprintf(p, " kernel text: %p-%p\n", _text, _etext-1); + p += sprintf(p, " kernel data: %p-%p\n", _etext, _edata-1); + p += sprintf(p, " kernel bss: %p-%p\n", _edata, _end-1); + size = NODE_DATA(0)->node_zones[ZONE_NORMAL].spanned_pages * PAGE_SIZE; + if(size) + p += sprintf(p, " zone_nomal: %08lx-%08lx\n", + MAX_DMA_ADDRESS, MAX_DMA_ADDRESS + size - 1); + p += sprintf(p, " kernel virtual area: %08lx-%08lx\n", + VMALLOC_START, VMALLOC_END - 1); +#ifdef CONFIG_X86 +#ifdef CONFIG_HIGHMEM + p += sprintf(p, " highmem access area: %08lx-%08lx\n", + PKMAP_BASE, FIXADDR_BOOT_START - 1); +#endif + p += sprintf(p, " fixed map area: %08lx-%08lx\n", + FIXADDR_START, FIXADDR_TOP - 1); +#endif + + return (p - page); +} + +#ifdef CABI_MEM_TIME_EVAL +/* + * /proc/cabi/mem/time + * Time evaluation for cabi_mem. + */ +static int +proc_mem_time_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + + p += sprintf(p, "HANDLE_MM_FAULT: %6d %6ld\n", + time_eval[HANDLE_MM_FAULT].count, + (unsigned long)time_eval[HANDLE_MM_FAULT].average); + p += sprintf(p, "REG_FILE_MAPPED: %6d %6ld\n", + time_eval[REG_FILE_MAPPED].count, + (unsigned long)time_eval[REG_FILE_MAPPED].average); + p += sprintf(p, "UNREG_FILE_MAPPED: %6d %6ld\n", + time_eval[UNREG_FILE_MAPPED].count, + (unsigned long)time_eval[UNREG_FILE_MAPPED].average); + p += sprintf(p, "REG_FILE_PAGES: %6d %6ld\n", + time_eval[REG_FILE_PAGES].count, + (unsigned long)time_eval[REG_FILE_PAGES].average); + p += sprintf(p, "UNREG_FILE_PAGES: %6d %6ld\n", + time_eval[UNREG_FILE_PAGES].count, + (unsigned long)time_eval[UNREG_FILE_PAGES].average); + + return (p - page); +} + +#endif + +/* + * Create/Destroy entries for the process atatted cabi_mem. + */ +#define CABI_PMAPS_ENTRY "pmaps" + +void +cabi_mem_proc_account_attach(unsigned long cabi_id, struct rs_proc_list *rs_proc) +{ + cabi_account_t cabi; + struct proc_dir_entry *entry; + unsigned char string[MAX_LEN]; + mem_process_data_t data = rs_proc->private_data; + + cabi_debug ("cabi_proc_account_attach: rs_proc(0x%x) pid (%d)\n", + (int) rs_proc, (int) rs_proc->rs_proc_pid); + + /* find the cabi address */ + if (!(cabi = search_cabi(cabi_id))) + return; + + /* create pid dir at /proc/cabi/mem/ */ + sprintf(string, "%d", (int) rs_proc->rs_proc_pid); + data->proc_ent = proc_mkdir (string, cabi->proc_account_dir); + + if (!data->proc_ent) + printk("Cannot create /proc/%s/%s\n", + cabi->proc_account_dir->name, string); + + /* create pmaps in procfs dir */ + entry = create_proc_entry (CABI_PMAPS_ENTRY, + S_IFREG|S_IRUGO, data->proc_ent); + if (!entry) + printk("Cannot create /proc/%s/%s\n", + data->proc_ent->name, CABI_PMAPS_ENTRY); + + entry->nlink = 1; + entry->data = rs_proc; + entry->proc_fops = &proc_mem_pmaps_operation; +} + +void +cabi_mem_proc_account_detach(unsigned long cabi_id, struct rs_proc_list *rs_proc) +{ + cabi_account_t cabi; + char buf[16]; + mem_process_data_t data = rs_proc->private_data; + + cabi_debug ("cabi_proc_account_detach: pid (%d)", + (int) rs_proc->rs_proc_pid); + + /* find the cabi address */ + if (!(cabi = search_cabi(cabi_id))) + return; /* FIXME */ + + /* remove pmaps from procfs dir */ + remove_proc_entry(CABI_PMAPS_ENTRY, data->proc_ent); + + /* remove pid dir from procfs */ + sprintf(buf, "%d", (int) rs_proc->rs_proc_pid); + remove_proc_entry(buf, cabi->proc_account_dir); +} + +/* + * Create/Destroy the entries for cabi_mem. + */ +struct cabi_entry_list { + const char *name; + int (*f)(char *, char **, off_t, int, int *, void *); +} CABI_PROC_ENTRY[] = { + { "status", proc_mem_status_read }, +}; + +void +cabi_mem_proc_account_create(cabi_account_t cabi) +{ + int i; + struct proc_dir_entry *entry; + unsigned char string[MAX_LEN]; + + cabi_debug ("cabi_proc_account_create: cabi(0x%x) cabi_id (%d) \n", + (int) cabi, (int) cabi->cabi_id); + + sprintf(string, "%d", (int) cabi->cabi_id); + cabi->proc_account_dir = proc_mkdir (string, proc_mem_dir); + + if (!cabi->proc_account_dir) + printk("Cannot create /proc/cabi/mem/%d\n", (int)cabi->cabi_id); + + for (i = 0; i < ENTRIES; i++) { + entry = create_proc_entry (CABI_PROC_ENTRY[i].name, + S_IFREG|S_IRUGO, cabi->proc_account_dir); + + if (!entry) + printk("Cannot create /proc/cabi/mem/%d/%s\n", + (int) cabi->cabi_id, CABI_PROC_ENTRY[i].name); + + entry->nlink = 1; + entry->data = cabi; + entry->read_proc = *CABI_PROC_ENTRY[i].f; + } +} + +void +cabi_mem_proc_account_destroy(cabi_account_t cabi) +{ + char buf[16]; + int i; + + cabi_debug ("cabi_proc_account_destroy: cabi(%d)", + (int) cabi->cabi_id); + + for (i = 0; i < ENTRIES; i++) + remove_proc_entry (CABI_PROC_ENTRY[i].name, + cabi->proc_account_dir); + + sprintf(buf, "%d", (int) cabi->cabi_id); + remove_proc_entry(buf, proc_mem_dir); + +} + +/* Create /proc/cabi/mem directory entry. */ +void +cabi_mem_proc_init(void) +{ + struct proc_dir_entry *proc_cabi_cmaps; + struct proc_dir_entry *proc_cabi_info; +#ifdef CABI_MEM_TIME_EVAL + struct proc_dir_entry *proc_cabi_time; +#endif + + proc_mem_dir = create_proc_entry("mem", S_IFDIR, proc_cabi_dir); + if (!proc_mem_dir) + printk("Cannot create /proc/cabi/mem\n"); + + proc_cabi_cmaps = create_proc_entry("cmaps", + S_IFREG | S_IRUGO | S_IWUSR, proc_mem_dir); + proc_cabi_cmaps->proc_fops = &proc_mem_cmaps_operation; + + proc_cabi_info = create_proc_entry("info", + S_IFREG | S_IRUGO, proc_mem_dir); + proc_cabi_info->read_proc = &proc_mem_info_read; + +#ifdef CABI_MEM_TIME_EVAL + /* create time in procfs dir */ + proc_cabi_time = create_proc_entry("time", + S_IFREG | S_IRUGO, proc_mem_dir); + proc_cabi_time->read_proc = &proc_mem_time_read; +#endif +} +#endif /* CONFIG_PROC_FS */ diff -Nur -x.svn linux-2.6.16-orig/drivers/cabi/mem/mem_reclaim.c linux-2.6.16/drivers/cabi/mem/mem_reclaim.c --- linux-2.6.16-orig/drivers/cabi/mem/mem_reclaim.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/drivers/cabi/mem/mem_reclaim.c 2007-12-28 16:46:22.000000000 +0900 @@ -0,0 +1,395 @@ +/* + * linux/drivers/cabi/mem/mem_reclaim.c + * + * CABI -- Common Accounting and Blocking Interfaces. + * + * Copyright (C) Lineo solutions, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * This file is derived from software distributed under the following terms: + */ +/* + * linux/mm/vmscan.c + * + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * Swap reorganised 29.12.95, Stephen Tweedie. + * kswapd added: 7.1.96 sct + * Removed kswapd_ctl limits, and swap out as many pages as needed + * to bring the system back to freepages.high: 2.4.97, Rik van Riel. + * Zone aware kswapd started 02/00, Kanoj Sarcar (kanoj@sgi.com). + * Multiqueue VM started 5.8.00, Rik van Riel. + */ +/* #define CABI_DEBUG */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for try_to_release_page(), + buffer_heads_over_limit */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru)) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +#define get_page_unless_zero(page) atomic_inc_not_zero(&(page)->_count) +#define SetPageLRU(page) set_bit(PG_lru, &(page)->flags) +#define ClearPageLRU(page) clear_bit(PG_lru, &(page)->flags) +#define PageActive(page) test_bit(PG_active, &(page)->flags) +#define ClearPageActive(page) clear_bit(PG_active, &(page)->flags) +#endif + +#ifdef ARCH_HAS_PREFETCHW +#define prefetchw_prev_lru_page(_page, _base, _field) \ + do { \ + if ((_page)->lru.prev != _base) { \ + struct page *prev; \ + \ + prev = lru_to_page(&(_page->lru)); \ + prefetchw(&prev->_field); \ + } \ + } while (0) +#else +#define prefetchw_prev_lru_page(_page, _base, _field) do { } while (0) +#endif + +/* + * zone->lru_lock is heavily contended. Some of the functions that + * shrink the lists perform better by taking out a batch of pages + * and working on them outside the LRU lock. + * + * For pagecache intensive workloads, this function is the hottest + * spot in the kernel (apart from copy_*_user functions). + * + * Appropriate locks must be held before calling this function. + * + * @nr_to_scan: The number of pages to look through on the list. + * @src: The ao cache list to pull pages off. + * @dst: The temp list to put pages on to. + * @scanned: The number of pages that were scanned. + * + */ +static struct list_head * cabi_mem_isolate_cache( + cabi_account_t cabi, + unsigned long nr_to_scan, + struct list_head *src, struct list_head *dst, + unsigned long *scanned, unsigned long *taken) +{ + unsigned long nr_taken = 0; + unsigned long scan = 0; + struct list_head *page_list = src; + struct page *page; + struct list_head *proc_head; + struct rs_proc_list *proc_list; + + BUG_ON(cabi == NULL); + + proc_head = &cabi->proc_list; + + for ( scan = 0; + (nr_taken < nr_to_scan) && (page_list->prev != src); + scan++) { + page = lru_to_page(page_list); + page_list = &page->lru; + prefetchw_prev_lru_page(page, src, flags); + + /* + * TODO: Sometime we've got a page which has no LRU flag. + * So we need the below workaround instruction. + */ + if(!PageLRU(page)) + break; + + list_for_each_entry(proc_list, proc_head, rs_proc_list) { + struct mem_process_data *data; + /* Skip thread */ + if(proc_list->rs_proc_task->pid != + proc_list->rs_proc_task->tgid) + continue; + data = proc_list->private_data; + if (radix_tree_lookup(&data->file_pages_tree, page_to_pfn(page))) + break; + } + + if(&proc_list->rs_proc_list == proc_head) + continue; + + if (unlikely(get_page_testone(page))) { + __put_page(page); + } else { + page_list = page->lru.next; + list_del(&page->lru); + ClearPageLRU(page); + nr_taken++; + list_add(&page->lru, dst); + } + } + + *scanned = scan; + *taken = nr_taken; + + cabi_debug("scan:%ld, nr_taken:%ld\n", scan, nr_taken); + + return page_list->prev; +} + +/* + * This moves pages from the active list to the inactive list. + * + * We move them the other way if the page is referenced by one or more + * processes, from rmap. + * + * If the pages are mostly unmapped, the processing is fast and it is + * appropriate to hold zone->lru_lock across the whole operation. But if + * the pages are mapped, the processing is slow (page_referenced()) so we + * should drop zone->lru_lock around each page. It's impossible to balance + * this, so instead we remove the pages from the LRU while processing them. + * It is safe to rely on PG_active against the non-LRU pages in here because + * nobody will play with that bit on a non-LRU page. + * + * The downside is that we have to touch page->_count against each page. + * But we had to alter page->flags anyway. + */ +static void cabi_mem_shrink_active_list(cabi_account_t cabi, + unsigned long nr_pages, + struct zone *zone) +{ + unsigned long pgmoved; + int pgdeactivate = 0; + unsigned long pgscanned; + LIST_HEAD(l_hold); /* The pages which were snipped off */ + LIST_HEAD(l_inactive); /* Pages to go onto the inactive_list */ + LIST_HEAD(l_active); /* Pages to go onto the active_list */ + struct page *page; + struct pagevec pvec; + + lru_add_drain(); + spin_lock_irq(&zone->lru_lock); + cabi_mem_isolate_cache(cabi, nr_pages, &zone->active_list, &l_hold, + &pgscanned, &pgmoved); + zone->nr_active -= pgmoved; + spin_unlock_irq(&zone->lru_lock); + + while (!list_empty(&l_hold)) { + cond_resched(); + page = lru_to_page(&l_hold); + list_del(&page->lru); + if (page_mapped(page)) { + if ((total_swap_pages == 0 && PageAnon(page)) || + page_referenced(page, 0)) { + list_add(&page->lru, &l_active); + continue; + } + } + list_add(&page->lru, &l_inactive); + } + + pagevec_init(&pvec, 1); + pgmoved = 0; + spin_lock_irq(&zone->lru_lock); + while (!list_empty(&l_inactive)) { + page = lru_to_page(&l_inactive); + prefetchw_prev_lru_page(page, &l_inactive, flags); + BUG_ON(PageLRU(page)); + SetPageLRU(page); + BUG_ON(!PageActive(page)); + ClearPageActive(page); + + list_move(&page->lru, &zone->inactive_list); + pgmoved++; + if (!pagevec_add(&pvec, page)) { + zone->nr_inactive += pgmoved; + spin_unlock_irq(&zone->lru_lock); + pgdeactivate += pgmoved; + pgmoved = 0; + if (buffer_heads_over_limit) + pagevec_strip(&pvec); + __pagevec_release(&pvec); + spin_lock_irq(&zone->lru_lock); + } + } + zone->nr_inactive += pgmoved; + pgdeactivate += pgmoved; + if (buffer_heads_over_limit) { + spin_unlock_irq(&zone->lru_lock); + pagevec_strip(&pvec); + spin_lock_irq(&zone->lru_lock); + } + + pgmoved = 0; + while (!list_empty(&l_active)) { + page = lru_to_page(&l_active); + prefetchw_prev_lru_page(page, &l_active, flags); + BUG_ON(PageLRU(page)); + SetPageLRU(page); + BUG_ON(!PageActive(page)); + list_move(&page->lru, &zone->active_list); + pgmoved++; + if (!pagevec_add(&pvec, page)) { + zone->nr_active += pgmoved; + pgmoved = 0; + spin_unlock_irq(&zone->lru_lock); + __pagevec_release(&pvec); + spin_lock_irq(&zone->lru_lock); + } + } + zone->nr_active += pgmoved; + + spin_unlock_irq(&zone->lru_lock); + + pagevec_release(&pvec); + + cabi_debug("pgmoved:%ld\n", pgmoved); +} + +extern int cabi_mem_shrink_list(struct list_head *); +/* + * It returns the number of reclaimed pages + */ +static unsigned long cabi_mem_shrink_inactive_list(cabi_account_t cabi, + unsigned long max_scan, struct zone *zone) +{ + struct list_head *src_head = &zone->inactive_list; + LIST_HEAD(page_list); + struct pagevec pvec; + unsigned long nr_scanned = 0; + unsigned long nr_reclaimed = 0; + + pagevec_init(&pvec, 1); + + lru_add_drain(); + spin_lock_irq(&zone->lru_lock); + do { + struct page *page; + unsigned long nr_taken; + unsigned long nr_scan; + + src_head = cabi_mem_isolate_cache(cabi, SWAP_CLUSTER_MAX, + src_head, + &page_list, &nr_scan, + &nr_taken); + zone->nr_inactive -= nr_taken; + spin_unlock_irq(&zone->lru_lock); + + nr_scanned += nr_scan; + nr_reclaimed += cabi_mem_shrink_list(&page_list); + local_irq_disable(); + + if (nr_taken == 0) + goto done; + + spin_lock(&zone->lru_lock); + /* + * Put back any unfreeable pages. + */ + while (!list_empty(&page_list)) { + page = lru_to_page(&page_list); + BUG_ON(PageLRU(page)); + SetPageLRU(page); + list_del(&page->lru); + if (PageActive(page)) + add_page_to_active_list(zone, page); + else + add_page_to_inactive_list(zone, page); + if (!pagevec_add(&pvec, page)) { + spin_unlock_irq(&zone->lru_lock); + __pagevec_release(&pvec); + spin_lock_irq(&zone->lru_lock); + } + } + } while ((nr_reclaimed < max_scan) && + (nr_scanned < zone->nr_inactive)); + spin_unlock(&zone->lru_lock); +done: + local_irq_enable(); + pagevec_release(&pvec); + cabi_debug("nr_reclaimed:%ld/%ld\n", nr_reclaimed, max_scan); + return nr_reclaimed; +} + +/* + * This is a basic per-zone page freer. Used by both kswapd and direct reclaim. + */ +static unsigned long cabi_mem_shrink_cache(cabi_account_t cabi, + struct zone *zone, + unsigned long nr_req_reclaim) +{ + unsigned long nr_reclaimed = 0; + + atomic_inc(&zone->reclaim_in_progress); + + if (zone->nr_active >= nr_req_reclaim) + cabi_mem_shrink_active_list(cabi, nr_req_reclaim, zone); + + if (zone->nr_inactive >= nr_req_reclaim) + nr_reclaimed = + cabi_mem_shrink_inactive_list(cabi, + nr_req_reclaim, zone); + + atomic_dec(&zone->reclaim_in_progress); + return nr_reclaimed; +} + +unsigned long cabi_mem_try_to_free_cache(cabi_account_t cabi, + unsigned long nr_req_reclaim) +{ + unsigned long nr_reclaimed = 0; + int i; + struct zone **zones = (struct zone **)(NODE_DATA(nid)->node_zonelists + + gfp_zone(GFP_USER)); + + for (i = 0; zones[i] != NULL; i++) { + struct zone *zone = zones[i]; + + if (!populated_zone(zone)) + continue; + + if (!cpuset_zone_allowed(zone, __GFP_HARDWALL)) + continue; + + nr_reclaimed += cabi_mem_shrink_cache(cabi, zone, nr_req_reclaim); + if (nr_reclaimed >= nr_req_reclaim) + break; + } + + cabi_debug("reclaimed %3ld/%3ld page caches!\n", + nr_reclaimed, nr_req_reclaim); + return nr_reclaimed; +} diff -Nur -x.svn linux-2.6.16-orig/include/cabi/mem.h linux-2.6.16/include/cabi/mem.h --- linux-2.6.16-orig/include/cabi/mem.h 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.16/include/cabi/mem.h 2008-01-23 14:00:46.000000000 +0900 @@ -0,0 +1,336 @@ +/* + * include/cabi/mem.h + * + * CABI -- Common resource Accounting and Blocking Interfaces. + * + * Copyright (C) Lineo solutions, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +#ifndef CABI_MEM_H +#define CABI_MEM_H + +#ifdef __KERNEL__ +#include +#endif + +/* #define CABI_MEM_TIME_EVAL */ +/* #define CABI_MEM_TIME_EVAL_PRINT */ + +/* + * Unit for the limit and thresold parameters. + */ +enum cabi_mem_unit { + CABI_MEM_UNIT_PFN, + CABI_MEM_UNIT_PERCENT, + CABI_MEM_UNIT_BYTE, + CABI_MEM_UNIT_KBYTE, + CABI_MEM_UNIT_MBYTE, + CABI_MEM_UNIT_GBYTE, +}; +typedef enum cabi_mem_unit cabi_mem_unit_t; + +/* + * Operation on warning status. + * Each setting can be set individually. + * NOTE: When CABI_MEM_OP_NONE is set, other flags are invalidate. + */ +enum cabi_mem_op_flag { + CABI_MEM_OP_NONE = 0x001, + CABI_MEM_OP_SIGNAL = 0x002, + CABI_MEM_OP_POLL = 0x004, + CABI_MEM_OP_RECLAIM = 0x008, +}; +typedef enum cabi_mem_op_flag cabi_mem_op_flag_t; + +#define CABI_MEM_OPS_MASK (CABI_MEM_OP_NONE | CABI_MEM_OP_SIGNAL | \ + CABI_MEM_OP_POLL | CABI_MEM_OP_RECLAIM) + +/* + * Optional flag for Accounting Object. + */ +enum cabi_mem_obj_flag { + CABI_MEM_OBJ_FBIND = 0x001, /* Allow force binding */ +}; +typedef enum cabi_mem_obj_flag cabi_mem_obj_flag_t; + +#define CABI_MEM_OBJ_MASK (CABI_MEM_OBJ_FBIND) +#define TGLEADER_ACCOUNT(tsk) ((tsk)->group_leader->cabi_info) +#define IS_CABI_MEM_ACCOUNT(tsk) (TGLEADER_ACCOUNT(tsk) && \ + (((cabi_account_t)TGLEADER_ACCOUNT(tsk))->type & CABI_MEM)) + +/* Parameter for API */ +struct mem_uaccount { + cabi_mem_unit_t mem_unit; /* memory size unit */ + + /* + * When op_flag is omitted, cache reclaiming operation would + * be selected. + */ + cabi_mem_op_flag_t op_flag; /* action on warning */ + + cabi_mem_obj_flag_t obj_flag; /* accounting object flag */ + + /* + * The bellow limit and warning params can be omitted as 0, except for + * user_limit. When file_limit is omitted, the value would be same as + * user_limit. + * When ***_warn is omitted, the values would be set as 80% of the limit. + */ + unsigned long user_limit; /* limitation of memory size */ + unsigned long file_limit; /* limitation of page cache */ + unsigned long user_warn; /* thresold of memory */ + unsigned long file_warn; /* thresold of page cache */ + + /* + * The default value of recraim_pages is 32. + * It's the same parameter as try_to_free_pages. + */ + unsigned long reclaim_pages; /* number of pages to reclaim at a time */ + + /* Signal parameter */ + struct { + pid_t pid; /* process id */ + int sig; /* signal number */ + int flag; /* default(current) or else */ + } signal; +}; +typedef struct mem_uaccount *mem_uaccount_t; + +#ifdef __KERNEL__ /* for kernel only */ + +enum cabi_mem_check { + CABI_MEM_CHK_VACANT = 0x00, /* under the thresould */ + CABI_MEM_CHK_OVER_FILE_WARN = 0x01, /* over file warning */ + CABI_MEM_CHK_OVER_FILE_LIMIT = 0x02, /* over file limit */ + CABI_MEM_CHK_OVER_USER_WARN = 0x04, /* over user warn */ + CABI_MEM_CHK_OVER_USER_LIMIT = 0x08, /* over user limit */ +}; +typedef enum cabi_mem_check cabi_mem_check_t; + +#define DEF_WARNING_RATIO 80 /* default warning threshould */ +#define DEF_RECLAIM_PAGES 32 /* reclaim 32pages at a time */ +#define CABI_PAGECACHE_TAG_MAPPED 0 /* tag index of radix tree */ + +/* memory accounting parameters */ +struct mem_param { + /* + * When operation value is omitted, cache reclaiming operation is + * selected. + */ + cabi_mem_op_flag_t op_flag; /* action on warning */ + + cabi_mem_obj_flag_t obj_flag; /* accounting object flag */ + + /* + * Limitations and threshoulds for memory management. + */ + unsigned long user_limit; /* limitation of memory size*/ + unsigned long file_limit; /* limitation of page cache */ + unsigned long user_warn; /* thresold of mapped memory */ + unsigned long file_warn; /* thresold of page cache */ + + /* + * The default value of recraim_pages is 32. + * It's same as the number of try_to_free_pages. + */ + unsigned long reclaim_pages; /* number of pages to reclaim at a time */ + + /* Signal parameter. */ + struct { + pid_t pid; /* process id */ + int sig; /* signal number */ + int flag; /* default(current) or else */ + } signal; +}; +typedef struct mem_param *mem_param_t; + +struct mem_account { + mem_param_t pm; + unsigned long user_max; + unsigned long file_max; + unsigned long reclaim_int; + int sig_stop; +}; +typedef struct mem_account *mem_account_t; + +/* Process list */ +struct mem_process_data { + struct radix_tree_root file_pages_tree; + unsigned long nr_file_mapped; + unsigned long nr_file_pages; + struct proc_dir_entry *proc_ent; +}; +typedef struct mem_process_data *mem_process_data_t; + +struct mem_total_page { + unsigned long user_page; /* total page frame number */ + unsigned long file_cache; /* page cache (include mapped & unmapped) */ + unsigned long file_unmapped; /* unmapped page cache */ +}; +typedef struct mem_total_page *mem_total_page_t; + + +/* + * Function prototypes for memory management + */ +/* mem_account.c */ +extern unsigned long map_to_pfn(struct vm_area_struct *, unsigned long); + +/* mem_mng.c */ +extern void cabi_mem_total_used(struct cabi_account *, mem_total_page_t); +extern void cabi_mem_update_max(struct cabi_account *); +extern cabi_mem_check_t cabi_mem_check_limit(struct cabi_account *); +extern int cabi_mem_regist_file_pages(struct cabi_account *, struct page *); +extern int cabi_mem_unregist_file_pages(struct page *); +extern int cabi_mem_regist_file_mapped(struct cabi_account *, struct page *); +extern int cabi_mem_unregist_file_mapped(struct page *); +extern struct page *cabi_mem_cache_alloc(gfp_t); +extern int cabi_mem_handle_mm_fault(struct mm_struct *, + struct vm_area_struct *, unsigned long, int); + +/* mem_reclaim.c */ +extern unsigned long cabi_mem_try_to_free_cache(struct cabi_account *, + unsigned long); + +/* mem_ops.c */ +extern void cabi_mem_user_warn_operation(struct cabi_account *); +extern void cabi_mem_file_warn_operation(struct cabi_account *); +extern void cabi_mem_file_limit_operation(struct cabi_account *); + +/* mem_proc.c */ +extern void cabi_mem_proc_account_create(struct cabi_account *); +extern void cabi_mem_proc_account_destroy(struct cabi_account *); +extern void cabi_mem_proc_account_attach(unsigned long, struct rs_proc_list *); +extern void cabi_mem_proc_account_detach(unsigned long, struct rs_proc_list *); +extern void cabi_mem_proc_init(void); + +/* + * Structures and functions for time evaluation + */ +#ifdef CABI_MEM_TIME_EVAL +typedef enum { + HANDLE_MM_FAULT, + REG_FILE_MAPPED, + UNREG_FILE_MAPPED, + REG_FILE_PAGES, + UNREG_FILE_PAGES, + FUNC_INDEX_END +} func_index_t; + +typedef struct { + int count; + unsigned long long average; + unsigned long long start[2]; + unsigned long long end[2]; +} time_eval_t; + +/* for x86 */ +#ifdef CONFIG_X86 + #define cabi_debug_time_st(x, y) \ + __asm__ __volatile__("rdtsc" : "=A" (time_eval[x].start[y])) + #define cabi_debug_time_ed(x, y) \ + __asm__ __volatile__("rdtsc" : "=A" (time_eval[x].end[y])) +/* for ARM */ +#elif defined(CONFIG_ARM) + extern unsigned long long sched_clock(void); + #define cabi_debug_time_st(x, y) \ + do { time_eval[x].start[y] = sched_clock(); } while(0) + #define cabi_debug_time_ed(x, y) \ + do { time_eval[x].end[y] = sched_clock(); } while(0) +#elif defined(CONFIG_CPU_SH4) + #include + #include + #define CLK_RAISE (HZ<=100?10:100) + #define TMU0_TCNT 0xffd8000c /* Long access */ + #define TMU0_TCR 0xffd80010 /* Word access */ + extern spinlock_t tmu0_lock; + +static __inline__ unsigned long long sched_clock_sh4(void) +{ + long count; + int lost = 0; + unsigned long flags; + unsigned long long jiffies_64_p; + + /* + * cache volatile jiffies temporarily; we have IRQs turned off. + */ + spin_lock_irqsave(&tmu0_lock, flags); + jiffies_64_p = get_jiffies_64(); + /* + * avoiding timer inconsistencies (they are rare, but they happen)... + * there is one kind of problem that must be avoided here: + * 1. the timer counter underflows + */ + if(ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */ + lost = 1; + } + count = ctrl_inl(TMU0_TCNT); /* read the latched count */ + if(ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */ + lost = 1; + count = ctrl_inl(TMU0_TCNT);/* reload the latched count */ + } + count = LATCH - count; + if (lost) { + count += LATCH; + } + + jiffies_64_p = (jiffies_64_p * LATCH + count) * CLK_RAISE * (1000/HZ); + spin_unlock_irqrestore(&tmu0_lock, flags); + + return jiffies_64_p; + +} + #define cabi_debug_time_st(x, y) \ + do { time_eval[x].start[y] = sched_clock_sh4(); } while(0) + #define cabi_debug_time_ed(x, y) \ + do { time_eval[x].end[y] = sched_clock_sh4(); } while(0) +#endif /* CONFIG_X86 */ + +#ifdef CABI_MEM_TIME_EVAL_PRINT +#define cabi_debug_time_print(x,y) \ +do { \ + printk("func:%d, time:%8ld\n", x, y); \ +} while(0) +#else +#define cabi_debug_time_print(x) do { } while(0) +#endif + +#define WEIGHT_COEFF 9 + +#define cabi_debug_time_ave(x) \ +do { \ + unsigned long _d0, _d1; \ + _d0 = (unsigned long)(time_eval[x].end[0] - time_eval[x].start[0]); \ + _d1 = (unsigned long)(time_eval[x].end[1] - time_eval[x].start[1]); \ + if (likely(time_eval[x].count)) { \ + time_eval[x].average = \ + (unsigned long)(time_eval[x].average * WEIGHT_COEFF + \ + (_d0 + _d1) * (10 - WEIGHT_COEFF)) / 10; \ + } else \ + time_eval[x].average = _d0 + _d1; \ + time_eval[x].count++; \ + if((_d0 + _d1) > 1000) \ + cabi_debug_time_print(x, _d0 + _d1); \ +} while(0) + +extern time_eval_t time_eval[]; +#else + #define cabi_debug_time_st(x, y) do { } while(0) + #define cabi_debug_time_ed(x, y) do { } while(0) + #define cabi_debug_time_ave(x) do { } while(0) +#endif /* CABI_MEM_TIME_EVAL */ + +#endif /* __KERNEL__ */ + + +#endif /* CABI_MEM_H */ diff -Nur -x.svn linux-2.6.16-orig/include/linux/mm.h linux-2.6.16/include/linux/mm.h --- linux-2.6.16-orig/include/linux/mm.h 2008-01-23 15:05:43.000000000 +0900 +++ linux-2.6.16/include/linux/mm.h 2008-01-23 14:16:00.000000000 +0900 @@ -39,6 +39,10 @@ #include #include +#ifdef CONFIG_CABI_MEM +#include +#endif + #define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n)) /* @@ -730,8 +734,17 @@ struct vm_area_struct *vma, unsigned long address, int write_access) { +#ifdef CONFIG_CABI_MEM + if (IS_CABI_MEM_ACCOUNT(current)) { + return cabi_mem_handle_mm_fault(mm, vma, + address, write_access) & (~VM_FAULT_WRITE); + } else + return __handle_mm_fault(mm, vma, address, write_access) & + (~VM_FAULT_WRITE); +#else return __handle_mm_fault(mm, vma, address, write_access) & (~VM_FAULT_WRITE); +#endif } #else static inline int handle_mm_fault(struct mm_struct *mm, diff -Nur -x.svn linux-2.6.16-orig/include/linux/pagemap.h linux-2.6.16/include/linux/pagemap.h --- linux-2.6.16-orig/include/linux/pagemap.h 2008-01-23 15:05:42.000000000 +0900 +++ linux-2.6.16/include/linux/pagemap.h 2007-12-28 11:56:59.000000000 +0900 @@ -51,6 +51,10 @@ #define page_cache_release(page) put_page(page) void release_pages(struct page **pages, int nr, int cold); +#ifdef CONFIG_CABI_MEM +extern struct page *page_cache_alloc(struct address_space *x); +extern struct page *page_cache_alloc_cold(struct address_space *x); +#else static inline struct page *page_cache_alloc(struct address_space *x) { return alloc_pages(mapping_gfp_mask(x), 0); @@ -60,6 +64,7 @@ { return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0); } +#endif typedef int filler_t(void *, struct page *); diff -Nur -x.svn linux-2.6.16-orig/mm/filemap.c linux-2.6.16/mm/filemap.c --- linux-2.6.16-orig/mm/filemap.c 2008-01-23 15:07:34.000000000 +0900 +++ linux-2.6.16/mm/filemap.c 2008-01-23 14:09:12.000000000 +0900 @@ -42,6 +42,11 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, unsigned long nr_segs); +#ifdef CONFIG_CABI_MEM +#include +#include +#endif + /* * Shared mappings implemented 30.11.1994. It's not fully working yet, * though. @@ -118,6 +123,9 @@ page->mapping = NULL; mapping->nrpages--; pagecache_acct(-1); +#ifdef CONFIG_CABI_MEM + cabi_mem_unregist_file_pages(page); +#endif } void remove_from_page_cache(struct page *page) @@ -496,6 +504,26 @@ } EXPORT_SYMBOL(end_page_writeback); +#ifdef CONFIG_CABI_MEM +struct page *page_cache_alloc(struct address_space *x) +{ + if (IS_CABI_MEM_ACCOUNT(current) && !in_interrupt()) + return cabi_mem_cache_alloc(mapping_gfp_mask(x)); + else + return alloc_pages(mapping_gfp_mask(x), 0); +} +EXPORT_SYMBOL(page_cache_alloc); + +struct page *page_cache_alloc_cold(struct address_space *x) +{ + if (IS_CABI_MEM_ACCOUNT(current) && !in_interrupt()) + return cabi_mem_cache_alloc(mapping_gfp_mask(x)|__GFP_COLD); + else + return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0); +} +EXPORT_SYMBOL(page_cache_alloc_cold); +#endif + /* * Get a lock on the page, assuming we need to sleep to get it. * diff -Nur -x.svn linux-2.6.16-orig/mm/memory.c linux-2.6.16/mm/memory.c --- linux-2.6.16-orig/mm/memory.c 2008-01-23 15:07:34.000000000 +0900 +++ linux-2.6.16/mm/memory.c 2008-01-23 14:10:17.000000000 +0900 @@ -58,6 +58,10 @@ #include #include +#ifdef CONFIG_CABI_MEM +#include +#endif + #ifndef CONFIG_NEED_MULTIPLE_NODES /* use the per-pgdat data instead for discontigmem - mbligh */ unsigned long max_mapnr; @@ -1046,8 +1050,18 @@ cond_resched(); while (!(page = follow_page(vma, start, foll_flags))) { int ret; +#ifdef CONFIG_CABI_MEM + if (IS_CABI_MEM_ACCOUNT(current)) + ret = cabi_mem_handle_mm_fault( + mm, vma, start, + foll_flags & FOLL_WRITE); + else + ret = __handle_mm_fault(mm, vma, start, + foll_flags & FOLL_WRITE); +#else ret = __handle_mm_fault(mm, vma, start, foll_flags & FOLL_WRITE); +#endif /* * The VM_FAULT_WRITE bit tells us that do_wp_page has * broken COW when necessary, even if maybe_mkwrite diff -Nur -x.svn linux-2.6.16-orig/mm/rmap.c linux-2.6.16/mm/rmap.c --- linux-2.6.16-orig/mm/rmap.c 2008-01-23 15:07:34.000000000 +0900 +++ linux-2.6.16/mm/rmap.c 2008-01-23 14:11:17.000000000 +0900 @@ -56,6 +56,10 @@ #include +#ifdef CONFIG_CABI_MEM +#include +#endif + //#define RMAP_DEBUG /* can be enabled only for debugging */ kmem_cache_t *anon_vma_cachep; @@ -537,8 +541,15 @@ */ void page_add_file_rmap(struct page *page) { - if (atomic_inc_and_test(&page->_mapcount)) + if (atomic_inc_and_test(&page->_mapcount)) { __inc_page_state(nr_mapped); +#ifdef CONFIG_CABI_MEM + if (IS_CABI_MEM_ACCOUNT(current)) + if (cabi_mem_regist_file_mapped( + (cabi_account_t)current->cabi_info, page)) + BUG(); +#endif + } } /** @@ -571,6 +582,10 @@ set_page_dirty(page); __dec_page_state(nr_mapped); } +#ifdef CONFIG_CABI_MEM + if ((IS_CABI_MEM_ACCOUNT(current)) && !PageAnon(page)) + cabi_mem_unregist_file_mapped(page); +#endif } /* diff -Nur -x.svn linux-2.6.16-orig/mm/vmscan.c linux-2.6.16/mm/vmscan.c --- linux-2.6.16-orig/mm/vmscan.c 2008-01-23 15:07:34.000000000 +0900 +++ linux-2.6.16/mm/vmscan.c 2007-12-25 14:41:28.000000000 +0900 @@ -583,6 +583,21 @@ return reclaimed; } +#ifdef CONFIG_CABI_MEM +int cabi_mem_shrink_list(struct list_head *page_list) +{ + struct scan_control sc = { + .gfp_mask = GFP_USER, + .may_writepage = !laptop_mode, + .swap_cluster_max = SWAP_CLUSTER_MAX, + .may_swap = 1, + }; + + return shrink_list(page_list, &sc); +} +EXPORT_SYMBOL(cabi_mem_shrink_list); +#endif + #ifdef CONFIG_MIGRATION static inline void move_to_lru(struct page *page) {