1 /*
2 * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
19 *
20 */
21
22 #include <linux/module.h>
23 #include <linux/device.h>
24 #include <linux/uaccess.h>
25 #include "ltp_uaccess.h"
26
27 MODULE_AUTHOR("Alexey Kodanev <alexey.kodanev@oracle.com>");
28 MODULE_DESCRIPTION("User-space access LTP test");
29 MODULE_LICENSE("GPL");
30
31 #define prk_err(fmt, ...) \
32 pr_err(DEV_NAME ": " fmt "\n", ##__VA_ARGS__)
33 #define prk_info(fmt, ...) \
34 pr_info(DEV_NAME ": " fmt "\n", ##__VA_ARGS__)
35
36 /*
37 * Test-case result,
38 * if test is passed, value will be set to 0
39 */
40 static int test_result;
41
device_release(struct device * dev)42 static void device_release(struct device *dev)
43 {
44 prk_info("device released");
45 }
46
47 static struct device tdev = {
48 .init_name = DEV_NAME,
49 .release = device_release
50 };
51
sys_result(struct device * dev,struct device_attribute * attr,char * buf)52 static ssize_t sys_result(struct device *dev,
53 struct device_attribute *attr, char *buf)
54 {
55 return scnprintf(buf, PAGE_SIZE, "%d\n", test_result);
56 }
57 static DEVICE_ATTR(result, S_IRUSR, sys_result, NULL);
58
59
sys_tcase(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)60 static ssize_t sys_tcase(struct device *dev,
61 struct device_attribute *attr, const char *buf, size_t count)
62 {
63 unsigned long ptr = 0;
64 int tc = 0;
65 char *str, ch, buffer[str_size];
66
67 sscanf(buf, "%d %lu", &tc, &ptr);
68 str = (char *) ptr;
69 test_result = 0;
70
71 switch (tc) {
72 case TC_READ_USER:
73 if (copy_from_user(buffer, str, str_size))
74 prk_err("copy_from_user() failed");
75 test_result = strncmp(test_str, buffer, str_size) ? 1 : 0;
76 if (get_user(ch, str))
77 prk_err("get_user() failed");
78 test_result |= ch != test_str[0];
79 break;
80 case TC_WRITE_USER:
81 if (copy_to_user(str + 1, test_str + 1, str_size - 1)) {
82 prk_err("copy_to_user() failed");
83 test_result = 1;
84 }
85 /* write the first skipped character */
86 if (put_user(test_str[0], str)) {
87 prk_err("put_user() failed");
88 test_result |= 1;
89 }
90 break;
91 }
92
93 return count;
94 }
95 static DEVICE_ATTR(tcase, S_IWUSR, NULL, sys_tcase);
96
uaccess_init(void)97 static int uaccess_init(void)
98 {
99 int err = 0;
100 prk_info("Starting module");
101
102 err = device_register(&tdev);
103 if (err) {
104 prk_err("Unable to register device");
105 goto err0;
106 }
107 prk_info("device registered");
108
109 err = device_create_file(&tdev, &dev_attr_result);
110 if (err) {
111 prk_err("Can't create sysfs file 'result'");
112 goto err1;
113 }
114
115 err = device_create_file(&tdev, &dev_attr_tcase);
116 if (err) {
117 prk_err(": Can't create sysfs file 'tc'");
118 goto err2;
119 }
120
121 return 0;
122
123 err2:
124 device_remove_file(&tdev, &dev_attr_result);
125 err1:
126 device_unregister(&tdev);
127 err0:
128 return err;
129 }
module_init(uaccess_init)130 module_init(uaccess_init)
131
132 static void uaccess_exit(void)
133 {
134 prk_info("Unloading module");
135
136 device_remove_file(&tdev, &dev_attr_result);
137 device_remove_file(&tdev, &dev_attr_tcase);
138 device_unregister(&tdev);
139 }
140 module_exit(uaccess_exit)
141