]> Pileus Git - ~andy/linux/blobdiff - include/linux/sched.h
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci
[~andy/linux] / include / linux / sched.h
index ad93e1ec8c656a38d8b1a1e8159896b387b3c3cb..21cd0303af5107ef944b27c334750d6cedfb13ef 100644 (file)
@@ -637,13 +637,15 @@ struct signal_struct {
 #endif
 #ifdef CONFIG_CGROUPS
        /*
-        * The threadgroup_fork_lock prevents threads from forking with
-        * CLONE_THREAD while held for writing. Use this for fork-sensitive
-        * threadgroup-wide operations. It's taken for reading in fork.c in
-        * copy_process().
-        * Currently only needed write-side by cgroups.
+        * group_rwsem prevents new tasks from entering the threadgroup and
+        * member tasks from exiting,a more specifically, setting of
+        * PF_EXITING.  fork and exit paths are protected with this rwsem
+        * using threadgroup_change_begin/end().  Users which require
+        * threadgroup to remain stable should use threadgroup_[un]lock()
+        * which also takes care of exec path.  Currently, cgroup is the
+        * only user.
         */
-       struct rw_semaphore threadgroup_fork_lock;
+       struct rw_semaphore group_rwsem;
 #endif
 
        int oom_adj;            /* OOM kill score adjustment (bit shift) */
@@ -1542,6 +1544,7 @@ struct task_struct {
         */
        int nr_dirtied;
        int nr_dirtied_pause;
+       unsigned long dirty_paused_when; /* start of a write-and-pause period */
 
 #ifdef CONFIG_LATENCYTOP
        int latency_record_count;
@@ -2394,29 +2397,62 @@ static inline void unlock_task_sighand(struct task_struct *tsk,
        spin_unlock_irqrestore(&tsk->sighand->siglock, *flags);
 }
 
-/* See the declaration of threadgroup_fork_lock in signal_struct. */
 #ifdef CONFIG_CGROUPS
-static inline void threadgroup_fork_read_lock(struct task_struct *tsk)
+static inline void threadgroup_change_begin(struct task_struct *tsk)
 {
-       down_read(&tsk->signal->threadgroup_fork_lock);
+       down_read(&tsk->signal->group_rwsem);
 }
-static inline void threadgroup_fork_read_unlock(struct task_struct *tsk)
+static inline void threadgroup_change_end(struct task_struct *tsk)
 {
-       up_read(&tsk->signal->threadgroup_fork_lock);
+       up_read(&tsk->signal->group_rwsem);
 }
-static inline void threadgroup_fork_write_lock(struct task_struct *tsk)
+
+/**
+ * threadgroup_lock - lock threadgroup
+ * @tsk: member task of the threadgroup to lock
+ *
+ * Lock the threadgroup @tsk belongs to.  No new task is allowed to enter
+ * and member tasks aren't allowed to exit (as indicated by PF_EXITING) or
+ * perform exec.  This is useful for cases where the threadgroup needs to
+ * stay stable across blockable operations.
+ *
+ * fork and exit paths explicitly call threadgroup_change_{begin|end}() for
+ * synchronization.  While held, no new task will be added to threadgroup
+ * and no existing live task will have its PF_EXITING set.
+ *
+ * During exec, a task goes and puts its thread group through unusual
+ * changes.  After de-threading, exclusive access is assumed to resources
+ * which are usually shared by tasks in the same group - e.g. sighand may
+ * be replaced with a new one.  Also, the exec'ing task takes over group
+ * leader role including its pid.  Exclude these changes while locked by
+ * grabbing cred_guard_mutex which is used to synchronize exec path.
+ */
+static inline void threadgroup_lock(struct task_struct *tsk)
 {
-       down_write(&tsk->signal->threadgroup_fork_lock);
+       /*
+        * exec uses exit for de-threading nesting group_rwsem inside
+        * cred_guard_mutex. Grab cred_guard_mutex first.
+        */
+       mutex_lock(&tsk->signal->cred_guard_mutex);
+       down_write(&tsk->signal->group_rwsem);
 }
-static inline void threadgroup_fork_write_unlock(struct task_struct *tsk)
+
+/**
+ * threadgroup_unlock - unlock threadgroup
+ * @tsk: member task of the threadgroup to unlock
+ *
+ * Reverse threadgroup_lock().
+ */
+static inline void threadgroup_unlock(struct task_struct *tsk)
 {
-       up_write(&tsk->signal->threadgroup_fork_lock);
+       up_write(&tsk->signal->group_rwsem);
+       mutex_unlock(&tsk->signal->cred_guard_mutex);
 }
 #else
-static inline void threadgroup_fork_read_lock(struct task_struct *tsk) {}
-static inline void threadgroup_fork_read_unlock(struct task_struct *tsk) {}
-static inline void threadgroup_fork_write_lock(struct task_struct *tsk) {}
-static inline void threadgroup_fork_write_unlock(struct task_struct *tsk) {}
+static inline void threadgroup_change_begin(struct task_struct *tsk) {}
+static inline void threadgroup_change_end(struct task_struct *tsk) {}
+static inline void threadgroup_lock(struct task_struct *tsk) {}
+static inline void threadgroup_unlock(struct task_struct *tsk) {}
 #endif
 
 #ifndef __HAVE_THREAD_FUNCTIONS