2007-11-01 04:41:35

by Matt Helsley

[permalink] [raw]
Subject: [RFC][PATCH 2/3] [RFC][PATCH] Add spinlock in mm to protext exe reference

The new and relatively unused (compared to VM ops) mm_struct exe file reference
uses the mmap semaphore. It may be preferrable to avoid using the mmap
semaphore at some point in the future. This patch demonstrates one way to avoid
using the mmap semaphore for the exe file reference inside /proc/pid/exe ops.

Unfortunately we can't entirely avoid using the mmap semaphore because we need
to drop the exe file reference when the VMA mapping the executable file does --
otherwise we'd pin mounted filesystems until all applications executed from
them exitted.

Signed-off-by: Matt Helsley <[email protected]>
---
include/linux/sched.h | 1 +
mm/mmap.c | 17 +++++++++++------
2 files changed, 12 insertions(+), 6 deletions(-)

Index: linux-2.6.23/include/linux/sched.h
===================================================================
--- linux-2.6.23.orig/include/linux/sched.h
+++ linux-2.6.23/include/linux/sched.h
@@ -432,10 +432,11 @@ struct mm_struct {
/* aio bits */
rwlock_t ioctx_list_lock;
struct kioctx *ioctx_list;

/* store ref to file /proc/<pid>/exe symlink points to */
+ spinlock_t exe_file_lock;
struct file *exe_file;
};

struct sighand_struct {
atomic_t count;
Index: linux-2.6.23/mm/mmap.c
===================================================================
--- linux-2.6.23.orig/mm/mmap.c
+++ linux-2.6.23/mm/mmap.c
@@ -1706,27 +1706,27 @@ find_extend_vma(struct mm_struct * mm, u
* reference; only puts old ones */
void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
{
struct file *old_exe_file;

- down_write(&mm->mmap_sem);
+ spin_lock(&mm->exe_file_lock);
old_exe_file = mm->exe_file;
mm->exe_file = new_exe_file;
- up_write(&mm->mmap_sem);
+ spin_unlock(&mm->exe_file_lock);
if (old_exe_file)
fput(old_exe_file);
}

struct file *get_mm_exe_file(struct mm_struct *mm)
{
struct file *exe_file;

- down_read(&mm->mmap_sem);
+ spin_lock(&mm->exe_file_lock);
exe_file = mm->exe_file;
if (exe_file)
get_file(exe_file);
- up_read(&mm->mmap_sem);
+ spin_unlock(&mm->exe_file_lock);
return exe_file;
}
#endif

/*
@@ -1744,14 +1744,19 @@ static void remove_vma_list(struct mm_st

mm->total_vm -= nrpages;
if (vma->vm_flags & VM_LOCKED)
mm->locked_vm -= nrpages;
vm_stat_account(mm, vma->vm_flags, vma->vm_file, -nrpages);
+ spin_lock(&mm->exe_file_lock);
if (mm->exe_file && (vma->vm_file == mm->exe_file)) {
- fput(mm->exe_file);
+ struct file *old_exe_file = mm->exe_file;
+
mm->exe_file = NULL;
- }
+ spin_unlock(&mm->exe_file_lock);
+ fput(old_exe_file);
+ } else
+ spin_unlock(&mm->exe_file_lock);
vma = remove_vma(vma);
} while (vma);
validate_mm(mm);
}


--