posix-cpu-timers: Store a reference to a pid not a task
[sfrench/cifs-2.6.git] / kernel / time / posix-cpu-timers.c
index ef936c5a910b91427cb3e3faa595b372596d2f17..6df468a622fe893586ba6104f28adcab12d678cb 100644 (file)
@@ -118,6 +118,16 @@ static inline int validate_clock_permissions(const clockid_t clock)
        return __get_task_for_clock(clock, false, false) ? 0 : -EINVAL;
 }
 
+static inline enum pid_type cpu_timer_pid_type(struct k_itimer *timer)
+{
+       return CPUCLOCK_PERTHREAD(timer->it_clock) ? PIDTYPE_PID : PIDTYPE_TGID;
+}
+
+static inline struct task_struct *cpu_timer_task_rcu(struct k_itimer *timer)
+{
+       return pid_task(timer->it.cpu.pid, cpu_timer_pid_type(timer));
+}
+
 /*
  * Update expiry time from increment, and increase overrun count,
  * given the current clock sample.
@@ -391,7 +401,12 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer)
 
        new_timer->kclock = &clock_posix_cpu;
        timerqueue_init(&new_timer->it.cpu.node);
-       new_timer->it.cpu.task = p;
+       new_timer->it.cpu.pid = get_task_pid(p, cpu_timer_pid_type(new_timer));
+       /*
+        * get_task_for_clock() took a reference on @p. Drop it as the timer
+        * holds a reference on the pid of @p.
+        */
+       put_task_struct(p);
        return 0;
 }
 
@@ -404,13 +419,15 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer)
 static int posix_cpu_timer_del(struct k_itimer *timer)
 {
        struct cpu_timer *ctmr = &timer->it.cpu;
-       struct task_struct *p = ctmr->task;
        struct sighand_struct *sighand;
+       struct task_struct *p;
        unsigned long flags;
        int ret = 0;
 
-       if (WARN_ON_ONCE(!p))
-               return -EINVAL;
+       rcu_read_lock();
+       p = cpu_timer_task_rcu(timer);
+       if (!p)
+               goto out;
 
        /*
         * Protect against sighand release/switch in exit/exec and process/
@@ -432,8 +449,10 @@ static int posix_cpu_timer_del(struct k_itimer *timer)
                unlock_task_sighand(p, &flags);
        }
 
+out:
+       rcu_read_unlock();
        if (!ret)
-               put_task_struct(p);
+               put_pid(ctmr->pid);
 
        return ret;
 }
@@ -561,13 +580,21 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
        clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
        u64 old_expires, new_expires, old_incr, val;
        struct cpu_timer *ctmr = &timer->it.cpu;
-       struct task_struct *p = ctmr->task;
        struct sighand_struct *sighand;
+       struct task_struct *p;
        unsigned long flags;
        int ret = 0;
 
-       if (WARN_ON_ONCE(!p))
-               return -EINVAL;
+       rcu_read_lock();
+       p = cpu_timer_task_rcu(timer);
+       if (!p) {
+               /*
+                * If p has just been reaped, we can no
+                * longer get any information about it at all.
+                */
+               rcu_read_unlock();
+               return -ESRCH;
+       }
 
        /*
         * Use the to_ktime conversion because that clamps the maximum
@@ -584,8 +611,10 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
         * If p has just been reaped, we can no
         * longer get any information about it at all.
         */
-       if (unlikely(sighand == NULL))
+       if (unlikely(sighand == NULL)) {
+               rcu_read_unlock();
                return -ESRCH;
+       }
 
        /*
         * Disarm any old timer after extracting its expiry time.
@@ -690,6 +719,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
 
        ret = 0;
  out:
+       rcu_read_unlock();
        if (old)
                old->it_interval = ns_to_timespec64(old_incr);
 
@@ -701,10 +731,12 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp
        clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
        struct cpu_timer *ctmr = &timer->it.cpu;
        u64 now, expires = cpu_timer_getexpires(ctmr);
-       struct task_struct *p = ctmr->task;
+       struct task_struct *p;
 
-       if (WARN_ON_ONCE(!p))
-               return;
+       rcu_read_lock();
+       p = cpu_timer_task_rcu(timer);
+       if (!p)
+               goto out;
 
        /*
         * Easy part: convert the reload time.
@@ -712,7 +744,7 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp
        itp->it_interval = ktime_to_timespec64(timer->it_interval);
 
        if (!expires)
-               return;
+               goto out;
 
        /*
         * Sample the clock to take the difference with the expiry time.
@@ -732,6 +764,8 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp
                itp->it_value.tv_nsec = 1;
                itp->it_value.tv_sec = 0;
        }
+out:
+       rcu_read_unlock();
 }
 
 #define MAX_COLLECTED  20
@@ -952,14 +986,15 @@ static void check_process_timers(struct task_struct *tsk,
 static void posix_cpu_timer_rearm(struct k_itimer *timer)
 {
        clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
-       struct cpu_timer *ctmr = &timer->it.cpu;
-       struct task_struct *p = ctmr->task;
+       struct task_struct *p;
        struct sighand_struct *sighand;
        unsigned long flags;
        u64 now;
 
-       if (WARN_ON_ONCE(!p))
-               return;
+       rcu_read_lock();
+       p = cpu_timer_task_rcu(timer);
+       if (!p)
+               goto out;
 
        /*
         * Fetch the current sample and update the timer's expiry time.
@@ -974,13 +1009,15 @@ static void posix_cpu_timer_rearm(struct k_itimer *timer)
        /* Protect timer list r/w in arm_timer() */
        sighand = lock_task_sighand(p, &flags);
        if (unlikely(sighand == NULL))
-               return;
+               goto out;
 
        /*
         * Now re-arm for the new expiry time.
         */
        arm_timer(timer, p);
        unlock_task_sighand(p, &flags);
+out:
+       rcu_read_unlock();
 }
 
 /**