Comparing directories

Left: clean-2.6.13.1/ Right: modif-2.6.13.1/
arch/i386/kernel/syscall_table.S
fs/exec.c
include/asm-i386/unistd.h
include/linux/init_task.h
include/linux/pkmem.h
include/linux/sched.h
kernel/exit.c
Makefile
mm/mprotect.c
pkmem/Makefile
pkmem/pkmem.c
 
clean-2.6.13.1/arch/i386/kernel/syscall_table.Smodif-2.6.13.1/arch/i386/kernel/syscall_table.S
2005-09-09 21:42:58.000000000 -05002006-03-01 04:40:37.114049000 -0600
294  .long sys_inotify_init294  .long sys_inotify_init
295  .long sys_inotify_add_watch295  .long sys_inotify_add_watch
296  .long sys_inotify_rm_watch296  .long sys_inotify_rm_watch
  297  .long sys_pk_alloc
  298  .long sys_pk_alloc_log    /* 295 */
  299  .long sys_pk_free
  300  .long sys_pk_free_log
  301  .long sys_pk_get
  302  .long sys_pk_end
  303
  304
  305  
  \ No newline at end of file
 
clean-2.6.13.1/fs/exec.cmodif-2.6.13.1/fs/exec.c
2005-09-09 21:42:58.000000000 -05002006-03-02 04:26:12.964415000 -0600
1138/*1138/*
1139 * sys_execve() executes a new program.1139 * sys_execve() executes a new program.
1140 */1140 */
  1141extern int attach_pkmem(void);
  1142
1141int do_execve(char * filename,1143int do_execve(char * filename,
1142  char __user *__user *argv,1144  char __user *__user *argv,
1143  char __user *__user *envp,1145  char __user *__user *envp,
 ... ...
1207  retval = search_binary_handler(bprm,regs);1209  retval = search_binary_handler(bprm,regs);
1208  if (retval >= 0) {1210  if (retval >= 0) {
1209    free_arg_pages(bprm);1211    free_arg_pages(bprm);
12101212    attach_pkmem();
  1213    current->pk = NULL;
1211    /* execve success */1214    /* execve success */
1212    security_bprm_free(bprm);1215    security_bprm_free(bprm);
1213    acct_update_integrals(current);1216    acct_update_integrals(current);
 
clean-2.6.13.1/include/asm-i386/unistd.hmodif-2.6.13.1/include/asm-i386/unistd.h
2005-09-09 21:42:58.000000000 -05002006-02-28 13:23:44.717387000 -0600
299#define __NR_inotify_init  291299#define __NR_inotify_init  291
300#define __NR_inotify_add_watch  292300#define __NR_inotify_add_watch  292
301#define __NR_inotify_rm_watch  293301#define __NR_inotify_rm_watch  293
  302#define __NR_pk_alloc    294
  303#define __NR_pk_alloc_log  295
  304#define __NR_pk_free    296
  305#define __NR_pk_free_log  297
  306#define __NR_pk_get    298
  307#define __NR_pk_end    299
302308
303#define NR_syscalls 294309
  310#define NR_syscalls 300
304311
305/*312/*
306 * user-visible error numbers are in the range -1 - -128: see313 * user-visible error numbers are in the range -1 - -128: see
 
clean-2.6.13.1/include/linux/init_task.hmodif-2.6.13.1/include/linux/init_task.h
2005-09-09 21:42:58.000000000 -05002006-02-28 03:38:53.194325000 -0600
112  .journal_info  = NULL,            \112  .journal_info  = NULL,            \
113  .cpu_timers  = INIT_CPU_TIMERS(tsk.cpu_timers),    \113  .cpu_timers  = INIT_CPU_TIMERS(tsk.cpu_timers),    \
114  .fs_excl  = ATOMIC_INIT(0),        \114  .fs_excl  = ATOMIC_INIT(0),        \
  115  .pk    = NULL,            \
115}116}
116117
117118
 
clean-2.6.13.1/include/linux/pkmem.hmodif-2.6.13.1/include/linux/pkmem.h
1969-12-31 18:00:00.000000000 -06002006-03-23 15:45:04.318940000 -0600
  1#ifndef __PKMEM_H
  2#define __PKMEM_H
  3
  4#include <linux/types.h>
  5#include <linux/rwsem.h>
  6#include <linux/jiffies.h>
  7#include <linux/sched.h>
  8#include <linux/errno.h>
  9#include <linux/spinlock.h>
  10#include <linux/list.h>
  11
  12#include <asm/types.h>
  13#include <asm/processor.h>
  14
  15////////////////////////////////////////////////////////////////////////////////
  16/// Important Symbols
  17////////////////////////////////////////////////////////////////////////////////
  18#define PKMEM_START  0x9bef8000
  19#define PKMEM_PAGES  512
  20#define PKMEM_SIZE  (PAGE_SIZE * PKMEM_PAGES)
  21//#define PKMEM_START  (TASK_SIZE - 1 - PKMEM_SIZE)
  22#define PK_TIMEOUT  (3 * HZ)
  23
  24////////////////////////////////////////////////////////////////////////////////
  25/// Important Macros
  26///////////////////////////////////////////////////////////////////////////////
  27#define PK_CUR_TASK_LOCK          spin_lock(&current->pk->lock)
  28#define PK_CUR_TASK_UNLOCK          spin_unlock(&current->pk->lock)
  29#define PK_TASK_LOCK(pk_tsk)          spin_lock(&pk_tsk->lock)
  30#define PK_TASK_UNLOCK(pk_tsk)          spin_unlock(&pk_tsk->lock)
  31
  32#define PK_LOCK        spin_lock(&pk_lock)
  33#define PK_UNLOCK      spin_unlock(&pk_lock)
  34#define PK_SHARE_LOCK(share)    spin_lock(&share->lock)
  35#define PK_SHARE_UNLOCK(share)    spin_unlock(&share->lock)
  36
  37#define GET_SEMAPHORE(task_share, status)        \
  38  if(status & PK_FL_RDLCK) down_read(&task_share->share->sem);  \
  39  else down_write(&task_share->share->sem);      
  40
  41#define RELEASE_SEMAPHORE(task_share, status)        \
  42  if(status & PK_FL_RDLCK) up_read(&task_share->share->sem);  \
  43  else up_write(&task_share->share->sem);  
  44
  45////////////////////////////////////////////////////////////////////////////////
  46/// Debug Macros
  47/// #define dbg(format, arg...) printk(KERN_INFO "pk: " format "\n" , ##arg)
  48////////////////////////////////////////////////////////////////////////////////
  49//#define PKMEM_DEBUG
  50
  51#ifdef PKMEM_DEBUG
  52  #define dbg(format, arg...)          \
  53    printk(KERN_INFO "pk: %d,(%s, %d):%s() " format "\n",    \
  54     current->pid, __FILE__, __LINE__, __FUNCTION__, ##arg)
  55#else
  56  #define dbg(format, arg...) do {} while (0)
  57#endif
  58
  59////////////////////////////////////////////////////////////////////////////////
  60/// Error Numbers in pkMem
  61////////////////////////////////////////////////////////////////////////////////
  62#define EABRT        100
  63#define EABRTONGOING      101
  64#define ENOTSTOPPED      102
  65#define EUNUSED        103 /* Unused */
  66#define ENOPARAM      104
  67#define EMPROTECT      105
  68#define ENOEXIST      106
  69#define EDELETED      107
  70#define ENODGRADE      108
  71#define ENOUGRADE      109
  72#define EBUG        110
  73#define EABRTPENDING      111
  74#define EDENIED        112
  75
  76////////////////////////////////////////////////////////////////////////////////
  77/// Constants in pkMem
  78////////////////////////////////////////////////////////////////////////////////
  79
  80/// Constants that are used to describe the status field of struct pk_share
  81/// AND are used by _userspace_ to specify the lock requested
  82#define PK_FL_RDLCK      0x000001
  83#define PK_FL_WRLCK      0x000002
  84
  85/// Constants used to descibe the status field of struct pk_share
  86#define PK_ST_DEL      0x000004
  87#define PK_ST_DEL_FINAL      0x002000
  88
  89/// Constants used to describe the status field of struct pk_task
  90#define PK_TR_STARTED      0x000008
  91#define PK_TR_STOPPED      0x000010
  92#define PK_TR_ABORTED      0x000020
  93#define PK_TR_ABORT_PENDING    0x000040
  94#define PK_TR_SYS_INPROGRESS    0x000080
  95#define PK_TR_ABORT_INPROGRESS    0x000100
  96
  97/// Constants used to descibe the status field of struct pk_task_share
  98#define PK_PROC_GOT_WR      0x000200
  99#define PK_PROC_GOT_RD      0x000400
  100#define PK_PROC_FREE      0x000800
  101#define PK_PROC_ALLOC      0x001000
  102
  103////////////////////////////////////////////////////////////////////////////////
  104/// Structures in pkMem
  105///////////////////////////////////////////////////////////////////////////////
  106struct pk_basic {
  107  struct list_head list;
  108  unsigned long start;
  109        unsigned long pages;
  110};
  111
  112struct pk_share {
  113        struct rw_semaphore sem;
  114  
  115  // Modification of these fields is done holding PK_LOCK
  116  unsigned long start;
  117        unsigned long pages;
  118  struct list_head list;
  119  
  120  spinlock_t lock;
  121
  122  // Modification of these fields is done holding ``lock'
  123  struct list_head task_head;
  124        unsigned long status;
  125        unsigned int refcnt;
  126};
  127
  128struct pk_task_share {  
  129        struct list_head list;
  130        struct list_head list_task;
  131  spinlock_t lock;
  132        unsigned int status;
  133  struct task_struct *task;
  134        struct pk_share *share;
  135  unsigned long jiffies;
  136};
  137
  138////////////////////////////////////////////////////////////////////////////////
  139/// Externally defined
  140////////////////////////////////////////////////////////////////////////////////
  141
  142extern long mprotect_for_task(struct task_struct *task, unsigned long start,
  143            size_t len, unsigned long prot);
  144extern long __do_abort(struct task_struct *task, int call_mprotect);
  145extern void __release_log_regions(struct pk_task *pk);
  146
  147#endif
 
clean-2.6.13.1/include/linux/sched.hmodif-2.6.13.1/include/linux/sched.h
2005-09-09 21:42:58.000000000 -05002006-03-01 03:04:48.417676000 -0600
596struct audit_context;    /* See audit.c */596struct audit_context;    /* See audit.c */
597struct mempolicy;597struct mempolicy;
598598
  599/// Note: struct pk_task is embedded inside struct task_struct;
  600struct pk_task {
  601  spinlock_t lock;
  602        unsigned long status;  
  603        struct list_head logs_head;
  604        struct list_head share_head;
  605};
  606
599struct task_struct {607struct task_struct {
600  volatile long state;  /* -1 unrunnable, 0 runnable, >0 stopped */608  volatile long state;  /* -1 unrunnable, 0 runnable, >0 stopped */
601  struct thread_info *thread_info;609  struct thread_info *thread_info;
 ... ...
770  int cpuset_mems_generation;778  int cpuset_mems_generation;
771#endif779#endif
772  atomic_t fs_excl;  /* holding fs exclusive resources */780  atomic_t fs_excl;  /* holding fs exclusive resources */
  781  struct pk_task *pk;
773};782};
774783
775static inline pid_t process_group(struct task_struct *tsk)784static inline pid_t process_group(struct task_struct *tsk)
 
clean-2.6.13.1/kernel/exit.cmodif-2.6.13.1/kernel/exit.c
2005-09-09 21:42:58.000000000 -05002006-03-23 00:57:31.231458000 -0600
28#include <linux/cpuset.h>28#include <linux/cpuset.h>
29#include <linux/syscalls.h>29#include <linux/syscalls.h>
30#include <linux/signal.h>30#include <linux/signal.h>
  31#include <linux/pkmem.h>
3132
32#include <asm/uaccess.h>33#include <asm/uaccess.h>
33#include <asm/unistd.h>34#include <asm/unistd.h>
 ... ...
833    del_timer_sync(&tsk->signal->real_timer);834    del_timer_sync(&tsk->signal->real_timer);
834    acct_process(code);835    acct_process(code);
835  }836  }
  837
  838  /// If the task's current transaction has already been aborted or
  839  /// has stopped then don't call __do_abort. But we always call
  840  /// __release_log_regions() it releases all the log regions allocated by
  841  /// the task back into the free list
  842  if(tsk->pk) {
  843    PK_TASK_LOCK(tsk->pk);
  844    if(!(tsk->pk->status & PK_TR_ABORTED
  845         || tsk->pk->status & PK_TR_STOPPED
  846         || tsk->pk->status & PK_TR_ABORT_INPROGRESS)) {
  847      PK_TASK_UNLOCK(tsk->pk);
  848      __do_abort(tsk, 0);
  849    } else
  850      PK_TASK_UNLOCK(tsk->pk);
  851    __release_log_regions(tsk->pk);
  852  }
  853
836  exit_mm(tsk);854  exit_mm(tsk);
837855
838  exit_sem(tsk);856  exit_sem(tsk);
 ... ...
852870
853  tsk->exit_code = code;871  tsk->exit_code = code;
854  exit_notify(tsk);872  exit_notify(tsk);
  873
855#ifdef CONFIG_NUMA874#ifdef CONFIG_NUMA
856  mpol_free(tsk->mempolicy);875  mpol_free(tsk->mempolicy);
857  tsk->mempolicy = NULL;876  tsk->mempolicy = NULL;
 
clean-2.6.13.1/Makefilemodif-2.6.13.1/Makefile
2005-09-09 21:42:58.000000000 -05002006-01-16 12:46:52.292063000 -0600
562562
563563
564ifeq ($(KBUILD_EXTMOD),)564ifeq ($(KBUILD_EXTMOD),)
565core-y    += kernel/ mm/ fs/ ipc/ security/ crypto/565core-y    += kernel/ mm/ fs/ ipc/ security/ crypto/ pkmem/
566566
567vmlinux-dirs  := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \567vmlinux-dirs  := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
568         $(core-y) $(core-m) $(drivers-y) $(drivers-m) \568         $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
 
clean-2.6.13.1/mm/mprotect.cmodif-2.6.13.1/mm/mprotect.c
2005-09-09 21:42:58.000000000 -05002006-03-08 01:13:10.271147000 -0600
19#include <linux/mempolicy.h>19#include <linux/mempolicy.h>
20#include <linux/personality.h>20#include <linux/personality.h>
21#include <linux/syscalls.h>21#include <linux/syscalls.h>
  22#include <linux/pkmem.h>
2223
23#include <asm/uaccess.h>24#include <asm/uaccess.h>
24#include <asm/pgtable.h>25#include <asm/pgtable.h>
 ... ...
184  struct vm_area_struct *vma, *prev;185  struct vm_area_struct *vma, *prev;
185  int error = -EINVAL;186  int error = -EINVAL;
186  const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);187  const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);
  188
  189  /* Cannot mprotect a VMA that belongs to pkmem */
  190  if(start >= PKMEM_START && start <= (PKMEM_START + PKMEM_SIZE)) {
  191    error = -EACCES;
  192    goto out;
  193  }
  194
