Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

oprofile: reduce mmap_sem hold for mm->exe_file

sync_buffer() needs the mmap_sem for two distinct operations, both only
occurring upon user context switch handling:

1) Dealing with the exe_file.

2) Adding the dcookie data as we need to lookup the vma that
backs it. This is done via add_sample() and add_data().

This patch isolates 1), for it will no longer need the mmap_sem for
serialization. However, for now, make of the more standard
get_mm_exe_file(), requiring only holding the mmap_sem to read the value,
and relying on reference counting to make sure that the exe file won't
dissappear underneath us while doing the get dcookie.

As a consequence, for 2) we move the mmap_sem locking into where we really
need it, in lookup_dcookie(). The benefits are twofold: reduce mmap_sem
hold times, and cleaner code.

[akpm@linux-foundation.org: export get_mm_exe_file for arch/x86/oprofile/oprofile.ko]
Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Cc: Robert Richter <rric@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Davidlohr Bueso and committed by
Linus Torvalds
11163348 15beb694

+17 -14
+16 -14
drivers/oprofile/buffer_sync.c
··· 21 21 * objects. 22 22 */ 23 23 24 + #include <linux/file.h> 24 25 #include <linux/mm.h> 25 26 #include <linux/workqueue.h> 26 27 #include <linux/notifier.h> ··· 225 224 static unsigned long get_exec_dcookie(struct mm_struct *mm) 226 225 { 227 226 unsigned long cookie = NO_COOKIE; 227 + struct file *exe_file; 228 228 229 - if (mm && mm->exe_file) 230 - cookie = fast_get_dcookie(&mm->exe_file->f_path); 229 + if (!mm) 230 + goto done; 231 231 232 + exe_file = get_mm_exe_file(mm); 233 + if (!exe_file) 234 + goto done; 235 + 236 + cookie = fast_get_dcookie(&exe_file->f_path); 237 + fput(exe_file); 238 + done: 232 239 return cookie; 233 240 } 234 241 ··· 245 236 * pair that can then be added to the global event buffer. We make 246 237 * sure to do this lookup before a mm->mmap modification happens so 247 238 * we don't lose track. 239 + * 240 + * The caller must ensure the mm is not nil (ie: not a kernel thread). 248 241 */ 249 242 static unsigned long 250 243 lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset) ··· 254 243 unsigned long cookie = NO_COOKIE; 255 244 struct vm_area_struct *vma; 256 245 246 + down_read(&mm->mmap_sem); 257 247 for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { 258 248 259 249 if (addr < vma->vm_start || addr >= vma->vm_end) ··· 274 262 275 263 if (!vma) 276 264 cookie = INVALID_COOKIE; 265 + up_read(&mm->mmap_sem); 277 266 278 267 return cookie; 279 268 } ··· 415 402 { 416 403 if (!mm) 417 404 return; 418 - up_read(&mm->mmap_sem); 419 405 mmput(mm); 420 406 } 421 - 422 - 423 - static struct mm_struct *take_tasks_mm(struct task_struct *task) 424 - { 425 - struct mm_struct *mm = get_task_mm(task); 426 - if (mm) 427 - down_read(&mm->mmap_sem); 428 - return mm; 429 - } 430 - 431 407 432 408 static inline int is_code(unsigned long val) 433 409 { ··· 534 532 new = (struct task_struct *)val; 535 533 oldmm = mm; 536 534 release_mm(oldmm); 537 - mm = take_tasks_mm(new); 535 + mm = get_task_mm(new); 538 536 if (mm != oldmm) 539 537 cookie = get_exec_dcookie(mm); 540 538 add_user_ctx_switch(new, cookie);
+1
kernel/fork.c
··· 752 752 rcu_read_unlock(); 753 753 return exe_file; 754 754 } 755 + EXPORT_SYMBOL(get_mm_exe_file); 755 756 756 757 /** 757 758 * get_task_mm - acquire a reference to the task's mm