2 #include <linux/cdev.h>
3 #include <linux/device.h>
4 #include <linux/seq_file.h>
6 #include <linux/security.h>
7 #include <linux/cpuset.h>
8 #include <linux/poll.h>
9 #include <linux/proc_fs.h>
10 #include <linux/module.h>
11 #include <linux/version.h>
12 #include "mt_sched_drv.h"
14 #define SCHED_DEV_NAME "sched"
18 struct task_struct
*p
;
20 struct list_head list
;
23 static struct mt_task mt_task_head
;
24 static DEFINE_SPINLOCK(mt_sched_spinlock
);
26 static int get_user_cpu_mask(unsigned long __user
*user_mask_ptr
, unsigned len
,
27 struct cpumask
*new_mask
)
29 if (len
< cpumask_size())
30 cpumask_clear(new_mask
);
31 else if (len
> cpumask_size())
34 return copy_from_user(new_mask
, user_mask_ptr
, len
) ? -EFAULT
: 0;
38 * find_process_by_pid - find a process with a matching PID value.
39 * @pid: the pid in question.
41 static struct task_struct
*find_process_by_pid(pid_t pid
)
43 return pid
? find_task_by_vpid(pid
) : current
;
47 * check the target process has a UID that matches the current process's
49 static bool check_same_owner(struct task_struct
*p
)
51 const struct cred
*cred
= current_cred(), *pcred
;
55 pcred
= __task_cred(p
);
56 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
57 match
= (cred
->euid
== pcred
->euid
|| cred
->euid
== pcred
->uid
);
59 match
= (uid_eq(cred
->euid
, pcred
->euid
) || uid_eq(cred
->euid
, pcred
->uid
));
66 * check the task link list. If the task is exit, delete the task.
68 static void mt_sched_check_tasks(void)
70 struct mt_task
*tmp
, *tmp2
;
71 unsigned long irq_flags
;
73 spin_lock_irqsave(&mt_sched_spinlock
, irq_flags
);
74 list_for_each_entry_safe(tmp
, tmp2
, &mt_task_head
.list
, list
) {
75 if (tmp
->pid
!= tmp
->p
->pid
) {
76 list_del(&(tmp
->list
));
80 spin_unlock_irqrestore(&mt_sched_spinlock
, irq_flags
);
83 static long __mt_sched_addaffinity(struct task_struct
*p
, const struct cpumask
*new_mask
)
86 struct mt_task
*tmp
, *tmp2
;
87 unsigned long irq_flags
;
90 new = kmalloc(sizeof(struct mt_task
), GFP_KERNEL
);
94 INIT_LIST_HEAD(&(new->list
));
97 cpumask_copy(&new->mask
, new_mask
);
99 spin_lock_irqsave(&mt_sched_spinlock
, irq_flags
);
100 list_for_each_entry_safe(tmp
, tmp2
, &mt_task_head
.list
, list
) {
101 if (tmp
->pid
!= tmp
->p
->pid
) {
102 list_del(&(tmp
->list
));
106 if (!find
&& (tmp
->p
== p
)) {
108 cpumask_copy(&tmp
->mask
, new_mask
);
113 list_add(&(new->list
), &(mt_task_head
.list
));
115 spin_unlock_irqrestore(&mt_sched_spinlock
, irq_flags
);
123 static long __mt_sched_setaffinity(pid_t pid
, const struct cpumask
*in_mask
)
125 cpumask_var_t cpus_allowed
, new_mask
;
126 struct task_struct
*p
;
132 p
= find_process_by_pid(pid
);
136 pr_debug("MT_SCHED: setaffinity find process %d fail\n", pid
);
140 /* Prevent p going away */
143 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
144 if (p
->flags
& PF_NO_SETAFFINITY
) {
146 pr_debug("MT_SCHED: setaffinity flags PF_NO_SETAFFINITY fail\n");
150 if (!alloc_cpumask_var(&cpus_allowed
, GFP_KERNEL
)) {
152 pr_debug("MT_SCHED: setaffinity allo_cpumask_var for cpus_allowed fail\n");
155 if (!alloc_cpumask_var(&new_mask
, GFP_KERNEL
)) {
157 pr_debug("MT_SCHED: setaffinity allo_cpumask_var for new_mask fail\n");
158 goto out_free_cpus_allowed
;
161 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
162 if (!check_same_owner(p
) && !ns_capable(task_user_ns(p
), CAP_SYS_NICE
)) {
163 pr_debug("MT_SCHED: setaffinity check_same_owner and task_ns_capable fail\n");
167 if (!check_same_owner(p
)) {
169 if (!ns_capable(__task_cred(p
)->user_ns
, CAP_SYS_NICE
)) {
171 pr_debug("MT_SCHED: setaffinity check_same_owner and task_ns_capable fail\n");
178 retval
= security_task_setscheduler(p
);
180 pr_debug("MT_SCHED: setaffinity security_task_setscheduler fail, status: %d\n",
185 cpuset_cpus_allowed(p
, cpus_allowed
);
186 cpumask_and(new_mask
, in_mask
, cpus_allowed
);
188 retval
= set_cpus_allowed_ptr(p
, new_mask
);
190 pr_debug("MT_SCHED: set_cpus_allowed_ptr status %d\n", retval
);
193 cpuset_cpus_allowed(p
, cpus_allowed
);
194 if (!cpumask_subset(new_mask
, cpus_allowed
)) {
196 * We must have raced with a concurrent cpuset
197 * update. Just reset the cpus_allowed to the
198 * cpuset's cpus_allowed
200 cpumask_copy(new_mask
, cpus_allowed
);
205 /* modify for the mt_sched_setaffinity */
206 if ((!retval
) || (!cpumask_intersects(new_mask
, cpu_active_mask
)))
207 retval
= __mt_sched_addaffinity(p
, new_mask
);
210 free_cpumask_var(new_mask
);
211 out_free_cpus_allowed
:
212 free_cpumask_var(cpus_allowed
);
218 pr_debug("MT_SCHED: setaffinity status %d\n", retval
);
223 static long __mt_sched_getaffinity(pid_t pid
, struct cpumask
*mask
, struct cpumask
*mt_mask
)
225 struct task_struct
*p
;
227 unsigned long irq_flags
;
235 p
= find_process_by_pid(pid
);
237 pr_debug("MT_SCHED: getaffinity find process %d fail\n", pid
);
241 retval
= security_task_getscheduler(p
);
243 pr_debug("MT_SCHED: getaffinity security_task_getscheduler fail, status: %d\n",
248 raw_spin_lock_irqsave(&p
->pi_lock
, flags
);
249 cpumask_and(mask
, &p
->cpus_allowed
, cpu_online_mask
);
250 raw_spin_unlock_irqrestore(&p
->pi_lock
, flags
);
252 /* add for the mt_mask */
253 cpumask_clear(mt_mask
);
254 spin_lock_irqsave(&mt_sched_spinlock
, irq_flags
);
255 list_for_each_entry(tmp
, &mt_task_head
.list
, list
) {
256 if ((p
== tmp
->p
) && (p
->pid
== tmp
->pid
)) {
257 cpumask_copy(mt_mask
, &tmp
->mask
);
261 spin_unlock_irqrestore(&mt_sched_spinlock
, irq_flags
);
268 pr_debug("MT_SCHED: getaffinity status %d\n", retval
);
273 static long __mt_sched_exitaffinity(pid_t pid
)
275 struct mt_task
*tmp
, *tmp2
;
276 unsigned long irq_flags
;
282 spin_lock_irqsave(&mt_sched_spinlock
, irq_flags
);
283 list_for_each_entry_safe(tmp
, tmp2
, &mt_task_head
.list
, list
) {
284 if (pid
== tmp
->pid
) {
285 list_del(&(tmp
->list
));
291 spin_unlock_irqrestore(&mt_sched_spinlock
, irq_flags
);
293 pr_debug("MT_SCHED: exit affinity find process %d fail.\n", pid
);
299 static long sched_ioctl_ioctl(struct file
*filp
, unsigned int cmd
, unsigned long arg
)
303 struct ioctl_arg data
;
304 cpumask_var_t new_mask
, mask
, mt_mask
;
307 memset(&data
, 0, sizeof(data
));
309 case IOCTL_SETAFFINITY
:
310 if (copy_from_user(&data
, (int __user
*)arg
, sizeof(data
))) {
315 if (!alloc_cpumask_var(&new_mask
, GFP_KERNEL
))
318 retval
= get_user_cpu_mask(data
.mask
, data
.len
, new_mask
);
320 retval
= __mt_sched_setaffinity(data
.pid
, new_mask
);
322 pr_debug("MT_SCHED: setaffinity status %d\n", retval
);
323 free_cpumask_var(new_mask
);
326 case IOCTL_GETAFFINITY
:
327 if (copy_from_user(&data
, (int __user
*)arg
, sizeof(data
))) {
334 if ((len
* BITS_PER_BYTE
) < nr_cpu_ids
)
336 if (len
& (sizeof(unsigned int) - 1))
339 if (!alloc_cpumask_var(&mask
, GFP_KERNEL
))
342 if (!alloc_cpumask_var(&mt_mask
, GFP_KERNEL
)) {
343 goto getaffinity_free1
;
347 retval
= __mt_sched_getaffinity(data
.pid
, mask
, mt_mask
);
349 size_t retlen
= min_t(size_t, len
, cpumask_size());
351 if (copy_to_user((int __user
*)data
.mask
, mask
, retlen
)) {
353 goto getaffinity_free
;
358 if (copy_to_user((int __user
*)data
.mt_mask
, mt_mask
, retlen
))
364 free_cpumask_var(mt_mask
);
366 free_cpumask_var(mask
);
369 case IOCTL_EXITAFFINITY
:
370 if (copy_from_user(&pid
, (int __user
*)arg
, sizeof(pid
))) {
375 retval
= __mt_sched_exitaffinity(pid
);
384 const struct file_operations sched_ioctl_fops
= {
385 .owner
= THIS_MODULE
,
386 .unlocked_ioctl
= sched_ioctl_ioctl
,
388 .compat_ioctl
= sched_ioctl_compat
,
392 static struct cdev
*sched_ioctl_cdev
;
393 static dev_t sched_dev_num
;
394 struct class *sched_class
;
395 static int __init
sched_ioctl_init(void)
398 struct device
*class_dev
= NULL
;
400 if (alloc_chrdev_region(&sched_dev_num
, 0, 1, SCHED_DEV_NAME
)) {
401 pr_debug("MT_SCHED: Device major number allocation failed\n");
405 sched_ioctl_cdev
= cdev_alloc();
406 if (NULL
== sched_ioctl_cdev
) {
407 pr_debug("MT_SCHED: cdev_alloc failed\n");
412 cdev_init(sched_ioctl_cdev
, &sched_ioctl_fops
);
413 sched_ioctl_cdev
->owner
= THIS_MODULE
;
414 ret
= cdev_add(sched_ioctl_cdev
, sched_dev_num
, 1);
416 pr_debug("MT_SCHED: Char device add failed\n");
420 sched_class
= class_create(THIS_MODULE
, "scheddrv");
421 if (IS_ERR(sched_class
)) {
422 pr_debug("Unable to create class, err = %d\n", (int)PTR_ERR(sched_class
));
425 class_dev
= device_create(sched_class
, NULL
, sched_dev_num
, NULL
, "mtk_sched");
427 pr_alert("MT_SCHED: Init complete, device major number = %d\n", MAJOR(sched_dev_num
));
431 class_destroy(sched_class
);
433 cdev_del(sched_ioctl_cdev
);
435 unregister_chrdev_region(sched_dev_num
, 1);
441 * /proc/mtk_sched/affinity_status
443 static int sched_status_show(struct seq_file
*seq
, void *v
);
444 static int sched_status_open(struct inode
*inode
, struct file
*file
);
445 static unsigned int sched_status_poll(struct file
*file
, poll_table
*wait
);
446 static const struct file_operations sched_status_fops
= {
447 .open
= sched_status_open
,
449 .poll
= sched_status_poll
,
451 .release
= single_release
454 static int sched_status_open(struct inode
*inode
, struct file
*file
)
456 return single_open(file
, sched_status_show
, inode
->i_private
);
459 static int sched_status_show(struct seq_file
*seq
, void *v
)
463 unsigned long irq_flags
;
466 for_each_online_cpu(i
)
467 seq_printf(seq
, "CPU%d:\t\tonline\n", i
);
469 mt_sched_check_tasks();
470 spin_lock_irqsave(&mt_sched_spinlock
, irq_flags
);
471 seq_puts(seq
, "\n PID REAL BACKUP CMD\n");
472 list_for_each_entry(tmp
, &mt_task_head
.list
, list
) {
473 cpumask_and(&mask
, &tmp
->p
->cpus_allowed
, cpu_online_mask
);
474 seq_printf(seq
, "%5d %4lu %4lu %s\n", tmp
->pid
, *mask
.bits
, *tmp
->mask
.bits
,
477 spin_unlock_irqrestore(&mt_sched_spinlock
, irq_flags
);
482 static unsigned int sched_status_poll(struct file
*file
, poll_table
*wait
)
487 static int __init
sched_proc_init(void)
489 struct proc_dir_entry
*pe
;
491 if (!proc_mkdir("mtk_sched", NULL
))
494 pe
= proc_create("mtk_sched/affinity_status", 0444, NULL
, &sched_status_fops
);
502 * sched_cpu_notify - sched cpu notifer callback function.
504 static int sched_cpu_notify(struct notifier_block
*self
, unsigned long action
, void *hcpu
)
506 long cpu
= (long)hcpu
;
508 unsigned long irq_flags
;
512 spin_lock_irqsave(&mt_sched_spinlock
, irq_flags
);
513 list_for_each_entry(tmp
, &mt_task_head
.list
, list
) {
514 if (cpumask_test_cpu(cpu
, &(tmp
->mask
))) {
515 if (tmp
->pid
== tmp
->p
->pid
)
516 cpumask_copy(&tmp
->p
->cpus_allowed
, &(tmp
->mask
));
519 spin_unlock_irqrestore(&mt_sched_spinlock
, irq_flags
);
522 case CPU_DOWN_FAILED
:
524 case CPU_DOWN_PREPARE
:
532 static struct notifier_block sched_cpu_nb
= {
533 .notifier_call
= sched_cpu_notify
,
536 static int __init
sched_module_init(void)
539 unsigned long irq_flags
;
541 ret
= sched_ioctl_init();
545 ret
= sched_proc_init();
549 ret
= register_cpu_notifier(&sched_cpu_nb
);
553 spin_lock_irqsave(&mt_sched_spinlock
, irq_flags
);
554 INIT_LIST_HEAD(&(mt_task_head
.list
));
555 spin_unlock_irqrestore(&mt_sched_spinlock
, irq_flags
);
559 static void sched_module_exit(void)
561 class_destroy(sched_class
);
562 cdev_del(sched_ioctl_cdev
);
563 unregister_chrdev_region(sched_dev_num
, 1);
564 pr_alert("MT_SCHED: driver removed.\n");
566 module_init(sched_module_init
);
567 module_exit(sched_module_exit
);
569 MODULE_LICENSE("GPL");
570 MODULE_AUTHOR("YaTing Chang <yt.chang@mediatek.com>");
571 MODULE_DESCRIPTION("This is sched module.");
573 #endif /* CONFIG_MT_SCHED */