From dfe195fb79e88c334481f1362fef52f6d2e30b2d Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Tue, 5 Aug 2008 13:01:41 -0700 Subject: mm: fix uninitialized variables for find_vma_prepare callers gcc 4.3.0 correctly emits the following warnings. When a vma covering addr is found, find_vma_prepare indeed returns without setting pprev, rb_link, and rb_parent. mm/mmap.c: In function `insert_vm_struct': mm/mmap.c:2085: warning: `rb_parent' may be used uninitialized in this function mm/mmap.c:2085: warning: `rb_link' may be used uninitialized in this function mm/mmap.c:2084: warning: `prev' may be used uninitialized in this function mm/mmap.c: In function `copy_vma': mm/mmap.c:2124: warning: `rb_parent' may be used uninitialized in this function mm/mmap.c:2124: warning: `rb_link' may be used uninitialized in this function mm/mmap.c:2123: warning: `prev' may be used uninitialized in this function mm/mmap.c: In function `do_brk': mm/mmap.c:1951: warning: `rb_parent' may be used uninitialized in this function mm/mmap.c:1951: warning: `rb_link' may be used uninitialized in this function mm/mmap.c:1949: warning: `prev' may be used uninitialized in this function mm/mmap.c: In function `mmap_region': mm/mmap.c:1092: warning: `rb_parent' may be used uninitialized in this function mm/mmap.c:1092: warning: `rb_link' may be used uninitialized in this function mm/mmap.c:1089: warning: `prev' may be used uninitialized in this function Hugh adds: in fact, none of find_vma_prepare's callers use those values when a vma is found to be already covering addr, it's either an error or an occasion to munmap and repeat. Okay, let's quieten the compiler (but I would prefer it if pprev, rb_link and rb_parent were meaningful in that case, rather than whatever's in them from descending the tree). Signed-off-by: Benny Halevy Signed-off-by: Hugh Dickins Cc: "Ryan Hope" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mm/mmap.c') diff --git a/mm/mmap.c b/mm/mmap.c index 245c3d69067b..971d0eda754a 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -370,7 +370,7 @@ find_vma_prepare(struct mm_struct *mm, unsigned long addr, if (vma_tmp->vm_end > addr) { vma = vma_tmp; if (vma_tmp->vm_start <= addr) - return vma; + break; __rb_link = &__rb_parent->rb_left; } else { rb_prev = __rb_parent; -- cgit v1.2.2 From 454ed842d55740160334efc9ad56cfef54ed37bc Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 11 Aug 2008 09:30:25 +0200 Subject: lockdep: annotate mm_take_all_locks() The nesting is correct due to holding mmap_sem, use the new annotation to annotate this. Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar --- mm/mmap.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'mm/mmap.c') diff --git a/mm/mmap.c b/mm/mmap.c index 245c3d69067b..5d09d08a4120 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2273,14 +2273,14 @@ int install_special_mapping(struct mm_struct *mm, static DEFINE_MUTEX(mm_all_locks_mutex); -static void vm_lock_anon_vma(struct anon_vma *anon_vma) +static void vm_lock_anon_vma(struct mm_struct *mm, struct anon_vma *anon_vma) { if (!test_bit(0, (unsigned long *) &anon_vma->head.next)) { /* * The LSB of head.next can't change from under us * because we hold the mm_all_locks_mutex. */ - spin_lock(&anon_vma->lock); + spin_lock_nest_lock(&anon_vma->lock, &mm->mmap_sem); /* * We can safely modify head.next after taking the * anon_vma->lock. If some other vma in this mm shares @@ -2296,7 +2296,7 @@ static void vm_lock_anon_vma(struct anon_vma *anon_vma) } } -static void vm_lock_mapping(struct address_space *mapping) +static void vm_lock_mapping(struct mm_struct *mm, struct address_space *mapping) { if (!test_bit(AS_MM_ALL_LOCKS, &mapping->flags)) { /* @@ -2310,7 +2310,7 @@ static void vm_lock_mapping(struct address_space *mapping) */ if (test_and_set_bit(AS_MM_ALL_LOCKS, &mapping->flags)) BUG(); - spin_lock(&mapping->i_mmap_lock); + spin_lock_nest_lock(&mapping->i_mmap_lock, &mm->mmap_sem); } } @@ -2359,9 +2359,9 @@ int mm_take_all_locks(struct mm_struct *mm) if (signal_pending(current)) goto out_unlock; if (vma->anon_vma) - vm_lock_anon_vma(vma->anon_vma); + vm_lock_anon_vma(mm, vma->anon_vma); if (vma->vm_file && vma->vm_file->f_mapping) - vm_lock_mapping(vma->vm_file->f_mapping); + vm_lock_mapping(mm, vma->vm_file->f_mapping); } ret = 0; -- cgit v1.2.2 From 7cd5a02f54f4c9d16cf7fdffa2122bc73bb09b43 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 11 Aug 2008 09:30:25 +0200 Subject: mm: fix mm_take_all_locks() locking order Lockdep spotted: ======================================================= [ INFO: possible circular locking dependency detected ] 2.6.27-rc1 #270 ------------------------------------------------------- qemu-kvm/2033 is trying to acquire lock: (&inode->i_data.i_mmap_lock){----}, at: [] mm_take_all_locks+0xc2/0xea but task is already holding lock: (&anon_vma->lock){----}, at: [] mm_take_all_locks+0x70/0xea which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&anon_vma->lock){----}: [] __lock_acquire+0x11be/0x14d2 [] lock_acquire+0x5e/0x7a [] _spin_lock+0x3b/0x47 [] vma_adjust+0x200/0x444 [] split_vma+0x12f/0x146 [] mprotect_fixup+0x13c/0x536 [] sys_mprotect+0x1a9/0x21e [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff -> #0 (&inode->i_data.i_mmap_lock){----}: [] __lock_acquire+0xedb/0x14d2 [] lock_release_non_nested+0x1c2/0x219 [] lock_release+0x127/0x14a [] _spin_unlock+0x1e/0x50 [] mm_drop_all_locks+0x7f/0xb0 [] do_mmu_notifier_register+0xe2/0x112 [] mmu_notifier_register+0xe/0x10 [] kvm_dev_ioctl+0x11e/0x287 [kvm] [] vfs_ioctl+0x2a/0x78 [] do_vfs_ioctl+0x257/0x274 [] sys_ioctl+0x55/0x78 [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff other info that might help us debug this: 5 locks held by qemu-kvm/2033: #0: (&mm->mmap_sem){----}, at: [] do_mmu_notifier_register+0x55/0x112 #1: (mm_all_locks_mutex){--..}, at: [] mm_take_all_locks+0x34/0xea #2: (&anon_vma->lock){----}, at: [] mm_take_all_locks+0x70/0xea #3: (&anon_vma->lock){----}, at: [] mm_take_all_locks+0x70/0xea #4: (&anon_vma->lock){----}, at: [] mm_take_all_locks+0x70/0xea stack backtrace: Pid: 2033, comm: qemu-kvm Not tainted 2.6.27-rc1 #270 Call Trace: [] print_circular_bug_tail+0xb8/0xc3 [] __lock_acquire+0xedb/0x14d2 [] ? add_lock_to_list+0x7e/0xad [] ? mm_take_all_locks+0x70/0xea [] ? mm_take_all_locks+0x70/0xea [] lock_release_non_nested+0x1c2/0x219 [] ? mm_take_all_locks+0xc2/0xea [] ? mm_take_all_locks+0xc2/0xea [] ? trace_hardirqs_on_caller+0x4d/0x115 [] ? mm_drop_all_locks+0x7f/0xb0 [] lock_release+0x127/0x14a [] _spin_unlock+0x1e/0x50 [] mm_drop_all_locks+0x7f/0xb0 [] do_mmu_notifier_register+0xe2/0x112 [] mmu_notifier_register+0xe/0x10 [] kvm_dev_ioctl+0x11e/0x287 [kvm] [] ? file_has_perm+0x83/0x8e [] vfs_ioctl+0x2a/0x78 [] do_vfs_ioctl+0x257/0x274 [] sys_ioctl+0x55/0x78 [] system_call_fastpath+0x16/0x1b Which the locking hierarchy in mm/rmap.c confirms as valid. Fix this by first taking all the mapping->i_mmap_lock instances and then take all anon_vma->lock instances. Signed-off-by: Peter Zijlstra Acked-by: Hugh Dickins Signed-off-by: Ingo Molnar --- mm/mmap.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'mm/mmap.c') diff --git a/mm/mmap.c b/mm/mmap.c index 5d09d08a4120..32a287b631d4 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2358,11 +2358,17 @@ int mm_take_all_locks(struct mm_struct *mm) for (vma = mm->mmap; vma; vma = vma->vm_next) { if (signal_pending(current)) goto out_unlock; - if (vma->anon_vma) - vm_lock_anon_vma(mm, vma->anon_vma); if (vma->vm_file && vma->vm_file->f_mapping) vm_lock_mapping(mm, vma->vm_file->f_mapping); } + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (signal_pending(current)) + goto out_unlock; + if (vma->anon_vma) + vm_lock_anon_vma(mm, vma->anon_vma); + } + ret = 0; out_unlock: -- cgit v1.2.2 From ce36394269ccd9d1d286d6192ba09fa6894365e9 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 3 Sep 2008 16:09:47 +0200 Subject: mmap: fix petty bug in anonymous shared mmap offset handling Anonymous mappings should ignore offset but shared anonymous mapping forgot to clear it and makes the following legit test program trigger SIGBUS. #include #include #include #define PAGE_SIZE 4096 int main(void) { char *p; int i; p = mmap(NULL, 2 * PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, PAGE_SIZE); if (p == MAP_FAILED) { perror("mmap"); return 1; } for (i = 0; i < 2; i++) { printf("page %d\n", i); p[i * 4096] = i; } return 0; } Fix it. Signed-off-by: Tejun Heo Acked-by: Hugh Dickins Acked-by: KOSAKI Motohiro Signed-off-by: Linus Torvalds --- mm/mmap.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'mm/mmap.c') diff --git a/mm/mmap.c b/mm/mmap.c index 339cf5c4d5d8..e7a5a68a9c2e 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1030,6 +1030,10 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, } else { switch (flags & MAP_TYPE) { case MAP_SHARED: + /* + * Ignore pgoff. + */ + pgoff = 0; vm_flags |= VM_SHARED | VM_MAYSHARE; break; case MAP_PRIVATE: -- cgit v1.2.2