From ae62af0e270e058f5e37bc6f7b7e90cb413626d6 Mon Sep 17 00:00:00 2001 From: maxsos Date: Wed, 28 Oct 2020 10:32:43 +0300 Subject: [PATCH 1/4] task1 --- test_one_line_buf.c | 164 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 test_one_line_buf.c 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); From 25a06eaaee2d241dcb11e052510063aeb1753115 Mon Sep 17 00:00:00 2001 From: maxsos Date: Wed, 28 Oct 2020 10:33:10 +0300 Subject: [PATCH 2/4] task2 --- test.c | 181 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 145 insertions(+), 36 deletions(-) diff --git a/test.c b/test.c index 53e77b7..7300fab 100644 --- a/test.c +++ b/test.c @@ -1,67 +1,160 @@ #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_open(struct inode *inode, struct file *file) -{ +static int dummy_open(struct inode *inode, struct file *file) { printk("%s: opened.\n", DUMMY_MODULE_NAME); - + mutex_init(&my_mutex); + + mutex_lock(&my_mutex); 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); - + mutex_unlock(&my_mutex); return 0; } +static ssize_t dummy_read(struct file *file, char __user *user_buffer, + size_t size, loff_t * offset) { + 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; + return 0; + } + if(n == NULL) { + printk("NODE IS NULL:((\n"); + return 0; + } + struct node *next = n->next; + + if(!n->line || !n->len) { + printk("LINE IS NULL:((\n"); + return 0; + } + + 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)) + return -EFAULT; + + vfree(n->line); + vfree(n); + dummy_device_data[0].node = next; + dummy_device_data[0].is_read = true; + return len; +} + +static ssize_t dummy_write(struct file *file, const char __user *user_buffer, + size_t size, loff_t * offset) { + 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); + return -1; + } + + 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); + return -1; + } + + if (copy_from_user(n->line, user_buffer, size)) + return -EFAULT; + + 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); + return size; +} + 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 +163,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 +196,33 @@ static int dummy_init(void) if (error) { pr_err("%s: dummy_cdev_init failed: %d\n", __FUNCTION__, error); + return error; } - 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); + + printk("%s: Bye\n", __FUNCTION__); } module_init(dummy_init); From b160f660bf9780103782ee1749d3501c7b14367b Mon Sep 17 00:00:00 2001 From: maxsos Date: Wed, 28 Oct 2020 10:36:23 +0300 Subject: [PATCH 3/4] Fix mutex --- test.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test.c b/test.c index 7300fab..92af72c 100644 --- a/test.c +++ b/test.c @@ -14,7 +14,7 @@ MODULE_LICENSE("GPL"); #define DUMMY_NUM_MINORS 1 #define DUMMY_MODULE_NAME "dummy" -DEFINE_MUTEX(my_mutex); +// DEFINE_MUTEX(my_mutex); struct node { struct node* next; @@ -33,15 +33,15 @@ 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); - mutex_init(&my_mutex); + // mutex_init(&my_mutex); - mutex_lock(&my_mutex); + // mutex_lock(&my_mutex); return 0; } static int dummy_release(struct inode *inode, struct file *file) { printk("%s: closed.\n", DUMMY_MODULE_NAME); - mutex_unlock(&my_mutex); + // mutex_unlock(&my_mutex); return 0; } From 4086f592ddbb8713569fb41ddf13c8ca952ca331 Mon Sep 17 00:00:00 2001 From: maxsos Date: Wed, 28 Oct 2020 20:11:28 +0300 Subject: [PATCH 4/4] Finally add mutex in read and write function --- test.c | 75 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/test.c b/test.c index 92af72c..08be7b1 100644 --- a/test.c +++ b/test.c @@ -14,7 +14,7 @@ MODULE_LICENSE("GPL"); #define DUMMY_NUM_MINORS 1 #define DUMMY_MODULE_NAME "dummy" -// DEFINE_MUTEX(my_mutex); +DEFINE_MUTEX(my_mutex); struct node { struct node* next; @@ -30,56 +30,80 @@ struct dummy_device_data { }; 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) { printk("%s: opened.\n", DUMMY_MODULE_NAME); - // mutex_init(&my_mutex); - - // mutex_lock(&my_mutex); return 0; } static int dummy_release(struct inode *inode, struct file *file) { printk("%s: closed.\n", DUMMY_MODULE_NAME); - // mutex_unlock(&my_mutex); 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; - return 0; + goto read_out_err; } + if(n == NULL) { printk("NODE IS NULL:((\n"); - return 0; + goto read_out_err; } struct node *next = n->next; if(!n->line || !n->len) { printk("LINE IS NULL:((\n"); - return 0; + 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)) - return -EFAULT; - + 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) { - printk("Write\n"); + 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; @@ -96,12 +120,11 @@ static ssize_t dummy_write(struct file *file, const char __user *user_buffer, n = n->next; } - - if (!n) { pr_err("%s: vmalloc failed: can't alloc memory for node. \n", __FUNCTION__, size); - return -1; + error = -ENOMEM; + goto write_out_err; } n->line = vmalloc(size * sizeof(char)); @@ -109,18 +132,27 @@ static ssize_t dummy_write(struct file *file, const char __user *user_buffer, if (!n->line) { pr_err("%s: vmalloc failed: can't alloc memory for line %zu size. \n", __FUNCTION__, size); - return -1; + error = -ENOMEM; + goto write_out_err; } - if (copy_from_user(n->line, user_buffer, size)) - return -EFAULT; + 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("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 = { @@ -198,6 +230,9 @@ static int dummy_init(void) __FUNCTION__, error); return error; } + mutex_init(&my_mutex); + for(i = 0; i < 100; ++i) + dummy_check_if_opened_before[i] = 0; return 0; } @@ -222,6 +257,8 @@ static void dummy_exit(void) unregister_chrdev_region(dummy_device_data[0].dev, DUMMY_NUM_MINORS); + mutex_destroy(&my_mutex); + printk("%s: Bye\n", __FUNCTION__); }