]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/exit.c
Improve queue_is_locked()
[linux-2.6-omap-h63xx.git] / kernel / exit.c
index 53872bf993fa79d46b6e252db4f393c6a3e6828f..ae0f2c4e452b8bf4f69bdbc2b96bb16650fc61fc 100644 (file)
@@ -507,10 +507,9 @@ void put_files_struct(struct files_struct *files)
        }
 }
 
-EXPORT_SYMBOL(put_files_struct);
-
-void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
+void reset_files_struct(struct files_struct *files)
 {
+       struct task_struct *tsk = current;
        struct files_struct *old;
 
        old = tsk->files;
@@ -519,9 +518,8 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
        task_unlock(tsk);
        put_files_struct(old);
 }
-EXPORT_SYMBOL(reset_files_struct);
 
-static void __exit_files(struct task_struct *tsk)
+void exit_files(struct task_struct *tsk)
 {
        struct files_struct * files = tsk->files;
 
@@ -533,12 +531,7 @@ static void __exit_files(struct task_struct *tsk)
        }
 }
 
-void exit_files(struct task_struct *tsk)
-{
-       __exit_files(tsk);
-}
-
-static void __put_fs_struct(struct fs_struct *fs)
+void put_fs_struct(struct fs_struct *fs)
 {
        /* No need to hold fs->lock if we are killing it */
        if (atomic_dec_and_test(&fs->count)) {
@@ -550,12 +543,7 @@ static void __put_fs_struct(struct fs_struct *fs)
        }
 }
 
-void put_fs_struct(struct fs_struct *fs)
-{
-       __put_fs_struct(fs);
-}
-
-static void __exit_fs(struct task_struct *tsk)
+void exit_fs(struct task_struct *tsk)
 {
        struct fs_struct * fs = tsk->fs;
 
@@ -563,16 +551,93 @@ static void __exit_fs(struct task_struct *tsk)
                task_lock(tsk);
                tsk->fs = NULL;
                task_unlock(tsk);
-               __put_fs_struct(fs);
+               put_fs_struct(fs);
        }
 }
 
-void exit_fs(struct task_struct *tsk)
+EXPORT_SYMBOL_GPL(exit_fs);
+
+#ifdef CONFIG_MM_OWNER
+/*
+ * Task p is exiting and it owned mm, lets find a new owner for it
+ */
+static inline int
+mm_need_new_owner(struct mm_struct *mm, struct task_struct *p)
 {
-       __exit_fs(tsk);
+       /*
+        * If there are other users of the mm and the owner (us) is exiting
+        * we need to find a new owner to take on the responsibility.
+        */
+       if (!mm)
+               return 0;
+       if (atomic_read(&mm->mm_users) <= 1)
+               return 0;
+       if (mm->owner != p)
+               return 0;
+       return 1;
 }
 
-EXPORT_SYMBOL_GPL(exit_fs);
+void mm_update_next_owner(struct mm_struct *mm)
+{
+       struct task_struct *c, *g, *p = current;
+
+retry:
+       if (!mm_need_new_owner(mm, p))
+               return;
+
+       read_lock(&tasklist_lock);
+       /*
+        * Search in the children
+        */
+       list_for_each_entry(c, &p->children, sibling) {
+               if (c->mm == mm)
+                       goto assign_new_owner;
+       }
+
+       /*
+        * Search in the siblings
+        */
+       list_for_each_entry(c, &p->parent->children, sibling) {
+               if (c->mm == mm)
+                       goto assign_new_owner;
+       }
+
+       /*
+        * Search through everything else. We should not get
+        * here often
+        */
+       do_each_thread(g, c) {
+               if (c->mm == mm)
+                       goto assign_new_owner;
+       } while_each_thread(g, c);
+
+       read_unlock(&tasklist_lock);
+       return;
+
+assign_new_owner:
+       BUG_ON(c == p);
+       get_task_struct(c);
+       /*
+        * The task_lock protects c->mm from changing.
+        * We always want mm->owner->mm == mm
+        */
+       task_lock(c);
+       /*
+        * Delay read_unlock() till we have the task_lock()
+        * to ensure that c does not slip away underneath us
+        */
+       read_unlock(&tasklist_lock);
+       if (c->mm != mm) {
+               task_unlock(c);
+               put_task_struct(c);
+               goto retry;
+       }
+       cgroup_mm_owner_callbacks(mm->owner, c);
+       mm->owner = c;
+       task_unlock(c);
+       put_task_struct(c);
+}
+#endif /* CONFIG_MM_OWNER */
 
 /*
  * Turn us into a lazy TLB process if we
@@ -613,6 +678,7 @@ static void exit_mm(struct task_struct * tsk)
        /* We don't want this task to be frozen prematurely */
        clear_freeze_flag(tsk);
        task_unlock(tsk);
+       mm_update_next_owner(mm);
        mmput(mm);
 }
 
@@ -967,8 +1033,8 @@ NORET_TYPE void do_exit(long code)
        if (group_dead)
                acct_process();
        exit_sem(tsk);
-       __exit_files(tsk);
-       __exit_fs(tsk);
+       exit_files(tsk);
+       exit_fs(tsk);
        check_stack_usage();
        exit_thread();
        cgroup_exit(tsk, 1);
@@ -984,7 +1050,7 @@ NORET_TYPE void do_exit(long code)
        proc_exit_connector(tsk);
        exit_notify(tsk, group_dead);
 #ifdef CONFIG_NUMA
-       mpol_free(tsk->mempolicy);
+       mpol_put(tsk->mempolicy);
        tsk->mempolicy = NULL;
 #endif
 #ifdef CONFIG_FUTEX
@@ -1608,7 +1674,7 @@ asmlinkage long sys_waitid(int which, pid_t upid,
        put_pid(pid);
 
        /* avoid REGPARM breakage on x86: */
-       prevent_tail_call(ret);
+       asmlinkage_protect(5, ret, which, upid, infop, options, ru);
        return ret;
 }
 
@@ -1640,7 +1706,7 @@ asmlinkage long sys_wait4(pid_t upid, int __user *stat_addr,
        put_pid(pid);
 
        /* avoid REGPARM breakage on x86: */
-       prevent_tail_call(ret);
+       asmlinkage_protect(4, ret, upid, stat_addr, options, ru);
        return ret;
 }