1/*
2 * ko_adapt.c
3 *
4 * function for find symbols not exported
5 *
6 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17#include "ko_adapt.h"
18#include <linux/types.h>
19#include <linux/mm_types.h>
20#include <linux/stddef.h>
21#include <linux/cred.h>
22#include <linux/version.h>
23#if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
24#include <linux/sched/task.h>
25#endif
26#include <linux/cpumask.h>
27#include <linux/syscalls.h>
28#include <linux/fs.h>
29#include "tc_ns_log.h"
30
31typedef const struct cred *(get_task_cred_func)(struct task_struct *);
32typedef void (kthread_bind_mask_func)(struct task_struct *, const struct cpumask *);
33typedef struct page *(alloc_pages_func)(gfp_t gfp_mask, unsigned int order);
34typedef struct workqueue_attrs *(alloc_workqueue_attrs_func)(gfp_t gfp_mask);
35typedef void (free_workqueue_attrs_func)(struct workqueue_attrs *attrs);
36
37const struct cred *koadpt_get_task_cred(struct task_struct *task)
38{
39#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
40	return get_task_cred(task);
41#else
42	static get_task_cred_func *get_task_cred_pt = NULL;
43
44	if (!task)
45		return NULL;
46
47	if (!get_task_cred_pt) {
48		get_task_cred_pt = (get_task_cred_func *)
49			(uintptr_t)kallsyms_lookup_name("get_task_cred");
50		if (IS_ERR_OR_NULL(get_task_cred_pt)) {
51			tloge("fail to find symbol get task cred\n");
52			return NULL;
53		}
54	}
55	return get_task_cred_pt(task);
56#endif
57}
58
59void koadpt_kthread_bind_mask(struct task_struct *task,
60	const struct cpumask *mask)
61{
62#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
63	(void)set_cpus_allowed_ptr(task, mask);
64#else
65	static kthread_bind_mask_func *kthread_bind_mask_pt = NULL;
66
67	if (!task || !mask)
68		return;
69
70	if (!kthread_bind_mask_pt) {
71		kthread_bind_mask_pt = (kthread_bind_mask_func *)
72			(uintptr_t)kallsyms_lookup_name("kthread_bind_mask");
73		if (IS_ERR_OR_NULL(kthread_bind_mask_pt)) {
74			tloge("fail to find symbol kthread bind mask\n");
75			return;
76		}
77	}
78	kthread_bind_mask_pt(task, mask);
79#endif
80}
81
82struct page *koadpt_alloc_pages(gfp_t gfp_mask, unsigned int order)
83{
84#ifdef CONFIG_NUMA
85#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
86	return alloc_pages(gfp_mask, order);
87#else
88	static alloc_pages_func *alloc_pages_pt = NULL;
89
90	if (!alloc_pages_pt) {
91		alloc_pages_pt = (alloc_pages_func *)
92			(uintptr_t)kallsyms_lookup_name("alloc_pages_current");
93		if (IS_ERR_OR_NULL(alloc_pages_pt)) {
94			tloge("fail to find symbol alloc pages current\n");
95			return NULL;
96		}
97	}
98	return alloc_pages_pt(gfp_mask, order);
99#endif
100#else
101	return alloc_pages(gfp_mask, order);
102#endif
103}
104
105struct workqueue_attrs *koadpt_alloc_workqueue_attrs(gfp_t gfp_mask)
106{
107#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
108	struct workqueue_attrs *attrs;
109	(void)gfp_mask;
110
111	attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
112	if (!attrs) {
113		tloge("alloc workqueue attr fail\n");
114		return NULL;
115	}
116
117	if (alloc_cpumask_var(&attrs->cpumask, GFP_KERNEL) == false) {
118		tloge("alloc cpumask var fail\n");
119		kfree(attrs);
120		return NULL;
121	}
122
123	cpumask_copy(attrs->cpumask, cpu_possible_mask);
124
125	return attrs;
126#else
127	static alloc_workqueue_attrs_func *alloc_workqueue_attrs_pt = NULL;
128
129	if (!alloc_workqueue_attrs_pt) {
130		alloc_workqueue_attrs_pt = (alloc_workqueue_attrs_func *)
131			(uintptr_t)kallsyms_lookup_name("alloc_workqueue_attrs");
132		if (IS_ERR_OR_NULL(alloc_workqueue_attrs_pt)) {
133			tloge("fail to find symbol alloc workqueue attrs\n");
134			return NULL;
135		}
136	}
137	return alloc_workqueue_attrs_pt(gfp_mask);
138#endif
139}
140
141void koadpt_free_workqueue_attrs(struct workqueue_attrs *attrs)
142{
143#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
144	if (!attrs)
145		return;
146
147	free_cpumask_var(attrs->cpumask);
148	kfree(attrs);
149#else
150	static free_workqueue_attrs_func *free_workqueue_attrs_pt = NULL;
151
152	if (!attrs)
153		return;
154
155	if (!free_workqueue_attrs_pt) {
156		free_workqueue_attrs_pt = (free_workqueue_attrs_func *)
157			(uintptr_t)kallsyms_lookup_name("free_workqueue_attrs");
158		if (IS_ERR_OR_NULL(free_workqueue_attrs_pt)) {
159			tloge("fail to find symbol free workqueue attrs\n");
160			return;
161		}
162	}
163	free_workqueue_attrs_pt(attrs);
164#endif
165}