]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - kernel/sys.c
staging: unisys: visorchannel some general function cleanups
[karo-tx-linux.git] / kernel / sys.c
index 3be344902316e93d8b147d1c5367dc60fe5908b8..a4e372b798a5f29535f9120b32fea70b0489f603 100644 (file)
@@ -1649,14 +1649,13 @@ SYSCALL_DEFINE1(umask, int, mask)
        return mask;
 }
 
-static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd)
+static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
 {
        struct fd exe;
+       struct file *old_exe, *exe_file;
        struct inode *inode;
        int err;
 
-       VM_BUG_ON_MM(!rwsem_is_locked(&mm->mmap_sem), mm);
-
        exe = fdget(fd);
        if (!exe.file)
                return -EBADF;
@@ -1680,15 +1679,22 @@ static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd)
        /*
         * Forbid mm->exe_file change if old file still mapped.
         */
+       exe_file = get_mm_exe_file(mm);
        err = -EBUSY;
-       if (mm->exe_file) {
+       if (exe_file) {
                struct vm_area_struct *vma;
 
-               for (vma = mm->mmap; vma; vma = vma->vm_next)
-                       if (vma->vm_file &&
-                           path_equal(&vma->vm_file->f_path,
-                                      &mm->exe_file->f_path))
-                               goto exit;
+               down_read(&mm->mmap_sem);
+               for (vma = mm->mmap; vma; vma = vma->vm_next) {
+                       if (!vma->vm_file)
+                               continue;
+                       if (path_equal(&vma->vm_file->f_path,
+                                      &exe_file->f_path))
+                               goto exit_err;
+               }
+
+               up_read(&mm->mmap_sem);
+               fput(exe_file);
        }
 
        /*
@@ -1702,10 +1708,18 @@ static int prctl_set_mm_exe_file_locked(struct mm_struct *mm, unsigned int fd)
                goto exit;
 
        err = 0;
-       set_mm_exe_file(mm, exe.file);  /* this grabs a reference to exe.file */
+       /* set the new file, lockless */
+       get_file(exe.file);
+       old_exe = xchg(&mm->exe_file, exe.file);
+       if (old_exe)
+               fput(old_exe);
 exit:
        fdput(exe);
        return err;
+exit_err:
+       up_read(&mm->mmap_sem);
+       fput(exe_file);
+       goto exit;
 }
 
 #ifdef CONFIG_CHECKPOINT_RESTORE
@@ -1840,10 +1854,9 @@ static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data
                user_auxv[AT_VECTOR_SIZE - 1] = AT_NULL;
        }
 
-       down_write(&mm->mmap_sem);
        if (prctl_map.exe_fd != (u32)-1)
-               error = prctl_set_mm_exe_file_locked(mm, prctl_map.exe_fd);
-       downgrade_write(&mm->mmap_sem);
+               error = prctl_set_mm_exe_file(mm, prctl_map.exe_fd);
+       down_read(&mm->mmap_sem);
        if (error)
                goto out;
 
@@ -1909,12 +1922,8 @@ static int prctl_set_mm(int opt, unsigned long addr,
        if (!capable(CAP_SYS_RESOURCE))
                return -EPERM;
 
-       if (opt == PR_SET_MM_EXE_FILE) {
-               down_write(&mm->mmap_sem);
-               error = prctl_set_mm_exe_file_locked(mm, (unsigned int)addr);
-               up_write(&mm->mmap_sem);
-               return error;
-       }
+       if (opt == PR_SET_MM_EXE_FILE)
+               return prctl_set_mm_exe_file(mm, (unsigned int)addr);
 
        if (addr >= TASK_SIZE || addr < mmap_min_addr)
                return -EINVAL;