187  prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP);195  prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP);
188  if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */196  if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */
189    return -EINVAL;197    return -EINVAL;
 ... ...
280  up_write(&current->mm->mmap_sem);288  up_write(&current->mm->mmap_sem);
281  return error;289  return error;
282}290}
  291
  292long mprotect_for_task(struct task_struct *task, unsigned long start,
  293           size_t len, unsigned long prot)
  294{
  295  unsigned long vm_flags, nstart, end, tmp, reqprot;
  296  struct vm_area_struct *vma, *prev;
  297  int error = -EINVAL;
  298  const int grows = prot & (PROT_GROWSDOWN|PROT_GROWSUP);
  299  prot &= ~(PROT_GROWSDOWN|PROT_GROWSUP);
  300  if (grows == (PROT_GROWSDOWN|PROT_GROWSUP)) /* can't be both */
  301    return -EINVAL;
  302
  303  if (start & ~PAGE_MASK)
  304    return -EINVAL;
  305  if (!len)
  306    return 0;
  307  len = PAGE_ALIGN(len);
  308  end = start + len;
  309  if (end <= start)
  310    return -ENOMEM;
  311  if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM))
  312    return -EINVAL;
  313
  314  reqprot = prot;
  315  /*
  316   * Does the application expect PROT_READ to imply PROT_EXEC:
  317   */
  318  if (unlikely((prot & PROT_READ) &&
  319      (task->personality & READ_IMPLIES_EXEC)))
  320    prot |= PROT_EXEC;
  321
  322  vm_flags = calc_vm_prot_bits(prot);
  323
  324  down_write(&task->mm->mmap_sem);
  325
  326  vma = find_vma_prev(task->mm, start, &prev);
  327  error = -ENOMEM;
  328  if (!vma)
  329    goto out;
  330  if (unlikely(grows & PROT_GROWSDOWN)) {
  331    if (vma->vm_start >= end)
  332      goto out;
  333    start = vma->vm_start;
  334    error = -EINVAL;
  335    if (!(vma->vm_flags & VM_GROWSDOWN))
  336      goto out;
  337  }
  338  else {
  339    if (vma->vm_start > start)
  340      goto out;
  341    if (unlikely(grows & PROT_GROWSUP)) {
  342      end = vma->vm_end;
  343      error = -EINVAL;
  344      if (!(vma->vm_flags & VM_GROWSUP))
  345        goto out;
  346    }
  347  }
  348  if (start > vma->vm_start)
  349    prev = vma;
  350
  351  for (nstart = start ; ; ) {
  352    unsigned long newflags;
  353
  354    /* Here we know that  vma->vm_start <= nstart < vma->vm_end. */
  355
  356    if (is_vm_hugetlb_page(vma)) {
  357      error = -EACCES;
  358      goto out;
  359    }
  360
  361    newflags = vm_flags | (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC));
  362
  363    if ((newflags & ~(newflags >> 4)) & 0xf) {
  364      error = -EACCES;
  365      goto out;
  366    }
  367    
  368    tmp = vma->vm_end;
  369    if (tmp > end)
  370      tmp = end;
  371    error = mprotect_fixup(vma, &prev, nstart, tmp, newflags);
  372    if (error)
  373      goto out;
  374    nstart = tmp;
  375
  376    if (nstart < prev->vm_end)
  377      nstart = prev->vm_end;
  378    if (nstart >= end)
  379      goto out;
  380
  381    vma = prev->vm_next;
  382    if (!vma || vma->vm_start != nstart) {
  383      error = -ENOMEM;
  384      goto out;
  385    }
  386  }
  387out:
  388  up_write(&task->mm->mmap_sem);
  389  return error;
  390}
 
