diff --git a/test.c b/test.c index 53e77b7..08be7b1 100644 --- a/test.c +++ b/test.c @@ -1,67 +1,192 @@ #include #include -#include #include -#include #include -#include +#include +#include +#include MODULE_DESCRIPTION("My kernel module"); -MODULE_AUTHOR("Me"); +MODULE_AUTHOR("maxsos"); MODULE_LICENSE("GPL"); #define DUMMY_MINOR 0 #define DUMMY_NUM_MINORS 1 #define DUMMY_MODULE_NAME "dummy" +DEFINE_MUTEX(my_mutex); + +struct node { + struct node* next; + size_t len; + char* line; +}; + struct dummy_device_data { struct cdev cdev; + bool is_read; dev_t dev; + struct node* node; }; static struct dummy_device_data dummy_device_data[DUMMY_NUM_MINORS]; +static int dummy_check_if_opened_before[100]; -static int dummy_open(struct inode *inode, struct file *file) -{ +static int dummy_open(struct inode *inode, struct file *file) { printk("%s: opened.\n", DUMMY_MODULE_NAME); - return 0; } -static int dummy_release (struct inode *inode, struct file *file) -{ +static int dummy_release(struct inode *inode, struct file *file) { printk("%s: closed.\n", DUMMY_MODULE_NAME); - return 0; } +static ssize_t dummy_read(struct file *file, char __user *user_buffer, + size_t size, loff_t * offset) { + mutex_lock(&my_mutex); + ssize_t error = 0; + int i; + for(i = 0; i < 100; ++i) + if (dummy_check_if_opened_before[i] == current->pid) { + dummy_check_if_opened_before[i] = 0; + goto read_out_err; + } + + struct dummy_device_data *ddd = &dummy_device_data[0]; + struct node *n = ddd->node; + + if(dummy_device_data[0].is_read) { + dummy_device_data[0].is_read = false; + goto read_out_err; + } + + if(n == NULL) { + printk("NODE IS NULL:((\n"); + goto read_out_err; + } + struct node *next = n->next; + + if(!n->line || !n->len) { + printk("LINE IS NULL:((\n"); + goto read_out_err; + } + + printk("READ %zu//%zu \n", size, dummy_device_data[0].node->len); + size_t len = n->len; + + if (copy_to_user(user_buffer, n->line, len)) { + error = -EFAULT; + goto read_out_err; + } + + vfree(n->line); + vfree(n); + dummy_device_data[0].node = next; + dummy_device_data[0].is_read = true; + mutex_unlock(&my_mutex); + + for(i = 0; i < 100; ++i) + if (dummy_check_if_opened_before[i] != 0) { + dummy_check_if_opened_before[i] = current->pid; + break; + } + + return len; + +read_out_err: + mutex_unlock(&my_mutex); + return error; +} + +static ssize_t dummy_write(struct file *file, const char __user *user_buffer, + size_t size, loff_t * offset) { + mutex_lock(&my_mutex); + ssize_t error = 0; + // printk("Write\n"); + struct dummy_device_data *ddd = &dummy_device_data[0]; + struct node *n = ddd->node; + + if (size <= 0) + return 0; + + if (!n) { + ddd->node = vmalloc(sizeof(struct node)); + n = ddd->node; + } else { + while (n->next) + n = n->next; + n->next = vmalloc(sizeof(struct node)); + n = n->next; + } + + if (!n) { + pr_err("%s: vmalloc failed: can't alloc memory for node. \n", + __FUNCTION__, size); + error = -ENOMEM; + goto write_out_err; + } + + n->line = vmalloc(size * sizeof(char)); + + if (!n->line) { + pr_err("%s: vmalloc failed: can't alloc memory for line %zu size. \n", + __FUNCTION__, size); + error = -ENOMEM; + goto write_out_err; + } + + if (copy_from_user(n->line, user_buffer, size)) { + error = -EFAULT; + goto write_out_err; + } + + n->len = size; + n->next = NULL; + // printk("Address: %p\t%p\n", dummy_device_data[0].node, n); + printk("WRITEN: line=%s, len=%zu, size=%zu\n", + n->line, n->len, size); + + mutex_unlock(&my_mutex); + return size; + +write_out_err: + mutex_unlock(&my_mutex); + return error; +} + static struct file_operations dummy_fops = { .owner = THIS_MODULE, - .open = dummy_open, - .release = dummy_release + .open = dummy_open, + .release = dummy_release, + .read = dummy_read, + .write = dummy_write, }; static int dummy_chrdev_init(void) { int error; dev_t first_dev; - unsigned int major, first_minor; int i; - error = alloc_chrdev_region(&first_dev, DUMMY_MINOR, DUMMY_NUM_MINORS, - DUMMY_MODULE_NAME); + error = alloc_chrdev_region(&first_dev, DUMMY_MINOR, + DUMMY_NUM_MINORS, DUMMY_MODULE_NAME); + if (error) { - pr_err("%s: alloc_chrdev_region failed: %d\n", - __FUNCTION__, error); + pr_err("%s: alloc_chrdev_region failed: %d. \n", + __FUNCTION__, error); return error; } - - major = MAJOR(first_dev); - first_minor = MINOR(first_dev); - BUG_ON(first_minor + DUMMY_NUM_MINORS > MINORMASK); - - for (i = 0; i < DUMMY_NUM_MINORS; i++) { - dummy_device_data[i].dev = MKDEV(major, first_minor + i); + BUG_ON(MINOR(first_dev) + DUMMY_NUM_MINORS > MINORMASK); + + for(i = 0; i < DUMMY_NUM_MINORS; ++i) { + dummy_device_data[i].dev = MKDEV(MAJOR(first_dev), + MINOR(first_dev) + i); + dummy_device_data[i].node = NULL; + // dummy_device_data[i].node = vmalloc(sizeof(struct node)); + // dummy_device_data[i].node->line = NULL; + // dummy_device_data[i].node->next = NULL; + // dummy_device_data[i].node->len = 0; } return 0; @@ -70,19 +195,16 @@ static int dummy_chrdev_init(void) static int dummy_cdev_init(struct dummy_device_data *device_data) { int error; - struct cdev *cdev = &device_data->cdev; - cdev_init(cdev, &dummy_fops); - error = cdev_add(cdev, device_data->dev, 1); + cdev_init(&device_data->cdev, &dummy_fops); + error = cdev_add(&device_data->cdev, device_data->dev, 1); + if (error) { - pr_err("%s: cdev_add failed: %d\n", - __FUNCTION__, error); + pr_err("%s: alloc_cdev_add failed: %d. \n", + __FUNCTION__, error); + return error; } - - printk("%s: created character device %x:%x (ma:mi).\n", DUMMY_MODULE_NAME, - MAJOR(device_data->dev), MINOR(device_data->dev)); - - return error; + return 0; } static int dummy_init(void) @@ -106,14 +228,38 @@ static int dummy_init(void) if (error) { pr_err("%s: dummy_cdev_init failed: %d\n", __FUNCTION__, error); + return error; } + mutex_init(&my_mutex); + for(i = 0; i < 100; ++i) + dummy_check_if_opened_before[i] = 0; - return 0; + return 0; } static void dummy_exit(void) { - printk("%s: Bye\n", __FUNCTION__); + int i; + for(i = 0; i < DUMMY_NUM_MINORS; ++i) { + struct dummy_device_data *ddd = &dummy_device_data[0]; + struct node *n = ddd->node; + struct node *temp; + + while (n) { + vfree(n->line); + temp = n->next; + vfree(n); + n = temp; + } + cdev_del(&dummy_device_data[i].cdev); + } + + unregister_chrdev_region(dummy_device_data[0].dev, + DUMMY_NUM_MINORS); + + mutex_destroy(&my_mutex); + + printk("%s: Bye\n", __FUNCTION__); } module_init(dummy_init); diff --git a/test_one_line_buf.c b/test_one_line_buf.c new file mode 100644 index 0000000..f5b932f --- /dev/null +++ b/test_one_line_buf.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("My kernel module"); +MODULE_AUTHOR("maxsos"); +MODULE_LICENSE("GPL"); + +#define DUMMY_MINOR 0 +#define DUMMY_NUM_MINORS 1 +#define DUMMY_MODULE_NAME "dummy" + +struct dummy_device_data { + struct cdev cdev; + dev_t dev; + size_t size; + char* buffer; +}; + +static struct dummy_device_data dummy_device_data[DUMMY_NUM_MINORS]; + +static int dummy_open(struct inode *inode, struct file *file) { + printk("%s: opened.\n", DUMMY_MODULE_NAME); + return 0; +} + + +static int dummy_release(struct inode *inode, struct file *file) { + printk("%s: closed.\n", DUMMY_MODULE_NAME); + return 0; +} + +static ssize_t dummy_read(struct file *file, char __user *user_buffer, + size_t size, loff_t * offset) { + size_t len = dummy_device_data[0].size; + printk("READ %zu//%zu \n", size, len); + if (len <= 0) + return 0; + + if (copy_to_user(user_buffer, + dummy_device_data[0].buffer, + len)) + return -EFAULT; + + vfree(dummy_device_data[0].buffer); + dummy_device_data[0].size = 0; + return len; +} + +static ssize_t dummy_write(struct file *file, const char __user *user_buffer, + size_t size, loff_t * offset) { + printk("WRITE %zu//%zu \n", size, dummy_device_data[0].size); + if (size <= 0) + return 0; + + dummy_device_data[0].buffer = vmalloc(size * sizeof(char)); + + if (!dummy_device_data[0].buffer) { + pr_err("%s: vmalloc failed: can't alloc memory %zu size. \n", + __FUNCTION__, size); + return -1; + } + + if (copy_from_user(dummy_device_data[0].buffer, user_buffer, size)) + return -EFAULT; + + dummy_device_data[0].size = size; + return size; +} + +static struct file_operations dummy_fops = { + .owner = THIS_MODULE, + .open = dummy_open, + .release = dummy_release, + .read = dummy_read, + .write = dummy_write, +}; + +static int dummy_chrdev_init(void) +{ + int error; + dev_t first_dev; + int i; + + error = alloc_chrdev_region(&first_dev, DUMMY_MINOR, + DUMMY_NUM_MINORS, DUMMY_MODULE_NAME); + + if (error) { + pr_err("%s: alloc_chrdev_region failed: %d. \n", + __FUNCTION__, error); + return error; + } + BUG_ON(MINOR(first_dev) + DUMMY_NUM_MINORS > MINORMASK); + + for(i = 0; i < DUMMY_NUM_MINORS; ++i) { + dummy_device_data[i].dev = MKDEV(MAJOR(first_dev), + MINOR(first_dev) + i); + dummy_device_data[i].size = 0; + dummy_device_data[i].buffer = NULL; + } + + return 0; +} + +static int dummy_cdev_init(struct dummy_device_data *device_data) +{ + int error; + + cdev_init(&device_data->cdev, &dummy_fops); + error = cdev_add(&device_data->cdev, device_data->dev, 1); + + if (error) { + pr_err("%s: alloc_cdev_add failed: %d. \n", + __FUNCTION__, error); + return error; + } + return 0; +} + +static int dummy_init(void) +{ + int error = 0; + int i; + + printk("%s: Hi\n", __FUNCTION__); + + error = dummy_chrdev_init(); + if (error) { + pr_err("%s: dummy_dev_init failed: %d\n", + __FUNCTION__, error); + return error; + } + + for (i = 0; i < DUMMY_NUM_MINORS && !error; i++) { + error = dummy_cdev_init(&dummy_device_data[i]); + } + + if (error) { + pr_err("%s: dummy_cdev_init failed: %d\n", + __FUNCTION__, error); + } + return 0; +} + +static void dummy_exit(void) +{ + int i; + for(i = 0; i < DUMMY_NUM_MINORS; ++i) + vfree(dummy_device_data[i].buffer); + + for(i = 0; i < DUMMY_NUM_MINORS; i++) { + /* release devs[i] fields */ + cdev_del(&dummy_device_data[i].cdev); + } + unregister_chrdev_region(dummy_device_data[0].dev, + DUMMY_NUM_MINORS); + + printk("%s: Bye\n", __FUNCTION__); +} +module_init(dummy_init); +module_exit(dummy_exit);