1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include "sched.h" 4 5 /* 6 * A simple wrapper around refcount. An allocated sched_core_cookie's 7 * address is used to compute the cookie of the task. 8 */ 9 struct sched_core_cookie { 10 refcount_t refcnt; 11 }; 12 13 unsigned long sched_core_alloc_cookie(void) 14 { 15 struct sched_core_cookie *ck = kmalloc(sizeof(*ck), GFP_KERNEL); 16 if (!ck) 17 return 0; 18 19 refcount_set(&ck->refcnt, 1); 20 sched_core_get(); 21 22 return (unsigned long)ck; 23 } 24 25 void sched_core_put_cookie(unsigned long cookie) 26 { 27 struct sched_core_cookie *ptr = (void *)cookie; 28 29 if (ptr && refcount_dec_and_test(&ptr->refcnt)) { 30 kfree(ptr); 31 sched_core_put(); 32 } 33 } 34 35 unsigned long sched_core_get_cookie(unsigned long cookie) 36 { 37 struct sched_core_cookie *ptr = (void *)cookie; 38 39 if (ptr) 40 refcount_inc(&ptr->refcnt); 41 42 return cookie; 43 } 44 45 /* 46 * sched_core_update_cookie - replace the cookie on a task 47 * @p: the task to update 48 * @cookie: the new cookie 49 * 50 * Effectively exchange the task cookie; caller is responsible for lifetimes on 51 * both ends. 52 * 53 * Returns: the old cookie 54 */ 55 unsigned long sched_core_update_cookie(struct task_struct *p, unsigned long cookie) 56 { 57 unsigned long old_cookie; 58 struct rq_flags rf; 59 struct rq *rq; 60 bool enqueued; 61 62 rq = task_rq_lock(p, &rf); 63 64 /* 65 * Since creating a cookie implies sched_core_get(), and we cannot set 66 * a cookie until after we've created it, similarly, we cannot destroy 67 * a cookie until after we've removed it, we must have core scheduling 68 * enabled here. 69 */ 70 SCHED_WARN_ON((p->core_cookie || cookie) && !sched_core_enabled(rq)); 71 72 enqueued = sched_core_enqueued(p); 73 if (enqueued) 74 sched_core_dequeue(rq, p); 75 76 old_cookie = p->core_cookie; 77 p->core_cookie = cookie; 78 79 if (enqueued) 80 sched_core_enqueue(rq, p); 81 82 /* 83 * If task is currently running, it may not be compatible anymore after 84 * the cookie change, so enter the scheduler on its CPU to schedule it 85 * away. 86 */ 87 if (task_running(rq, p)) 88 resched_curr(rq); 89 90 task_rq_unlock(rq, p, &rf); 91 92 return old_cookie; 93 } 94 95 static unsigned long sched_core_clone_cookie(struct task_struct *p) 96 { 97 unsigned long cookie, flags; 98 99 raw_spin_lock_irqsave(&p->pi_lock, flags); 100 cookie = sched_core_get_cookie(p->core_cookie); 101 raw_spin_unlock_irqrestore(&p->pi_lock, flags); 102 103 return cookie; 104 } 105 106 void sched_core_free(struct task_struct *p) 107 { 108 sched_core_put_cookie(p->core_cookie); 109 } 110