diff options
author | syn <isaqtm@gmail.com> | 2020-02-02 20:40:08 +0300 |
---|---|---|
committer | syn <isaqtm@gmail.com> | 2020-02-02 20:40:08 +0300 |
commit | f339f5666935584389a4c220af1ab6965e18bf40 (patch) | |
tree | e2d32990d0517a8c8586fc5002c43342bd41a294 | |
parent | d9f271c40b968501337f14d2bfef0884490064fe (diff) | |
download | sad-f339f5666935584389a4c220af1ab6965e18bf40.tar.gz |
Seems like we are not lock-free
-rw-r--r-- | mod_add.c | 48 |
1 files changed, 29 insertions, 19 deletions
@@ -5,6 +5,7 @@ #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/cdev.h> +#include <linux/semaphore.h> MODULE_LICENSE("GPL"); @@ -22,7 +23,8 @@ static int device_open_count = 0; struct sad_buf { char *buf; size_t size; -}; + struct semaphore lock; +} *buf; static struct file_operations sad_fops = { .owner = THIS_MODULE, @@ -34,64 +36,63 @@ static struct file_operations sad_fops = { static ssize_t sad_read(struct file *flip, char __user *user_buf, size_t len, loff_t *offset) { - struct sad_buf *buf = flip->private_data; size_t bytes_left, read_size, uncopied; - printk(KERN_INFO "Getting offset %llu\t buf size: %zu\n", *offset, buf->size); + if (down_interruptible(&buf->lock)) + return -ERESTARTSYS; - if (*offset >= buf->size) + if (*offset >= buf->size) { + up(&buf->lock); return 0; + } bytes_left = buf->size - *offset; read_size = min(bytes_left, len); uncopied = copy_to_user(user_buf, buf->buf + *offset, read_size); *offset += read_size - uncopied; - printk(KERN_INFO "off: %llu\t uncopied: %zu\t ret: %zu\n", *offset, uncopied, read_size - uncopied); + + up(&buf->lock); return read_size - uncopied; } static ssize_t sad_write(struct file *flip, const char __user *user_buf, size_t len, loff_t *offset) { - struct sad_buf *buf = flip->private_data; size_t uncopied; + if (down_interruptible(&buf->lock)) + return -ERESTARTSYS; + if (buf->buf) kfree(buf->buf); buf->buf = kmalloc(len, GFP_KERNEL); - if (!buf->buf) + if (!buf->buf) { + up(&buf->lock); return -ENOMEM; + } buf->size = len; *offset = 0; uncopied = copy_from_user(buf->buf, user_buf, len); - printk(KERN_INFO "uncopied: %zu\t ret: %zu\n", uncopied, len - uncopied); + + up(&buf->lock); return len - uncopied; } static int sad_open(struct inode *inode, struct file *file) { - struct sad_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - file->private_data = buf; - device_open_count++; try_module_get(THIS_MODULE); return 0; } static int sad_release(struct inode *inode, struct file *file) { - struct sad_buf *buf = file->private_data; - if (buf->buf) - kfree(buf->buf); - kfree(buf); device_open_count--; - module_put(THIS_MODULE); + if (device_open_count == 0) + module_put(THIS_MODULE); return 0; } @@ -101,6 +102,12 @@ static int __init sad_init(void) { const unsigned int minor = 0; const unsigned int count = 1; + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + sema_init(&buf->lock, 1); + rc = alloc_chrdev_region(&dev, minor, count, DEV_NAME); if (rc < 0) { printk(KERN_ALERT "Could not register device: %d\n", rc); @@ -123,6 +130,9 @@ static int __init sad_init(void) { } static void __exit sad_exit(void) { cdev_del(cdev); + if (buf->buf) + kfree(buf->buf); + kfree(buf); unregister_chrdev_region(dev, 1); printk(KERN_INFO "okay, bye\n"); } |