lkml.org 
[lkml]   [2007]   [Apr]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 09/33] holepunch: fix mmap_sem i_mutex deadlock
    -stable review patch.  If anyone has any objections, please let us know.

    ------------------
    From: Hugh Dickins <hugh@veritas.com>

    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 <hugh@veritas.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    mm/madvise.c | 19 ++++++++++++++-----
    1 file changed, 14 insertions(+), 5 deletions(-)

    --- a/mm/madvise.c
    +++ b/mm/madvise.c
    @@ -159,9 +159,10 @@ static long madvise_remove(struct vm_are
    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_are
    + ((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 lon
    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 linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-04-26 19:17    [W:0.021 / U:92.860 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site