forked from sysprog21/ksort
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsort_mod.c
148 lines (119 loc) · 3.36 KB
/
sort_mod.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
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/version.h>
#include "sort.h"
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("National Cheng Kung University, Taiwan");
MODULE_DESCRIPTION("Concurrent sorting driver");
MODULE_VERSION("0.1");
#define DEVICE_NAME "sort"
static dev_t dev = -1;
static struct cdev cdev;
static struct class *class;
struct workqueue_struct *workqueue;
static int sort_open(struct inode *inode, struct file *file)
{
return 0;
}
static int sort_release(struct inode *inode, struct file *file)
{
return 0;
}
static int num_compare(const void *a, const void *b)
{
return (*(int *) a - *(int *) b);
}
static ssize_t sort_read(struct file *file,
char *buf,
size_t size,
loff_t *offset)
{
unsigned long len;
size_t es;
void *sort_buffer = kmalloc(size, GFP_KERNEL);
if (!sort_buffer)
return 0;
/* FIXME: Requiring users to manually input data into a buffer for read
* operations is not ideal, even if it is only for testing purposes.
*/
len = copy_from_user(sort_buffer, buf, size);
if (len != 0)
return 0;
/* TODO: While currently designed to handle integer arrays, there is an
* intention to expand the sorting object's capability to accommodate
* various types in the future.
*/
es = sizeof(int);
sort_main(sort_buffer, size / es, es, num_compare);
len = copy_to_user(buf, sort_buffer, size);
if (len != 0)
return 0;
kfree(sort_buffer);
return size;
}
static ssize_t sort_write(struct file *file,
const char *buf,
size_t size,
loff_t *offset)
{
return 0;
}
static const struct file_operations fops = {
.read = sort_read,
.write = sort_write,
.open = sort_open,
.release = sort_release,
.owner = THIS_MODULE,
};
static int __init sort_init(void)
{
struct device *device;
printk(KERN_INFO DEVICE_NAME ": loaded\n");
if (alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME) < 0)
return -1;
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)
class = class_create(THIS_MODULE, DEVICE_NAME);
#else
class = class_create(DEVICE_NAME);
#endif
if (IS_ERR(class)) {
goto error_unregister_chrdev_region;
}
device = device_create(class, NULL, dev, NULL, DEVICE_NAME);
if (IS_ERR(device)) {
goto error_class_destroy;
}
cdev_init(&cdev, &fops);
if (cdev_add(&cdev, dev, 1) < 0)
goto error_device_destroy;
workqueue = alloc_workqueue("sortq", 0, WQ_MAX_ACTIVE);
if (!workqueue)
goto error_cdev_del;
return 0;
error_cdev_del:
cdev_del(&cdev);
error_device_destroy:
device_destroy(class, dev);
error_class_destroy:
class_destroy(class);
error_unregister_chrdev_region:
unregister_chrdev_region(dev, 1);
return -1;
}
static void __exit sort_exit(void)
{
/* Given that drain_workqueue will be executed, there is no need for an
* explicit flush action.
*/
destroy_workqueue(workqueue);
cdev_del(&cdev);
device_destroy(class, dev);
class_destroy(class);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO DEVICE_NAME ": unloaded\n");
}
module_init(sort_init);
module_exit(sort_exit);