diff options
author | syn <isaqtm@gmail.com> | 2020-01-31 09:02:55 +0300 |
---|---|---|
committer | syn <isaqtm@gmail.com> | 2020-01-31 09:02:55 +0300 |
commit | c21e867c6b272fb6722c46aa0a06d63611d0a373 (patch) | |
tree | c2250fd3f42d195e263ef2b70d57bbef178ae7cd | |
parent | 6662cea6b2572cd70a60aadfb28312e2bbef6ecc (diff) | |
download | sad-c21e867c6b272fb6722c46aa0a06d63611d0a373.tar.gz |
Finished echo with private data
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | mod_add.c | 195 | ||||
-rw-r--r-- | test.c | 15 |
3 files changed, 100 insertions, 115 deletions
@@ -10,8 +10,9 @@ rm: sudo rm -f dev nod: all ins - sudo mknod dev c 238 0 - sudo chmod 666 dev + sudo mknod dev c $(shell awk '$$2=="sad_dev" {print $$1}' /proc/devices) 0 + sudo chgrp wheel dev + sudo chmod 664 dev clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean @@ -4,159 +4,128 @@ #include <linux/fs.h> #include <linux/slab.h> #include <linux/uaccess.h> +#include <linux/cdev.h> MODULE_LICENSE("GPL"); -#include "assoc_buf.h" +#define DEV_NAME "sad_dev" -#define DEV_NAME "mod_add" -#define OP_INVALID "Operation invalid\n" +static int sad_open(struct inode *, struct file *); +static int sad_release(struct inode *, struct file *); +static ssize_t sad_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t sad_write(struct file *, const char __user *, size_t, loff_t *); -static int device_open(struct inode *, struct file *); -static int device_release(struct inode *, struct file *); -static ssize_t device_read(struct file *, char *, size_t, loff_t *); -static ssize_t device_write(struct file *, const char *, size_t, loff_t *); - -static int major_num; +static dev_t dev; +static struct cdev *cdev; static int device_open_count = 0; -static struct buf_list { - struct asbuf *buf; - struct buf_list *next; -} *buffers; - -struct asbuf *find_by_inode(unsigned long ino) { - struct buf_list *iter = buffers->next; - while (iter) { - if (iter->buf->ino == ino) - return iter->buf; - iter = iter->next; - } - return NULL; -} - -ssize_t add_buf(struct asbuf *buf) { - struct buf_list *iter; +struct sad_buf { + char *buf; + size_t size; +}; - if (!buffers) { - buffers = kmalloc(sizeof(struct buf_list), GFP_KERNEL); - if (!buffers) - return -ENOMEM; - buffers->buf = buf; - buffers->next = NULL; - return 0; - } +static struct file_operations sad_fops = { + .owner = THIS_MODULE, + .read = sad_read, + .write = sad_write, + .open = sad_open, + .release = sad_release +}; - iter = buffers; - while (iter->next) - iter = iter->next; - iter->next = kmalloc(sizeof(struct buf_list), GFP_KERNEL); - if (!iter->next) - return -ENOMEM; - iter->buf = buf; - iter->next = NULL; - return 0; -} +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; -void free_buf_list(void) { - struct buf_list *iter = buffers, *next; + printk(KERN_INFO "Getting offset %llu\t buf size: %zu\n", *offset, buf->size); - while (iter) { - next = iter->next; - asbuf_free(iter->buf); - kfree(iter->buf); - kfree(iter); - iter = next; - } -} + if (*offset >= buf->size) + return 0; -ssize_t rm_by_inode(unsigned long ino) { - struct buf_list *iter = buffers; - struct buf_list *save_prev; + bytes_left = buf->size - *offset; + read_size = min(bytes_left, len); + uncopied = copy_to_user(user_buf, buf->buf + *offset, read_size); - if (!buffers) - return 0; + *offset += read_size - uncopied; + printk(KERN_INFO "off: %llu\t uncopied: %zu\t ret: %zu\n", *offset, uncopied, read_size - uncopied); - while (iter->next) { - save_prev = iter; - iter = iter->next; - if (iter->buf->ino == ino) { - save_prev->next = iter->next; - asbuf_free(iter->buf); - kfree(iter->buf); - kfree(iter); - return 0; - } - } - return -EINVAL; + return read_size - uncopied; } -static struct file_operations file_ops = { - .read = device_read, - .write = device_write, - .open = device_open, - .release = device_release -}; +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 (buf->buf) + kfree(buf->buf); -static ssize_t device_read(struct file *flip, char *buffer, size_t len, loff_t *offset) { - struct asbuf *buf = find_by_inode(flip->f_inode->i_ino); - printk(KERN_INFO "req inode %lu\n", flip->f_inode->i_ino); - if (!buf) - return -EINVAL; - return asbuf_to_user(buf, buffer, len, offset); -} + buf->buf = kmalloc(len, GFP_KERNEL); + if (!buf->buf) + return -ENOMEM; -static ssize_t device_write(struct file *flip, const char *buffer, size_t len, loff_t *offset) { - if (len == 0) - return 0; + buf->size = len; - return asbuf_from_user(find_by_inode(flip->f_inode->i_ino), buffer, len, offset); -} + *offset = 0; -static int device_open(struct inode *inode, struct file *file) { - struct asbuf *newbuf; + uncopied = copy_from_user(buf->buf, user_buf, len); + printk(KERN_INFO "uncopied: %zu\t ret: %zu\n", uncopied, len - uncopied); - if (device_open_count) - return -EBUSY; + return len - uncopied; +} - newbuf = kzalloc(sizeof(*newbuf), GFP_KERNEL); - if (!newbuf) +static int sad_open(struct inode *inode, struct file *file) { + struct sad_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) return -ENOMEM; - printk(KERN_INFO "opened for inode %lu", inode->i_ino); - newbuf->ino = inode->i_ino; - add_buf (newbuf); + file->private_data = buf; + device_open_count++; try_module_get(THIS_MODULE); return 0; } -static int device_release(struct inode *inode, struct file *file) { - rm_by_inode(inode->i_ino); +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); return 0; } -static int __init mod_add_init(void) { - buffers = kzalloc(sizeof(*buffers), GFP_KERNEL); +static int __init sad_init(void) { + int rc; + + const unsigned int minor = 0; + const unsigned int count = 1; - major_num = register_chrdev(0, DEV_NAME, &file_ops); - if (major_num < 0) { - printk(KERN_ALERT "Could not register device: %d\n", major_num); - return major_num; + rc = alloc_chrdev_region(&dev, minor, count, DEV_NAME); + if (rc < 0) { + printk(KERN_ALERT "Could not register device: %d\n", rc); + return rc; } else { - printk(KERN_INFO "mod_add loaded. dev maj = %d\n", major_num); - return 0; + printk(KERN_INFO "Allocated maj %d\n", MAJOR(dev)); + } + + cdev = cdev_alloc(); + cdev->owner = THIS_MODULE; + cdev->ops = &sad_fops; + rc = cdev_add(cdev, dev, 1); + + if (rc) { + printk(KERN_ALERT "Could not cdev_add: %d\n", rc); + return rc; } + + return 0; } -static void __exit mod_add_exit(void) { - unregister_chrdev(major_num, DEV_NAME); - free_buf_list(); +static void __exit sad_exit(void) { + cdev_del(cdev); + unregister_chrdev_region(dev, 1); printk(KERN_INFO "okay, bye\n"); } -module_init(mod_add_init); -module_exit(mod_add_exit); +module_init(sad_init); +module_exit(sad_exit); @@ -0,0 +1,15 @@ +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> + +int main() { + int fd = open("dev", O_RDWR); + const char buf[] = "Some string"; + printf("wrote %d bytes\n", write(fd, buf, sizeof(buf))); + char retbuf[256]; + int bytes_read = read(fd, retbuf, sizeof(retbuf)); + printf("read %d bytes\n", bytes_read); + retbuf[bytes_read] = 0; + printf("ret: '%s'\n", retbuf); + return 0; +}
\ No newline at end of file |