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 (at) 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 (at) 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 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 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 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 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 } 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