clean-2.6.13.1/pkmem/Makefilemodif-2.6.13.1/pkmem/Makefile
1969-12-31 18:00:00.000000000 -06002006-01-16 12:46:52.382063000 -0600
  1# pkmem
  2#
  3obj-y := pkmem.o
 
clean-2.6.13.1/pkmem/pkmem.cmodif-2.6.13.1/pkmem/pkmem.c
1969-12-31 18:00:00.000000000 -06002006-04-02 19:05:32.234443000 -0500
  1#include <linux/init.h>
  2#include <linux/devfs_fs_kernel.h>
  3#include <linux/vfs.h>
  4#include <linux/mount.h>
  5#include <linux/file.h>
  6#include <linux/mm.h>
  7#include <linux/module.h>
  8#include <linux/swap.h>
  9#include <linux/ramfs.h>
  10#include <asm/mman.h>
  11#include <linux/list.h>
  12#include <linux/slab.h>
  13#include <linux/ptrace.h>
  14#include <linux/syscalls.h>
  15#include <linux/linkage.h>
  16#include <linux/spinlock.h>
  17#include <linux/pkmem.h>
  18
  19/// Globals needed for creating the pkMem region
  20static struct vfsmount *pkmem_mnt;
  21static struct file *pk_file;
  22
  23/// Global pkMem data structure slabs
  24kmem_cache_t *pk_task_cachep;
  25kmem_cache_t *pk_basic_cachep;
  26kmem_cache_t *pk_share_cachep;
  27kmem_cache_t *pk_task_share_cachep;
  28
  29/// Definitions of global PK_LOCK
  30spinlock_t pk_lock;
  31
  32/// Keeps track of the size of the largest contigious free pkMem region in the
  33/// free list [Protected by PK_LOCK]
  34/// pk_freeHEAD points to a list of struct pk_basic object (free list)
  35/// pk_shareHEAD points to a list of struct pk_share objects (shared list)
  36static unsigned long __pk_free_pages;
  37static LIST_HEAD(pk_freeHEAD);
  38static LIST_HEAD(pk_shareHEAD);
  39
  40////////////////////////////////////////////////////////////////////////////////
  41/// Functions to initialize the pkMem data structures
  42////////////////////////////////////////////////////////////////////////////////
  43
  44static inline struct pk_basic *init_pk_basic(void)
  45{
  46  struct pk_basic *basic;
  47
  48  might_sleep();
  49  basic = kmem_cache_alloc(pk_basic_cachep, GFP_KERNEL);
  50
  51  if(!basic)
  52    return NULL;
  53  INIT_LIST_HEAD(&basic->list);
  54        basic->pages = 0;
  55        basic->start = 0;
  56        return basic;
  57}
  58
  59static inline struct pk_share *init_pk_share(void)
  60{
  61  struct pk_share *share;
  62
  63  might_sleep();
  64  share = kmem_cache_alloc(pk_share_cachep, GFP_KERNEL);
  65  
  66  if(!share)
  67    return NULL;
  68  init_rwsem(&share->sem);
  69  share->lock = SPIN_LOCK_UNLOCKED;
  70  INIT_LIST_HEAD(&share->list);
  71  INIT_LIST_HEAD(&share->task_head);
  72        share->status = 0;
  73        share->pages = 0;
  74        share->start = 0;
  75  share->refcnt = 0;
  76        return share;
  77}
  78
  79static inline struct pk_task *init_pk_task(unsigned long status)
  80{
  81        struct pk_task *pk;
  82
  83  might_sleep();
  84  pk = kmem_cache_alloc(pk_task_cachep, GFP_KERNEL);
  85
  86  if(!pk)
  87    return NULL;
  88        pk->lock = SPIN_LOCK_UNLOCKED;
  89        pk->status = status;
  90        INIT_LIST_HEAD(&pk->logs_head);
  91        INIT_LIST_HEAD(&pk->share_head);
  92        return pk;
  93}
  94
  95static inline struct pk_task_share *init_pk_task_share(void)
  96{
  97  struct pk_task_share *task_share;
  98
  99  might_sleep();
  100  task_share = kmem_cache_alloc(pk_task_share_cachep, GFP_KERNEL);
  101
  102  if(!task_share)
  103    return NULL;
  104  INIT_LIST_HEAD(&task_share->list);
  105  task_share->share = NULL;
  106  task_share->status = 0;
  107  task_share->task = current;
  108  // Note: We do not set task_share->jiffies at this point
  109  return task_share;
  110}
  111
  112static inline long setup_transaction(unsigned long status)
  113{
  114  long err;
  115
  116  err = 0;
  117  if(current->pk == NULL) {
  118    dbg();
  119                current->pk = init_pk_task((PK_TR_STARTED | status));
  120    if(current->pk == NULL) {
  121      dbg();
  122      err = -ENOMEM;
  123      goto out;
  124    }
  125        } else {
  126    PK_CUR_TASK_LOCK;
  127    dbg();
  128                if(current->pk->status & PK_TR_ABORTED) {
  129      dbg();
  130      err = -EABRT;
  131                } else if(current->pk->status & PK_TR_ABORT_PENDING) {
  132      err = -EABRTPENDING;
  133      BUG();
  134    } else if(current->pk->status & PK_TR_STOPPED) {
  135      dbg();
  136      current->pk->status = PK_TR_STARTED;
  137    }
  138    else if(current->pk->status & PK_TR_ABORT_INPROGRESS) {
  139      dbg();
  140      err = -EABRT;
  141    }
  142    if(err == 0)
  143      current->pk->status |= status;
  144    PK_CUR_TASK_UNLOCK;
  145        }
  146
  147out:
  148  return err;
  149}
  150
  151////////////////////////////////////////////////////////////////////////////////
  152/// Functions to search {log|share} regions in pkMem
  153////////////////////////////////////////////////////////////////////////////////
  154static inline struct pk_share *search_shareHEAD(unsigned long start)
  155{
  156  struct list_head *idx;
  157  struct pk_share *share;
  158  
  159  PK_LOCK;
  160  list_for_each(idx, &pk_shareHEAD) {
  161    share = list_entry(idx, struct pk_share, list);
  162    if(share->start == start) {
  163      PK_SHARE_LOCK(share);
  164      if(share->status & PK_ST_DEL
  165         || share->status & PK_ST_DEL_FINAL)
  166        share = NULL;
  167      else
  168        share->refcnt++;
  169      PK_SHARE_UNLOCK(share);
  170      goto out;
  171    }
  172  }
  173
  174  share = NULL;
  175out:
  176  PK_UNLOCK;
  177  return share;
  178}
  179
  180/// This function searches if a struct pk_share object that is in the pk_shareHEAD
  181/// global list, can be found in the task's pk_share_head list
  182static inline struct pk_task_share *search_share_head(struct pk_share *share)
  183{
  184  struct list_head *idx;
  185  struct pk_task_share *task_share;
  186
  187  list_for_each(idx, &current->pk->share_head) {
  188    task_share = list_entry(idx, struct pk_task_share, list);
  189    if(task_share->share == share)
  190      goto out;
  191  }
  192  
  193  task_share = NULL;
  194out:
  195  return task_share;
  196}
  197
  198/// During rollback this function checks if the address given has been obtained
  199/// by the process for exclusive accesse either via an alloc or a pk_get
  200static inline int __share_addr_in_range(unsigned long addr)
  201{
  202  struct list_head *idx;
  203  struct pk_task_share *task_share;
  204  unsigned long start, pages, status;
  205  int err;
  206  
  207  err = 0;
  208  list_for_each(idx, &current->pk->share_head) {
  209    task_share = list_entry(idx, struct pk_task_share, list);
  210    status = task_share->status;
  211    if(status & PK_PROC_ALLOC || status & PK_PROC_GOT_WR) {
  212      start = task_share->share->start;
  213      pages = task_share->share->pages;
  214      if(start <= addr && addr <= (start + pages * PAGE_SIZE))
  215        goto out;
  216    }
  217  }
  218  err = -1;
  219out:
  220  return err;
  221}
  222
  223/// This function searches if a struct pk_basic object that is in the
  224/// logs_head list can be found
  225static inline struct pk_basic *search_logs_head(unsigned long start)
  226{
  227  struct list_head *idx;
  228  struct pk_basic *log;
  229  
  230  list_for_each(idx, &current->pk->logs_head) {
  231    log = list_entry(idx, struct pk_basic, list);
  232    if(log->start == start)
  233      goto out;
  234  }
  235  log = NULL;
  236out:
  237  return log;
  238}
  239
  240/// During rollback this function checks if the address given does indeed refer
  241/// to a start address of a log page
  242static inline int __log_addr_in_range(unsigned long addr)
  243{
  244  struct list_head *idx;
  245  struct pk_basic *log;
  246  int err;
  247
  248  err = 0;
  249  list_for_each(idx, &current->pk->logs_head) {
  250    log = list_entry(idx, struct pk_basic, list);
  251    if((unsigned long)log->start == addr)
  252      goto out;
  253  }
  254  err = -1;
  255out:
  256  return err;
  257}
  258
  259////////////////////////////////////////////////////////////////////////////////
  260/// Create the pkMem file in memory
  261////////////////////////////////////////////////////////////////////////////////
  262
  263/// The internal pkmem filesystem that represents the entire pkMem region
  264static struct file_system_type pkmemfs_fs_type = {
  265  .owner          = THIS_MODULE,
  266        .name           = "pkmemfs",
  267        .get_sb         = ramfs_get_sb,
  268        .kill_sb        = kill_litter_super,
  269};      
  270
  271struct file *__file_setup(char *name, loff_t size)
  272{
  273        int error;
  274        struct file *file;
  275        struct inode *inode;
  276        struct dentry *dentry, *root;
  277        struct qstr this;
  278
  279        if (IS_ERR(pkmem_mnt))
  280                return (void *)pkmem_mnt;
  281
  282        error = -ENOMEM;
  283        this.name = name;
  284        this.len = strlen(name);
  285        this.hash = 0; /* Make file (deleted) in /proc/<pid>/maps */
  286        root = pkmem_mnt->mnt_root;
  287        dentry = d_alloc(root, &this);
  288  if (!dentry)
  289                goto put_memory;
  290        error = -ENFILE;
  291        file = get_empty_filp();
  292        if (!file)
  293                goto put_dentry;
  294
  295        error = -ENOSPC;
  296        inode = ramfs_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0);
  297        if (!inode)
  298                goto close_file;
  299
  300        d_instantiate(dentry, inode);
  301        inode->i_size = size;
  302        inode->i_nlink = 0;     /* It is unlinked */
  303        file->f_vfsmnt = mntget(pkmem_mnt);
  304        file->f_dentry = dentry;
  305        file->f_mapping = inode->i_mapping;
  306        file->f_op = &ramfs_file_operations;
  307        file->f_mode = FMODE_WRITE | FMODE_READ;
  308  return file;
  309
  310close_file:
  311        put_filp(file);
  312put_dentry:
  313        dput(dentry);
  314put_memory:
  315        return ERR_PTR(error);
  316}
  317
  318int attach_pkmem(void)
  319{
  320        if(IS_ERR(pk_file))
  321                return -1;
  322  down_write(&current->mm->mmap_sem);
  323  do_mmap(pk_file, PKMEM_START, PKMEM_SIZE, PROT_NONE, MAP_SHARED, 0);
  324  up_write(&current->mm->mmap_sem);
  325  
  326  return 0;
  327}
  328
  329static int __init init_pkmemfs(void)
  330{      
  331  int error;
  332  loff_t size;
  333  struct pk_basic *basic;
  334
  335  size = PKMEM_SIZE;
  336  pk_lock = SPIN_LOCK_UNLOCKED;
  337  error = register_filesystem(&pkmemfs_fs_type);
  338  if (error) {
  339    printk(KERN_ERR "pkMem: Could not register pkmemfs\n");
  340    goto out2;
  341  }
  342
  343        devfs_mk_dir("pkmem");
  344        pkmem_mnt = kern_mount(&pkmemfs_fs_type);
  345  if (IS_ERR(pkmem_mnt)) {
  346    printk(KERN_ERR "pkMem: Could not kern_mount pkmemfs\n");
  347    error = PTR_ERR(pkmem_mnt);
  348    goto out1;
  349  }
  350      
  351        pk_file = __file_setup("pkmem", size);
  352        if(IS_ERR(pk_file)) {
  353    error = -1;
  354    goto out1;
  355  }
  356
  357        pk_file->f_op = &ramfs_file_operations;
  358        pk_basic_cachep = kmem_cache_create("pk_basic",
  359               sizeof(struct pk_basic),
  360               0, SLAB_RECLAIM_ACCOUNT,
  361               NULL, NULL);
  362  pk_share_cachep = kmem_cache_create("pk_share",
  363               sizeof(struct pk_share),
  364               0, SLAB_RECLAIM_ACCOUNT,
  365               NULL, NULL);
  366        pk_task_cachep = kmem_cache_create("pk_task",
  367               sizeof(struct pk_task),
  368               0, SLAB_RECLAIM_ACCOUNT,
  369               NULL, NULL);
  370        pk_task_share_cachep = kmem_cache_create("pk_task_share",
  371               sizeof(struct pk_task_share),
  372               0, SLAB_RECLAIM_ACCOUNT,
  373               NULL, NULL);
  374
  375  basic = init_pk_basic();
  376  basic->start = PKMEM_START;
  377  basic->pages = PKMEM_PAGES;
  378  list_add(&basic->list, &pk_freeHEAD);
  379  __pk_free_pages = PKMEM_PAGES;
  380        printk(KERN_INFO "pkMem: initialized\n");
  381  return 0;
  382out1:
  383  unregister_filesystem(&pkmemfs_fs_type);
  384out2:
  385  return error;
  386}
  387
  388module_init(init_pkmemfs)
  389
  390////////////////////////////////////////////////////////////////////////////////
  391/// __insert_into_freelist releases the pk_basic region pointed by insert
  392/// The caller needn't destroy the region. Since the region, which belongs to
  393/// the pk_logHEAD list is of type pk_basic and so are the nodes in the
  394/// pk_freeHEAD list. So all we have to do is just re-insert into sorted order
  395/// Hold PK_LOCK
  396////////////////////////////////////////////////////////////////////////////////
  397void __insert_into_freelist(struct pk_basic *insert)
  398{
  399  struct list_head *idx, *prev;
  400  struct pk_basic *ptr;
  401  
  402  // Insert the free space pointed to by the deleted node
  403  // into the sorted place in the pk_freeHEAD list
  404  // case 1: check if pk_freeHEAD list is empty
  405  if(list_empty(&pk_freeHEAD)) {
  406    dbg();
  407    list_add(&insert->list, &pk_freeHEAD);
  408    goto out;
  409  }
  410  // case 2: put entry in sorted position in pk_freeHEAD list
  411  prev = NULL;
  412  list_for_each(idx, &pk_freeHEAD) {
  413    ptr = list_entry(idx, struct pk_basic, list);
  414    prev = idx;
  415    if(insert->start < ptr->start) {
  416      dbg();
  417      list_add_tail(&insert->list, idx);
  418      goto out;
  419    }
  420  }
  421  // case 3: We need to put the entry in the end (case 3)
  422  list_add(&insert->list, prev);  
  423
  424out:
  425  __pk_free_pages += insert->pages;
  426  return;
  427}
  428
  429////////////////////////////////////////////////////////////////////////////////
  430/// __release_share_region releases the share region pointed by delete
  431/// The caller NEEDS to destroy the region. The caller must also allocate memory
  432/// for the insert node, which will eventually be inserted into the pk_freeHEAD
  433/// list. (insert = init_pk_basic();)
  434/// IMP: On err < 0 the caller must free insert
  435/// Hold PK_LOCK [Always], PK_SHARE_LOCK(share) [Except on pk_alloc, we needn't]
  436////////////////////////////////////////////////////////////////////////////////
  437int __release_share_region(struct pk_share *delete, struct pk_basic *insert)
  438{
  439  int err;
  440  struct list_head *idx;
  441  struct pk_share *share;
  442
  443  // Delete the node from the shareHEAD list
  444  err = -ENOEXIST;
  445  list_for_each(idx, &pk_shareHEAD) {
  446    share = list_entry(idx, struct pk_share, list);
  447    if(share == delete) {
  448      dbg();
  449      list_del(&share->list);
  450      err = 0;
  451      break;
  452    }
  453  }
  454
  455  if(err == -ENOEXIST) {
  456    dbg();
  457    goto out;
  458  }
  459  insert->start = delete->start;
  460  insert->pages = delete->pages;
  461  __insert_into_freelist(insert);
  462
  463out:
  464  return err;
  465}
  466
  467////////////////////////////////////////////////////////////////////////////////
  468/// __dec_share_refcnt decrements the share->refcnt and if the region
  469/// has been marked for deletion, then it releases the region back
  470/// into the free list
  471////////////////////////////////////////////////////////////////////////////////
  472void __dec_share_refcnt(struct pk_share *share)
  473{
  474  struct pk_basic *insert;
  475
  476  PK_SHARE_LOCK(share);
  477  if(--share->refcnt == 0 && share->status & PK_ST_DEL_FINAL) {
  478    PK_SHARE_UNLOCK(share);
  479    dbg();
  480    insert = init_pk_basic();
  481    
  482    if(!insert) {
  483      dbg();
  484      goto out;
  485    }
  486    PK_LOCK;
  487    PK_SHARE_LOCK(share);
  488
  489    if(__release_share_region(share, insert) < 0) {
  490      dbg();
  491      kmem_cache_free(pk_basic_cachep, insert);
  492    }
  493    else {
  494      dbg();
  495      PK_SHARE_UNLOCK(share);
  496      kmem_cache_free(pk_share_cachep, share);
  497      goto unlock;
  498    }
  499    dbg();
  500    PK_SHARE_UNLOCK(share);
  501    goto unlock;
  502  }
  503  dbg();
  504  PK_SHARE_UNLOCK(share);
  505  goto out;
  506
  507unlock:
  508  PK_UNLOCK;
  509out:
  510  return;
  511}
  512
  513////////////////////////////////////////////////////////////////////////////////
  514/// __merge_free_list(): merges consecutive entries in the free list
  515/// and returns the largest consecutive region that it has merged
  516////////////////////////////////////////////////////////////////////////////////
  517int __merge_free_list(void)
  518{
  519  unsigned long page_cnt;
  520  struct list_head *idx;
  521  struct pk_basic *cur, *prev;
  522
  523  page_cnt = 0;
  524restart:
  525  prev = NULL;
  526  PK_LOCK;
  527  list_for_each(idx, &pk_freeHEAD) {
  528    dbg();
  529    cur = list_entry(idx, struct pk_basic, list);
  530    if(prev) {
  531      dbg();
  532      if(prev->start + (prev->pages * PAGE_SIZE)
  533         == cur->start) {
  534        dbg();
  535        prev->pages += cur->pages;
  536        list_del(&cur->list);
  537        if(page_cnt < cur->pages) {
  538          dbg();
  539          page_cnt = prev->pages;
  540        }
  541        PK_UNLOCK;
  542        kmem_cache_free(pk_basic_cachep, cur);
  543        dbg();
  544        goto restart;
  545      }
  546    }
  547    prev = cur;
  548  }
  549  PK_UNLOCK;
  550
  551  dbg("page_cnt: %lu", page_cnt);
  552  return page_cnt;
  553}
  554
  555////////////////////////////////////////////////////////////////////////////////
  556/// __split_free_list(pages): Splits free list, to satisfy the
  557/// allocation for 'pages' number of pages. It returns the start
  558/// address of the allocation
  559////////////////////////////////////////////////////////////////////////////////
  560unsigned long __split_free_list(unsigned long pages)
  561{
  562  int try;
  563  unsigned long addr;
  564  struct list_head *idx;
  565  struct pk_basic *free_entry;
  566
  567  addr = try = 0;
  568  PK_LOCK;
  569  if(__pk_free_pages < pages) {
  570    PK_UNLOCK;
  571    dbg("__pk_free_pages %lu\n", __pk_free_pages);
  572    goto out;
  573  }
  574
  575retry:
  576  try++;
  577  list_for_each(idx, &pk_freeHEAD) {
  578    dbg();
  579    free_entry = list_entry(idx, struct pk_basic, list);
  580    if(free_entry->pages >= pages) {
  581      dbg();
  582      addr = free_entry->start;
  583      __pk_free_pages -= pages;
  584      free_entry->start += (pages * PAGE_SIZE);
  585      free_entry->pages -= pages;
  586      if(free_entry->pages == 0) {
  587        dbg();
  588        list_del(&free_entry->list);
  589        kmem_cache_free(pk_basic_cachep, free_entry);
  590      }
  591      PK_UNLOCK;
  592      goto out;
  593    }
  594  }
  595  PK_UNLOCK;
  596
  597  if(__merge_free_list() >= pages && try <= 2) {
  598    PK_LOCK;
  599    goto retry;
  600  }
  601
  602out:
  603  dbg("__pk_free_pages %lu\n", __pk_free_pages);
  604  return addr;
  605}
  606
  607////////////////////////////////////////////////////////////////////////////////
  608/// __alloc_share_regions(pages): returns a shareable region by
  609/// splitting the free list  
  610/// IMPORTANT: It is upto the caller of this function, to add the
  611/// share region into the pk_shareHEAD list
  612/// i.e. list_add(&share->list, &pk_shareHEAD);
  613////////////////////////////////////////////////////////////////////////////////
  614struct pk_share *__alloc_share_regions(unsigned int pages)
  615{
  616  unsigned long addr;
  617  struct pk_share *share;
  618  
  619  dbg("__pk_free_pages %lu\n", __pk_free_pages);
  620  share = NULL;
  621  addr = __split_free_list(pages);
  622
  623  if(addr == 0) {
  624    dbg();
  625    goto out;
  626  }
  627  share = init_pk_share();
  628
  629  if(!share) {
  630    dbg();
  631    goto out;
  632  }
  633  share->start = addr;
  634  share->pages = pages;
  635out:
  636  return share;
  637}
  638
  639////////////////////////////////////////////////////////////////////////////////
  640/// __alloc_log_pages(pages): returns a log region by
  641/// splitting the free list  
  642////////////////////////////////////////////////////////////////////////////////
  643struct pk_basic *__alloc_log_pages(unsigned int pages)
  644{
  645  unsigned long addr;
  646  struct pk_basic *log;
  647
  648  dbg("__pk_free_pages %lu\n", __pk_free_pages);
  649  log = NULL;
  650  addr = __split_free_list(pages);
  651  
  652  if(addr == 0) {
  653    dbg();
  654    goto out;
  655  }
  656  log = init_pk_basic();
  657  
  658  if(!log) {
  659    dbg();
  660    goto out;
  661  }
  662  log->start = addr;
  663  log->pages = pages;
  664out:
  665  return log;
  666}
  667
  668////////////////////////////////////////////////////////////////////////////////
  669/// __rollback performs the rollback by following the records given in the
  670/// task's log regions
  671////////////////////////////////////////////////////////////////////////////////
  672void __rollback(unsigned long start)
  673{
  674  // __log_addr_in_range(unsigned long addr); 0 or -1
  675  // __share_addr_in_range(unsigned long addr); 0 or -1
  676  dbg();
  677  PK_LOCK;
  678
  679  PK_UNLOCK;
  680}
  681
  682////////////////////////////////////////////////////////////////////////////////
  683/// __release_log_regions(). Called from do_exit() to release the log regions
  684/// that the process has obtained. The status of the transaction at this point
  685/// is always PK_TR_ABORTED or PK_TR_STOPPED
  686////////////////////////////////////////////////////////////////////////////////
  687void __release_log_regions(struct pk_task *pk)
  688{
  689  struct list_head *idx;
  690  struct pk_basic *log_region;
  691
  692  while(!list_empty(&pk->logs_head)) {
  693    dbg();
  694    idx = pk->logs_head.next;
  695    log_region = list_entry(idx, struct pk_basic, list);
  696    list_del(idx);
  697    __insert_into_freelist(log_region);
  698  }
  699}
  700
  701////////////////////////////////////////////////////////////////////////////////
  702/// __do_abort(). The main body of the __do_abort call
  703/// it finally sets the task's status to PK_TR_ABORTED and only a pk_end()
  704/// will set the status to PK_TR_STOPPED. From then on, new transactions can be
  705/// started
  706////////////////////////////////////////////////////////////////////////////////
  707long __do_abort(struct task_struct *task, int call_mprotect)
  708{
  709  long err;
  710  struct list_head *idx;
  711  struct pk_task *pk;
  712  struct pk_task_share *task_share;
  713  struct pk_basic *log_region;
  714  
  715  err = 0;
  716  pk = task->pk;
  717  
  718  if(!task) {
  719    err = -EBUG;
  720    BUG();
  721    goto out;
  722  }
  723  
  724  if(!pk) {
  725    dbg();
  726    goto out;
  727  }
  728  
  729  // If we are interrupting another pk_* system call then we set the
  730  // status to PK_TR_ABORT_PENDING otherwise we set the status to note
  731  // that and abort is in progress with PK_TR_ABORT_INPROGRESS
  732  PK_TASK_LOCK(pk);
  733  if(pk->status & PK_TR_SYS_INPROGRESS) {
  734    dbg();
  735    PK_TASK_UNLOCK(pk);
  736    pk->status |= PK_TR_ABORT_PENDING;
  737    goto out;
  738  }
  739  else {
  740    dbg();
  741    pk->status |= PK_TR_ABORT_INPROGRESS;
  742  }
  743  PK_TASK_UNLOCK(pk);
  744
  745  // Perform rollback
  746  if(!list_empty(&pk->logs_head)) {
  747    idx = pk->logs_head.next;
  748    log_region = list_entry(idx, struct pk_basic, list);
  749    __rollback(log_region->start);
  750  }
  751
  752  // 1. We iterate over all the shared regions in the task's share_head
  753  //  list and remove the pk_task_share nodes from the share's task_head
  754  //  list.
  755  // 2. Undo
  756  //  If a region has been: ALLOCED + FREED then delete it (default)
  757  //  If a region has been: FREEED don't delete
  758  //  If a region has been: ALLOCED, then delete it
  759  // 3. Call mprotect(): Since we need to unmap the memory regions that
  760  //  that the task_share elements in the task's share_head list point to
  761  //  NOTE: If PK_PROC_FREE only then don't call mprotect().  All other
  762  //  possible combinations call mprotect()
  763  // 4. dec refcnts of the share regions
  764  list_for_each(idx, &pk->share_head) {
  765    unsigned long start, pages;
  766    // 1.
  767                task_share = list_entry(idx, struct pk_task_share, list);
  768    PK_LOCK;
  769    PK_SHARE_LOCK(task_share->share);
  770    list_del(&task_share->list_task);
  771
  772    // 2.
  773    // NOTE: We can call PK_UNLOCK here, but we call it below to be
  774    // consistent
  775    if(task_share->status & PK_PROC_FREE  &&
  776       !(task_share->status & PK_PROC_ALLOC))
  777      task_share->share->status &= ~(PK_ST_DEL);
  778    else if(task_share->status & PK_PROC_ALLOC)
  779      task_share->share->status |= PK_ST_DEL_FINAL;
  780    PK_SHARE_UNLOCK(task_share->share);
  781    PK_UNLOCK;
  782    
  783    // 3.
  784    PK_SHARE_LOCK(task_share->share);
  785    start = task_share->share->start;
  786    pages = task_share->share->pages;
  787    PK_SHARE_UNLOCK(task_share->share);
  788    if(call_mprotect) {
  789      dbg();
  790      if(!((task_share->status & PK_PROC_FREE)
  791           && !(task_share->status & PK_PROC_GOT_WR)
  792           && !(task_share->status & PK_PROC_ALLOC))) {
  793        dbg("undoing mprotect at %lu, pages %lu", start,
  794            pages);
  795        err = mprotect_for_task(task, start, pages
  796              * PAGE_SIZE, PROT_NONE);
  797        if(err < 0) {
  798          BUG();
  799          err = -EMPROTECT;
  800          goto out;
  801        }
  802      }
  803    }
  804    // 4.
  805    __dec_share_refcnt(task_share->share);
  806    dbg();
  807  }
  808  
  809  // Empty the elements in the task's pk->share_head list and free the
  810  // task_share structure
  811  while(!list_empty(&pk->share_head)) {
  812    dbg();
  813    idx = pk->share_head.next;
  814    list_del(idx);
  815    kmem_cache_free(pk_task_share_cachep, idx);
  816  }
  817  
  818  // Set the status of the transaction to PK_TR_ABORTED
  819  PK_TASK_LOCK(pk);
  820  pk->status = PK_TR_ABORTED;
  821  PK_TASK_UNLOCK(pk);
  822  err = -EABRT;
  823out:
  824  return err;
  825}
  826
  827////////////////////////////////////////////////////////////////////////////////
  828/// __advance_queue() makes sure no task holds a shareable region for ever
  829////////////////////////////////////////////////////////////////////////////////
  830long __advance_queue(struct pk_task_share *task_share, unsigned long status)
  831{
  832  long err;
  833  struct list_head *idx;
  834  struct pk_task_share *ts;
  835  unsigned long alloted_time, current_time;
  836
  837  err = 0;
  838  GET_SEMAPHORE(task_share, status);
  839  PK_SHARE_LOCK(task_share->share);
  840
  841  // Has the region been marked for deletion while we waited for it?
  842  if(task_share->share->status & PK_ST_DEL ||
  843     task_share->share->status & PK_ST_DEL_FINAL) {
  844    dbg(); err = -EDELETED; goto out;
  845  }
  846
  847  // If there is no one currently holding the region, then we just add
  848  // ourselves to the list of users after setting the status of the region
  849  if(list_empty(&task_share->share->task_head)) {
  850    dbg();
  851    task_share->share->status |= status;
  852    goto add;
  853  }
  854
  855  // Case 1: If there are currently readers to the region and we've
  856  // requested a read lock
  857  if((task_share->share->status & PK_FL_RDLCK) && (status & PK_FL_RDLCK)) {
  858    dbg();
  859    goto add;
  860  }
  861  
  862  // Case 2: share->status & PK_FL_RDLCK && status & PK_FL_WRLCK
  863  // Case 3: share->status & PK_FL_WRLCK
  864  // - If alloted_time <= current_time, then abort the process!
  865  // - Otherwise wait for time differential to elapse and retry
  866_continue:
  867  dbg();
  868  while(!list_empty(&task_share->share->task_head)) {
  869    list_for_each(idx, &task_share->share->task_head) {
  870      ts = list_entry(idx, struct pk_task_share, list_task);
  871      current_time = jiffies;
  872      alloted_time = ts->jiffies + PK_TIMEOUT;
  873      dbg("current_time %lu ts->jiffies %lu alloted_time %lu",
  874          current_time, ts->jiffies, alloted_time);
  875      if(time_before_eq(alloted_time, current_time)) {
  876        PK_SHARE_UNLOCK(task_share->share);
  877        dbg("calling __do_abort %d -> %d",
  878            current->pid, ts->task->pid);
  879        __do_abort(ts->task, 1);
  880        PK_SHARE_LOCK(task_share->share);
  881        goto _continue;
  882      }
  883      else {
  884        long diff;
  885        diff = (long) alloted_time - (long) current_time;
  886        dbg("sleep for diff = %lu", diff);
  887        PK_SHARE_UNLOCK(task_share->share);
  888        set_current_state(TASK_UNINTERRUPTIBLE);
  889        schedule_timeout(diff);
  890        PK_SHARE_LOCK(task_share->share);
  891        goto _continue;
  892      }
  893    }
  894  }
  895  
  896  // Update the status of share (other cases the status stays the same)
  897  if(task_share->share->status & PK_FL_RDLCK && status & PK_FL_WRLCK) {
  898    dbg();
  899    task_share->share->status &= ~(PK_FL_RDLCK);
  900    task_share->share->status |= PK_FL_WRLCK;
  901  }
  902  
  903  if(task_share->share->status & PK_FL_WRLCK && status & PK_FL_RDLCK) {
  904    dbg();
  905    task_share->share->status &= ~(PK_FL_WRLCK);
  906    task_share->share->status |= PK_FL_RDLCK;
  907  }
  908add:
  909  task_share->jiffies = jiffies;
  910  dbg("jiffies assigned to task_share %lu", task_share->jiffies);
  911  list_add_tail(&task_share->list_task, &task_share->share->task_head);
  912out:
  913  PK_SHARE_UNLOCK(task_share->share);
  914  RELEASE_SEMAPHORE(task_share, status);
  915  return err;
  916}
  917
  918////////////////////////////////////////////////////////////////////////////////
  919/// The pk_alloc_log() system call
  920////////////////////////////////////////////////////////////////////////////////
  921asmlinkage long sys_pk_alloc_log(unsigned long pages, unsigned long flag)
  922{
  923  long err;
  924  struct pk_basic *log;
  925  
  926  // Initialize the transaction and/or change its status
  927  err = setup_transaction(PK_TR_SYS_INPROGRESS);
  928  if(err == -ENOMEM || err == -EABRT)
  929    goto out;
  930
  931  log =  __alloc_log_pages(pages);
  932  if(!log) {
  933    dbg();
  934    err = -ENOMEM;
  935    goto out;
  936  }
  937
  938  err = mprotect_for_task(current, log->start, pages * PAGE_SIZE,
  939        (PROT_READ | PROT_WRITE));
  940  if(err < 0) {
  941    BUG();  
  942    err = -EMPROTECT;
  943    PK_LOCK;
  944    __insert_into_freelist(log);
  945    PK_UNLOCK;
  946    goto out;
  947  }
  948  err = log->start;
  949  list_add_tail(&log->list, &current->pk->logs_head);
  950
  951  // Did someone abort us, while we were executing this call?
  952  // If so, then it is _our_ responsibility to abort the transaction
  953  PK_CUR_TASK_LOCK;
  954  if(current->pk->status & PK_TR_ABORT_PENDING) {
  955    PK_CUR_TASK_UNLOCK;
  956    dbg("calling __do_abort on %d", current->pid);
  957    err = __do_abort(current, 1);
  958    goto out;
  959  }
  960  current->pk->status &= ~(PK_TR_SYS_INPROGRESS);
  961  PK_CUR_TASK_UNLOCK;
  962out:
  963  force_successful_syscall_return();
  964  return err;
  965}
  966
  967////////////////////////////////////////////////////////////////////////////////
  968///  The sys_pk_alloc() system call
  969////////////////////////////////////////////////////////////////////////////////
  970asmlinkage long sys_pk_alloc(unsigned long pages)
  971{
  972  long err;
  973  struct pk_share *share;
  974  struct pk_task_share *task_share;
  975  struct pk_basic *insert;
  976
  977  // Initialize the transaction and/or change its status
  978  err = setup_transaction(PK_TR_SYS_INPROGRESS);
  979  if(err == -ENOMEM || err == -EABRT)
  980    goto out;
  981  task_share = init_pk_task_share();
  982  if(!task_share) {
  983    err = -ENOMEM;
  984    goto reset;
  985  }
  986
  987  share = __alloc_share_regions(pages);
  988  if(!share) {
  989    dbg();
  990    err = -ENOMEM;
  991    kmem_cache_free(pk_task_share_cachep, task_share);
  992    goto reset;
  993  }
  994  
  995  task_share->share = share;
  996  task_share->status = PK_PROC_ALLOC | PK_FL_WRLCK;
  997  share->status = PK_FL_WRLCK;
  998  err = mprotect_for_task(current, share->start, pages * PAGE_SIZE,
  999        (PROT_READ | PROT_WRITE));
  1000  if(err < 0) {
  1001    BUG();
  1002    err = -EMPROTECT;
  1003    insert = init_pk_basic();
  1004    // Release the share region to the free list
  1005    PK_LOCK;
  1006    PK_SHARE_LOCK(share);
  1007    if(__release_share_region(share, insert) < 0)
  1008      kmem_cache_free(pk_basic_cachep, insert);
  1009    PK_SHARE_UNLOCK(share);
  1010    PK_UNLOCK;
  1011    // Free memory allocated to share
  1012    kmem_cache_free(pk_share_cachep, share);
  1013    kmem_cache_free(pk_task_share_cachep, task_share);
  1014    goto reset;
  1015  }
  1016
  1017  err = share->start;
  1018  // Now that memory protection has been setup
  1019  // - Link up this task_share node with the task's share_head list
  1020  // - Link up this task_share node with region's task_head list
  1021  // - Increment the refcnt of the region, no one _can_ possibly
  1022  //   use the region now, so don't bother holding the share->lock
  1023  // NOTE: There is no point in holding the share->lock as there
  1024  // can be no contention for the lock
  1025  list_add(&task_share->list, &current->pk->share_head);
  1026  list_add_tail(&task_share->list_task, &share->task_head);
  1027  share->refcnt++;
  1028  
  1029  // Add the share region to the global shareable region list
  1030  PK_LOCK;
  1031  list_add(&share->list, &pk_shareHEAD);
  1032  PK_UNLOCK;
  1033  
  1034  // Did someone abort us, while we were executing this call?
  1035  // If so, then it is _our_ responsibility to abort the transaction
  1036  PK_CUR_TASK_LOCK;
  1037  if(current->pk->status & PK_TR_ABORT_PENDING) {
  1038    PK_CUR_TASK_UNLOCK;
  1039    dbg("calling __do_abort on %d", current->pid);
  1040    err = __do_abort(current, 1);
  1041    goto out;
  1042  }
  1043
  1044  current->pk->status &= ~(PK_TR_SYS_INPROGRESS);
  1045  PK_CUR_TASK_UNLOCK;
  1046  goto out;
  1047reset:
  1048  PK_CUR_TASK_LOCK;
  1049  current->pk->status &= ~(PK_TR_SYS_INPROGRESS);
  1050  PK_CUR_TASK_UNLOCK;
  1051out:
  1052  force_successful_syscall_return();
  1053  return err;
  1054}
  1055
  1056////////////////////////////////////////////////////////////////////////////////
  1057/// sys_pk_get()
  1058////////////////////////////////////////////////////////////////////////////////
  1059asmlinkage long sys_pk_get(unsigned long start, unsigned long flag)
  1060{
  1061  long err;
  1062  unsigned long prot;
  1063  struct pk_share *share;
  1064  struct pk_task_share *task_share;  
  1065  
  1066  // Check if the parameters to the syscall are correct
  1067  if(flag & ~(PK_FL_WRLCK | PK_FL_RDLCK)) {
  1068    dbg();
  1069    err = -EINVAL;
  1070    goto out;
  1071  }
  1072  
  1073  // Initialize the transaction and/or change its status
  1074  err = setup_transaction(PK_TR_SYS_INPROGRESS);
  1075  if(err == -ENOMEM || err == -EABRT) {
  1076    dbg();
  1077    goto out;
  1078  }
  1079  
  1080  // First off, search the shareHEAD list, to see if the region
  1081  // exists in the first place; if it does exist, then we increment
  1082  // the share->refcnt of the region (IMPORTANT)
  1083  share = search_shareHEAD(start);
  1084  if(!share) {
  1085    dbg();
  1086    err = -ENOEXIST;
  1087    goto reset;
  1088  }
  1089
  1090  // The region does exist, now we check to make sure we haven't
  1091  // already got, free-ed, or alloced the same region in the
  1092  // current transaction
  1093  // Case #1:  We have alloced this region; If a request for WRLCK was
  1094  // made then the request is ignored. If a request for RDLCK is made then
  1095  // we return with an error stating ENODGRADE (no downgrading lock!)
  1096  // Case #2:  We have already free-ed this region; signal error because
  1097  // it makes _no_ sense to obtain a RDLCK or WRLCK on the region
  1098  // Case #3a: We have already got WRLCK on this region; Then the cases
  1099  // are identical to case #1
  1100  // Case #3b:  We already got RDLCK on this region; If a request for
  1101  // WRLCK is made then return ENUGRADE (no upgrading lock!); If a request
  1102  // for RDLCK is made then the request is ignored
  1103  task_share = search_share_head(share);
  1104  if(task_share) {
  1105    dbg();
  1106    if(task_share->status & PK_PROC_ALLOC
  1107       || task_share->status & PK_PROC_GOT_WR) {
  1108      if(flag & PK_FL_WRLCK) {
  1109        dbg();
  1110        err = share->pages;
  1111        goto dec;
  1112      }
  1113      else {
  1114        dbg();
  1115        err = -ENODGRADE;
  1116        goto dec;
  1117      }
  1118    }
  1119    else if(task_share->status & PK_PROC_FREE) {
  1120      dbg();
  1121      err = -EDELETED;
  1122      goto dec;
  1123    }
  1124    else if(task_share->status & PK_PROC_GOT_RD) {
  1125      if(flag & PK_FL_WRLCK) {
  1126        dbg();
  1127        err = -ENOUGRADE;
  1128        goto dec;
  1129      } else {
  1130        dbg();
  1131        err = share->pages;
  1132        goto dec;
  1133      }
  1134    }
  1135  }
  1136  
  1137  prot = PROT_READ;
  1138  // Initialize an object of the task_share struct, to link with share obj
  1139  task_share = init_pk_task_share();
  1140  if(!task_share) {
  1141    dbg();
  1142    err = -ENOMEM;
  1143    goto dec;
  1144  }
  1145  task_share->share = share;
  1146  if(flag & PK_FL_WRLCK) {
  1147    dbg();
  1148    prot |= (PROT_WRITE);
  1149    task_share->status = PK_PROC_GOT_WR;
  1150  }
  1151  else {
  1152    dbg();
  1153    task_share->status = PK_PROC_GOT_RD;
  1154  }
  1155  
  1156  // Advance the wait queue for the shareable region. No one should be
  1157  // allowed to hold a lock on a region for ever
  1158  err = __advance_queue(task_share, flag);
  1159  if(err < 0) {
  1160    dbg();
  1161    goto release;
  1162  }
  1163  
  1164  // Call mprotect to protect the region
  1165  err = mprotect_for_task(current, share->start, share->pages * PAGE_SIZE,
  1166        prot);
  1167  if(err < 0) {
  1168    BUG();
  1169    err = -EMPROTECT;
  1170    goto release;
  1171  }
  1172
  1173  // Link up this task_share node with the task's share_head list
  1174  list_add(&task_share->list, &current->pk->share_head);
  1175  
  1176  // Did someone abort us, while we were executing this call?
  1177  // If so, then it is _our_ responsibility to abort the transaction
  1178  PK_CUR_TASK_LOCK;
  1179  if(current->pk->status & PK_TR_ABORT_PENDING) {
  1180    PK_CUR_TASK_UNLOCK;
  1181    dbg("calling __do_abort on %d", current->pid);
  1182    err = __do_abort(current, 1);
  1183    goto out;
  1184  }
  1185  current->pk->status &= ~(PK_TR_SYS_INPROGRESS);
  1186  PK_CUR_TASK_UNLOCK;
  1187  err = share->pages;
  1188  goto out;
  1189
  1190release:
  1191        kmem_cache_free(pk_task_share_cachep, task_share);
  1192dec:
  1193  __dec_share_refcnt(share);
  1194reset:
  1195  PK_CUR_TASK_LOCK;
  1196  current->pk->status &= ~(PK_TR_SYS_INPROGRESS);
  1197  PK_CUR_TASK_UNLOCK;
  1198out:
  1199  force_successful_syscall_return();
  1200  return err;
  1201}
  1202
  1203////////////////////////////////////////////////////////////////////////////////
  1204/// sys_pk_free_log()
  1205////////////////////////////////////////////////////////////////////////////////
  1206asmlinkage long sys_pk_free_log(unsigned long start)
  1207{
  1208  long err;
  1209  struct pk_basic *remove;
  1210
  1211  // Success only if the status is PK_TR_STOPPED
  1212  err = -ENOTSTOPPED;
  1213  if(current->pk) {
  1214    dbg();
  1215    PK_CUR_TASK_LOCK;
  1216    if(current->pk->status & PK_TR_STOPPED)
  1217      err = 0;
  1218    PK_CUR_TASK_UNLOCK;
  1219  }
  1220  if(err < 0)
  1221    goto out;
  1222
  1223  // Check if a log region with log->start = start exists
  1224  // in the processes logs_head list
  1225  remove = search_logs_head(start);
  1226  if(!remove) {
  1227    dbg();
  1228    err = -ENOEXIST;
  1229    goto out;
  1230  }
  1231  
  1232  // Remove the log region from the task's logs_head list
  1233  list_del(&remove->list);
  1234
  1235  // Call mprotect to remove the physical memory protection
  1236  err = mprotect_for_task(current, remove->start,
  1237        remove->pages * PAGE_SIZE, PROT_NONE);
  1238  if(err < 0) {
  1239    BUG();
  1240    err = -EMPROTECT;
  1241    goto out;
  1242  }
  1243
  1244  // Now, we release the log region back into the free list
  1245  PK_LOCK;
  1246  __insert_into_freelist(remove);
  1247  PK_UNLOCK;
  1248
  1249out:
  1250  force_successful_syscall_return();
  1251  return err;
  1252}
  1253
  1254////////////////////////////////////////////////////////////////////////////////
  1255/// sys_pk_free()
  1256////////////////////////////////////////////////////////////////////////////////
  1257asmlinkage long sys_pk_free(unsigned long start)
  1258{
  1259  long err;
  1260  struct pk_share *share;
  1261  struct pk_task_share *task_share;
  1262  
  1263  // Initialize the transaction and/or change its status
  1264  err = setup_transaction(PK_TR_SYS_INPROGRESS);
  1265  if(err == -ENOMEM || err == -EABRT) {
  1266    dbg();
  1267    goto out;
  1268  }
  1269
  1270  // First off, search the shareHEAD list, to see if the region
  1271  // exists in the first place; if it does exist, then we increment
  1272  // the share->refcnt of the region (IMPORTANT)
  1273  share = search_shareHEAD(start);
  1274  if(!share) {
  1275    dbg();
  1276    err = -ENOEXIST;
  1277    goto reset;
  1278  }
  1279  
  1280  // If the region is found in the sharedH list, then we come up with the
  1281  // following cases
  1282  // Case #1: If the region has already been alloced, then we set the
  1283  // status of the shareable region to |= PK_ST_DEL
  1284  // Case #2: If the region has already been free-ed, then we return 0
  1285  // Case #3a: If the region has already been got (WRLCK) then it is the
  1286  // same situation as #1
  1287  // Case #3b: If the region has already been got (RDLCK) then we deny
  1288  // the operation
  1289  // FIXME? We never do an mprotect() to remove any protection that we
  1290  // have on an already alloced/got-wr region.
  1291  task_share = search_share_head(share);
  1292  if(task_share) {
  1293    dbg();
  1294    if(task_share->status & PK_PROC_ALLOC
  1295       || task_share->status & PK_PROC_GOT_WR) {
  1296      dbg();
  1297      task_share->status |= PK_PROC_FREE;
  1298      PK_SHARE_LOCK(task_share->share);
  1299      share->status |= PK_ST_DEL;
  1300      PK_SHARE_UNLOCK(task_share->share);
  1301      err = 0;
  1302      goto dec;
  1303    }
  1304    else if(task_share->status & PK_PROC_FREE) {
  1305      dbg();
  1306      err = 0;
  1307      goto dec;
  1308    }
  1309    else if(task_share->status & PK_PROC_GOT_RD) {
  1310      dbg();
  1311      err = -EDENIED;
  1312      goto dec;
  1313    }
  1314  }
  1315
  1316  // Initialize an object of the task_share struct, to link with share obj
  1317  task_share = init_pk_task_share();
  1318  if(!task_share) {
  1319    dbg();
  1320    err = -ENOMEM;
  1321    goto dec;
  1322  }
  1323  task_share->share = share;
  1324  task_share->status = PK_PROC_FREE;
  1325
  1326  // Advance the wait queue for the shareable region. No one should be
  1327  // allowed to hold a lock on a region for ever
  1328  err = __advance_queue(task_share, PK_FL_WRLCK);
  1329  if(err < 0) {
  1330    dbg();
  1331    goto release;
  1332  }
  1333
  1334  // Mark the region as deleted
  1335  PK_SHARE_LOCK(task_share->share);
  1336  share->status |= PK_ST_DEL;
  1337  PK_SHARE_UNLOCK(task_share->share);
  1338
  1339  // Link up this task_share node with the task's share_head list
  1340  list_add(&task_share->list, &current->pk->share_head);
  1341  
  1342  // Did someone abort us, while we were executing this call?
  1343  // If so, then it is _our_ responsibility to abort the transaction
  1344  PK_CUR_TASK_LOCK;
  1345  if(current->pk->status & PK_TR_ABORT_PENDING) {
  1346    PK_CUR_TASK_UNLOCK;
  1347    dbg("calling __do_abort on %d", current->pid);
  1348    err = __do_abort(current, 1);
  1349    goto out;
  1350  }
  1351
  1352  current->pk->status &= ~(PK_TR_SYS_INPROGRESS);
  1353  PK_CUR_TASK_UNLOCK;
  1354  goto out;
  1355
  1356release:
  1357        kmem_cache_free(pk_task_share_cachep, task_share);
  1358dec:
  1359  __dec_share_refcnt(share);
  1360reset:
  1361  PK_CUR_TASK_LOCK;
  1362  current->pk->status &= ~(PK_TR_SYS_INPROGRESS);
  1363  PK_CUR_TASK_UNLOCK;
  1364out:
  1365  force_successful_syscall_return();
  1366  return err;
  1367}
  1368
  1369////////////////////////////////////////////////////////////////////////////////
  1370/// sys_pk_end call
  1371////////////////////////////////////////////////////////////////////////////////
  1372asmlinkage long sys_pk_end(void)
  1373{
  1374  long err;
  1375  struct list_head *idx;
  1376  struct pk_task_share *task_share;
  1377  err = 0;
  1378  
  1379  // If the transaction has been stopped, then the call to pk_end is as
  1380  // good as a NOP. If the transaction has been aborted then set the
  1381  // status to stopped. If the transaction is currently being aborted,
  1382  // then userspace would need to call pk_end again. Else set the
  1383  // transaction to PK_SYS_IN_PROGRESS
  1384  if(current->pk) {
  1385    dbg();
  1386    PK_CUR_TASK_LOCK;
  1387    if(current->pk->status & PK_TR_STOPPED)
  1388      goto unlock;
  1389    else if(current->pk->status & PK_TR_ABORTED) {
  1390      dbg();
  1391      current->pk->status |= PK_TR_STOPPED;
  1392      err = -EABRT;
  1393      goto unlock;
  1394    }
  1395    else if(current->pk->status & PK_TR_ABORT_INPROGRESS) {
  1396      dbg();
  1397      err = -EABRTONGOING;
  1398      goto unlock;
  1399    }
  1400    else if(current->pk->status & PK_TR_STARTED) {
  1401      dbg();
  1402      current->pk->status |= PK_TR_SYS_INPROGRESS;
  1403    }
  1404  }
  1405  else {
  1406    dbg();
  1407    goto out;
  1408  }
  1409  PK_CUR_TASK_UNLOCK;
  1410
  1411  // 0. Delete the task_share node from the processes
  1412  // share_head list
  1413  // 1. Now, we need to unmap the memory regions point to by the
  1414  // task_share elements in the task's share_head list NOTE: If
  1415  // PK_PROC_FREE only then don't call mprotect().  All other
  1416  // possible combinations call mprotect() to remove protection If the
  1417  // region has been marked for deletion, then make sure it
  1418  // does get deleted. PK_ST_DEL_FINAL is needed to make sure the region
  1419  // is indeed released
  1420  // 2. We delete the task_share node from the share region's task_head
  1421  // list
  1422  // 3. We also decrement the refcnts of all the shared
  1423  // regions we have task_share->share
  1424  // 4. Free up the task_share datastructure
  1425  while(!list_empty(&current->pk->share_head)) {
  1426    unsigned long start, pages;
  1427    dbg();
  1428    idx = current->pk->share_head.next;
  1429    // 0.
  1430    list_del(idx);
  1431    task_share = list_entry(idx, struct pk_task_share, list);
  1432    // 1.
  1433    PK_SHARE_LOCK(task_share->share);
  1434    start = task_share->share->start;
  1435    pages = task_share->share->pages;
  1436    if(task_share->status & PK_PROC_FREE)
  1437      task_share->share->status |= PK_ST_DEL_FINAL;
  1438    PK_SHARE_UNLOCK(task_share->share);
  1439    if(!((task_share->status & PK_PROC_FREE)
  1440         && !(task_share->status & PK_PROC_GOT_WR)
  1441         && !(task_share->status & PK_PROC_ALLOC))) {
  1442      dbg("undoing mprotect at %lu, pages %lu", start, pages);
  1443      err = mprotect_for_task(current, start, pages
  1444            * PAGE_SIZE, PROT_NONE);
  1445      if(err < 0) {
  1446        BUG();
  1447        err = -EMPROTECT;
  1448        goto out;
  1449      }
  1450    }
  1451    // 2.
  1452    PK_LOCK;
  1453    PK_SHARE_LOCK(task_share->share);
  1454    list_del(&task_share->list_task);
  1455    PK_SHARE_UNLOCK(task_share->share);
  1456    PK_UNLOCK;
  1457    // 3.
  1458    __dec_share_refcnt(task_share->share);
  1459    // 4.
  1460    kmem_cache_free(pk_task_share_cachep, task_share);
  1461  }
  1462
  1463  // Set the status of the transaction to PK_TR_STOPPED
  1464  // NOTE: If someone aborts us during this call, we ignore it and still go
  1465  // ahead with the pk_end
  1466  PK_CUR_TASK_LOCK;
  1467  current->pk->status = PK_TR_STOPPED;
  1468
  1469unlock:
  1470  PK_CUR_TASK_UNLOCK;
  1471out:
  1472  force_successful_syscall_return();
  1473  return err;
  1474}