-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkdreg2_main.c
214 lines (172 loc) · 6.07 KB
/
kdreg2_main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*
* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2012-2019 Cray(R)
* Copyright (C) 2020-2023 Hewlett Packard Enterprise Development LP
*
* Kernel level memory registration cache monitoring interface (KDREG2).
*
* The purpose of this driver is to allow processes to safely cache
* memory registration information in user space. An application using
* kdreg2 supplies the driver with 'monitor' requests. A monitor
* request specifies a region in the process's virtual address space that
* should be 'monitored' by kdreg2, and report back to user space
* when a virtual memory operation has occurred which would cause
* the cached memory registration information to be invalid. The
* application is responsible for doing the hardware device specific
* memory deregistration and cache cleanup.
*
* KDREG2 uses the mmu_notifier interface to monitor for changes in
* the virtual address space of the process/thread group.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "LICENSE" in the main directory for more details.
*
* Derived in part from dreg.c by Pete Wyckoff.
* Copyright (C) 2004-5 Pete Wyckoff <[email protected]>
* Distributed under the GNU Public License Version 2 (See LICENSE)
*/
#include "kdreg2_priv.h"
#include "kdreg2_version.h"
#include "kdreg2_build.h"
#include <linux/module.h>
#include <linux/slab.h>
MODULE_AUTHOR("Pete Wyckoff");
MODULE_AUTHOR("Cray Inc.");
MODULE_AUTHOR("Hewlett Packard Enterprise Development LP");
MODULE_DESCRIPTION("Dynamic registration cache monitoring using mmu notifiers");
MODULE_LICENSE("GPL v2");
static const char * const copyright[] = {
"Copyright (C) 2004-5 Pete Wyckoff",
"Copyright (C) 2012-2019 Cray(R)",
"Copyright (C) 2020-2023 Hewlett Packard Development LP",
};
struct kdreg2_global kdreg2_global = {
.driver_string = "Kernel Dynamic Registration (KDREG2) Interface",
.driver_copyright = copyright,
.num_copyright = ARRAY_SIZE(copyright),
.driver_name = KDREG2_DRIVER_NAME,
.class_name = KDREG2_CLASS_NAME,
.build_string = KDREG2_BUILD_DATE " " KDREG2_BUILD_HASH,
.driver_version = KDREG2_DRIVER_VERSION,
.driver_lock = __MUTEX_INITIALIZER(kdreg2_global.driver_lock),
.dev_id = 0,
.major_dev = 0,
.driver_numdev = 1,
.num_contexts = 0,
.debug_level = KDREG2_DEBUG_LEVEL,
.debug_mask = KDREG2_DEBUG_MASK,
.class = NULL,
.class_device = NULL,
.kdreg2_dev = { },
};
static struct file_operations kdreg2_fops = {
.owner = THIS_MODULE,
.read = kdreg2_read,
.write = kdreg2_write,
.poll = kdreg2_poll,
.unlocked_ioctl = kdreg2_ioctl,
.open = kdreg2_open,
.release = kdreg2_release,
};
/*
* Module initialization
*/
static int __init kdreg2_module_init(void)
{
int ret;
size_t i;
pr_info("%s - version 0x%llx\n", kdreg2_global.driver_string,
kdreg2_global.driver_version);
for (i = 0; i < kdreg2_global.num_copyright; i++)
pr_info("%s\n", kdreg2_global.driver_copyright[i]);
/* Register driver */
if (!kdreg2_global.major_dev) {
ret = alloc_chrdev_region(&kdreg2_global.dev_id, 0,
kdreg2_global.driver_numdev,
kdreg2_global.driver_name);
kdreg2_global.major_dev = MAJOR(kdreg2_global.dev_id);
} else {
kdreg2_global.dev_id = MKDEV(kdreg2_global.major_dev, 0);
ret = register_chrdev_region(kdreg2_global.dev_id,
kdreg2_global.driver_numdev,
kdreg2_global.driver_name);
}
if (ret)
goto err_alloc_chrdev;
/* Set the device file operations */
cdev_init(&kdreg2_global.kdreg2_dev.cdev, &kdreg2_fops);
ret = cdev_add(&kdreg2_global.kdreg2_dev.cdev,
kdreg2_global.dev_id,
kdreg2_global.driver_numdev);
if (ret)
goto err_cdev_add;
/* set up the kdreg2 class */
KDREG2_DEBUG(KDREG2_DEBUG_INIT, 2,
"creating class %s", kdreg2_global.class_name);
#if KDREG2_CLASS_CREATE_WITH_MODULE
kdreg2_global.class = class_create(THIS_MODULE,
kdreg2_global.class_name);
#else
kdreg2_global.class = class_create(kdreg2_global.class_name);
#endif
if (IS_ERR(kdreg2_global.class)) {
ret = PTR_ERR(kdreg2_global.class);
pr_warn("couldn't create class %s\n",
kdreg2_global.class_name);
goto err_class_create;
}
kdreg2_global.class->dev_uevent = kdreg2_dev_uevent;
/* create class device */
KDREG2_DEBUG(KDREG2_DEBUG_INIT, 2,
"creating %s device", kdreg2_global.class_name);
kdreg2_global.class_device =
device_create(kdreg2_global.class, NULL,
kdreg2_global.dev_id, NULL,
"%s", kdreg2_global.driver_name);
if (IS_ERR(kdreg2_global.class_device)) {
ret = PTR_ERR(kdreg2_global.class_device);
pr_warn("class_device_create() returned error %d\n", ret);
goto err_class_dev;
}
ret = kdreg2_create_class_device_files();
if (ret) {
pr_warn("couldn't create attribute files.\n");
goto err_class_dev_attr_files;
}
pr_info("data mode: %s\n", KDREG2_DB_MODE_NAME);
pr_info("Module installed successfully.\n");
return 0;
err_class_dev_attr_files:
device_destroy(kdreg2_global.class,
kdreg2_global.kdreg2_dev.cdev.dev);
err_class_dev:
class_destroy(kdreg2_global.class);
err_class_create:
cdev_del(&kdreg2_global.kdreg2_dev.cdev);
err_cdev_add:
unregister_chrdev_region(kdreg2_global.dev_id,
kdreg2_global.driver_numdev);
err_alloc_chrdev:
pr_warn("Module installation aborted: %i.\n", ret);
return ret;
}
/*
* Module removal.
*/
static void __exit kdreg2_module_exit(void)
{
KDREG2_DEBUG(KDREG2_DEBUG_EXIT, 1,
"Cleaning up kdreg2 module resources");
/* clean up sys fs stuff first, then destroy the device, etc. */
kdreg2_remove_class_device_files();
device_destroy(kdreg2_global.class,
kdreg2_global.kdreg2_dev.cdev.dev);
class_destroy(kdreg2_global.class);
cdev_del(&kdreg2_global.kdreg2_dev.cdev);
unregister_chrdev_region(kdreg2_global.dev_id,
kdreg2_global.driver_numdev);
pr_info("Module uninstalled.\n");
}
module_init(kdreg2_module_init);
module_exit(kdreg2_module_exit);