Răsfoiți Sursa

[PATCH] taskstats_tgid_free: fix usage

taskstats_tgid_free() is called on copy_process's error path. This is wrong.

	IF (clone_flags & CLONE_THREAD)
		We should not clear ->signal->taskstats, current uses it,
		it probably has a valid accumulated info.
	ELSE
		taskstats_tgid_init() set ->signal->taskstats = NULL,
		there is nothing to free.

Move the callsite to __exit_signal(). We don't need any locking, entire
thread group is exiting, nobody should have a reference to soon to be
released ->signal.

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Shailabh Nagar <nagar@watson.ibm.com>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Jay Lan <jlan@sgi.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Oleg Nesterov 18 ani în urmă
părinte
comite
093a8e8aec
3 a modificat fișierele cu 3 adăugiri și 12 ștergeri
  1. 2 11
      include/linux/taskstats_kern.h
  2. 1 0
      kernel/exit.c
  3. 0 1
      kernel/fork.c

+ 2 - 11
include/linux/taskstats_kern.h

@@ -49,17 +49,8 @@ static inline void taskstats_tgid_alloc(struct signal_struct *sig)
 
 
 static inline void taskstats_tgid_free(struct signal_struct *sig)
 static inline void taskstats_tgid_free(struct signal_struct *sig)
 {
 {
-	struct taskstats *stats = NULL;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sig->stats_lock, flags);
-	if (sig->stats) {
-		stats = sig->stats;
-		sig->stats = NULL;
-	}
-	spin_unlock_irqrestore(&sig->stats_lock, flags);
-	if (stats)
-		kmem_cache_free(taskstats_cache, stats);
+	if (sig->stats)
+		kmem_cache_free(taskstats_cache, sig->stats);
 }
 }
 
 
 extern void taskstats_exit_alloc(struct taskstats **, unsigned int *);
 extern void taskstats_exit_alloc(struct taskstats **, unsigned int *);

+ 1 - 0
kernel/exit.c

@@ -128,6 +128,7 @@ static void __exit_signal(struct task_struct *tsk)
 	flush_sigqueue(&tsk->pending);
 	flush_sigqueue(&tsk->pending);
 	if (sig) {
 	if (sig) {
 		flush_sigqueue(&sig->shared_pending);
 		flush_sigqueue(&sig->shared_pending);
+		taskstats_tgid_free(sig);
 		__cleanup_signal(sig);
 		__cleanup_signal(sig);
 	}
 	}
 }
 }

+ 0 - 1
kernel/fork.c

@@ -897,7 +897,6 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
 void __cleanup_signal(struct signal_struct *sig)
 void __cleanup_signal(struct signal_struct *sig)
 {
 {
 	exit_thread_group_keys(sig);
 	exit_thread_group_keys(sig);
-	taskstats_tgid_free(sig);
 	kmem_cache_free(signal_cachep, sig);
 	kmem_cache_free(signal_cachep, sig);
 }
 }