Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=90ed52ebe48181d3c5427b3bd1d24f659e7575ad
Commit:     90ed52ebe48181d3c5427b3bd1d24f659e7575ad
Parent:     16a100190d39592d1d56ff5a0b978b20288c3427
Author:     Hugh Dickins <[EMAIL PROTECTED]>
AuthorDate: Thu Mar 29 01:20:38 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Thu Mar 29 08:22:26 2007 -0700

    [PATCH] holepunch: fix mmap_sem i_mutex deadlock
    
    sys_madvise has down_write of mmap_sem, then madvise_remove calls
    vmtruncate_range which takes i_mutex and i_alloc_sem: no, we can easily 
devise
    deadlocks from that ordering.
    
    madvise_remove drop mmap_sem while calling vmtruncate_range: luckily, since
    madvise_remove doesn't split or merge vmas, it's easy to handle this case 
with
    a NULL prev, without restructuring sys_madvise.  (Though sad to retake
    mmap_sem when it's unlikely to be needed, and certainly down_read is
    sufficient for MADV_REMOVE, unlike the other madvices.)
    
    Signed-off-by: Hugh Dickins <[EMAIL PROTECTED]>
    Cc: Miklos Szeredi <[EMAIL PROTECTED]>
    Cc: Badari Pulavarty <[EMAIL PROTECTED]>
    Cc: Nick Piggin <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 mm/madvise.c |   19 ++++++++++++++-----
 1 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/mm/madvise.c b/mm/madvise.c
index 77916e9..603c525 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -159,9 +159,10 @@ static long madvise_remove(struct vm_area_struct *vma,
                                unsigned long start, unsigned long end)
 {
        struct address_space *mapping;
-        loff_t offset, endoff;
+       loff_t offset, endoff;
+       int error;
 
-       *prev = vma;
+       *prev = NULL;   /* tell sys_madvise we drop mmap_sem */
 
        if (vma->vm_flags & (VM_LOCKED|VM_NONLINEAR|VM_HUGETLB))
                return -EINVAL;
@@ -180,7 +181,12 @@ static long madvise_remove(struct vm_area_struct *vma,
                        + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
        endoff = (loff_t)(end - vma->vm_start - 1)
                        + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
-       return  vmtruncate_range(mapping->host, offset, endoff);
+
+       /* vmtruncate_range needs to take i_mutex and i_alloc_sem */
+       up_write(&current->mm->mmap_sem);
+       error = vmtruncate_range(mapping->host, offset, endoff);
+       down_write(&current->mm->mmap_sem);
+       return error;
 }
 
 static long
@@ -315,12 +321,15 @@ asmlinkage long sys_madvise(unsigned long start, size_t 
len_in, int behavior)
                if (error)
                        goto out;
                start = tmp;
-               if (start < prev->vm_end)
+               if (prev && start < prev->vm_end)
                        start = prev->vm_end;
                error = unmapped_error;
                if (start >= end)
                        goto out;
-               vma = prev->vm_next;
+               if (prev)
+                       vma = prev->vm_next;
+               else    /* madvise_remove dropped mmap_sem */
+                       vma = find_vma(current->mm, start);
        }
 out:
        up_write(&current->mm->mmap_sem);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to