diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | sad_mod.c (renamed from mod_add.c) | 63 |
2 files changed, 44 insertions, 25 deletions
@@ -1,12 +1,12 @@ -obj-m += mod_add.o +obj-m += sad_mod.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules ins: - sudo insmod mod_add.ko + sudo insmod sad_mod.ko rm: - sudo rmmod mod_add + sudo rmmod sad_mod sudo rm -f dev nod: all ins @@ -20,8 +20,10 @@ static dev_t dev; static struct cdev *cdev; static int device_open_count = 0; +#define LL_MAX_LEN 20 + struct sad_buf { - char *buf; + char buf[LL_MAX_LEN + 1]; size_t size; struct semaphore lock; } *buf; @@ -34,6 +36,41 @@ static struct file_operations sad_fops = { .release = sad_release }; +static ssize_t sad_parse(const char __user *user_buf, size_t len) { + char *in_buf; + unsigned long uncopied; + long long lhs, rhs, res; + char op; + int ret; + + in_buf = kmalloc(len, GFP_KERNEL); + if (!in_buf) + return -ENOMEM; + + uncopied = copy_from_user(in_buf, user_buf, len); + if (uncopied > 0) { + kfree(in_buf); + return -EFAULT; + } + + sscanf(in_buf, "%lld%c%lld", &lhs, &op, &rhs); + + switch (op) { + case '+': res = lhs + rhs; break; + case '-': res = lhs - rhs; break; + case '*': res = lhs * rhs; break; + case '/': res = lhs / rhs; break; + case '%': res = lhs & rhs; break; + default: + kfree(in_buf); + return -EPROTO; + } + + ret = snprintf(buf->buf, LL_MAX_LEN + 1, "%lld", res); + buf->size = ret; + + return len; /* need to indicate, that all data was processed */ +} static ssize_t sad_read(struct file *flip, char __user *user_buf, size_t len, loff_t *offset) { size_t bytes_left, read_size, uncopied; @@ -53,34 +90,18 @@ static ssize_t sad_read(struct file *flip, char __user *user_buf, size_t len, lo *offset += 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) { - size_t uncopied; + ssize_t ret; if (down_interruptible(&buf->lock)) return -ERESTARTSYS; - if (buf->buf) - kfree(buf->buf); - - buf->buf = kmalloc(len, GFP_KERNEL); - if (!buf->buf) { - up(&buf->lock); - return -ENOMEM; - } - - buf->size = len; - - *offset = 0; - - uncopied = copy_from_user(buf->buf, user_buf, len); - + ret = sad_parse(user_buf, len); up(&buf->lock); - - return len - uncopied; + return ret; } static int sad_open(struct inode *inode, struct file *file) { @@ -130,8 +151,6 @@ 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"); |