Partial locking for mempolicy in task_struct Currently the mempolicy in task_struct is a pointer to a structure containing policy information for a task that is protected by no locks meaning that only a currently executing task can reliably access that information. The memory policies in the vm_area struct are protected by mmap_sem. This means that memory policies from the vm_area_struct can be accessed after taking a readlock on mmap_sem. This patch extends the protection to all memory policies. Any writer to a memory policy must take an mmap_sem writelock. Readers take the mmap_sem readlock. However, this is not always possible since the policies are used in critical sections where we cannot affort to take an mmap_sem lock. We can therefore only protect against modifications and not exclude concurrent readers unless the modification is executed in the context of the task. The patch will therefore enable the reading of the memory policy from the task struct by taking mmap_sem. It does *not* allow changing the policy in task_struct. The memory policy must be changed from inside of the task_struct. Signed-off-by: Christoph Lameter Index: linux-2.6.13-rc5/mm/mempolicy.c =================================================================== --- linux-2.6.13-rc5.orig/mm/mempolicy.c 2005-08-05 09:29:11.000000000 -0700 +++ linux-2.6.13-rc5/mm/mempolicy.c 2005-08-05 09:36:07.000000000 -0700 @@ -450,6 +450,7 @@ asmlinkage long sys_set_mempolicy(int mo if (mode < 0 || mode > MPOL_MAX) return -EINVAL; + down_write(¤t->mm->mmap_sem); err = get_nodes(&nodes, nmask, maxnode, mode); if (err) return err; @@ -460,6 +461,7 @@ asmlinkage long sys_set_mempolicy(int mo current->mempolicy = new; if (new && new->policy == MPOL_INTERLEAVE) current->il_next = first_node(new->v.nodes); + up_write(¤t->mm->mmap_sem); return 0; } @@ -537,19 +539,21 @@ asmlinkage long sys_get_mempolicy(int __ return -EINVAL; if (nmask != NULL && maxnode < MAX_NUMNODES) return -EINVAL; + down_read(&mm->mmap_sem); if (flags & MPOL_F_ADDR) { - down_read(&mm->mmap_sem); vma = find_vma_intersection(mm, addr, addr + 1); if (!vma) { - up_read(&mm->mmap_sem); - return -EFAULT; + err = -EFAULT; + goto out; } if (vma->vm_ops && vma->vm_ops->get_policy) pol = vma->vm_ops->get_policy(vma, addr); else pol = vma->vm_policy; - } else if (addr) - return -EINVAL; + } else if (addr) { + err = -EINVAL; + goto out; + } if (!pol) pol = &default_policy; @@ -570,10 +574,8 @@ asmlinkage long sys_get_mempolicy(int __ } else pval = pol->policy; - if (vma) { - up_read(¤t->mm->mmap_sem); - vma = NULL; - } + up_read(&mm->mmap_sem); + vma = NULL; if (policy && put_user(pval, policy)) return -EFAULT; @@ -586,8 +588,7 @@ asmlinkage long sys_get_mempolicy(int __ } out: - if (vma) - up_read(¤t->mm->mmap_sem); + up_read(&mm->mmap_sem); return err; }