diff options
author | syn <isaqtm@gmail.com> | 2020-01-30 20:31:23 +0300 |
---|---|---|
committer | syn <isaqtm@gmail.com> | 2020-01-30 20:31:23 +0300 |
commit | 6662cea6b2572cd70a60aadfb28312e2bbef6ecc (patch) | |
tree | 1a4a527af10c11ba47224efd14cf866158ca774e /mod_add.c | |
download | sad-6662cea6b2572cd70a60aadfb28312e2bbef6ecc.tar.gz |
Faulty first implementation of echo module
Diffstat (limited to 'mod_add.c')
-rw-r--r-- | mod_add.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/mod_add.c b/mod_add.c new file mode 100644 index 0000000..cfabc50 --- /dev/null +++ b/mod_add.c @@ -0,0 +1,162 @@ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/uaccess.h> + +MODULE_LICENSE("GPL"); + +#include "assoc_buf.h" + +#define DEV_NAME "mod_add" +#define OP_INVALID "Operation invalid\n" + +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 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; + + if (!buffers) { + buffers = kmalloc(sizeof(struct buf_list), GFP_KERNEL); + if (!buffers) + return -ENOMEM; + buffers->buf = buf; + buffers->next = NULL; + return 0; + } + + 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; +} + +void free_buf_list(void) { + struct buf_list *iter = buffers, *next; + + while (iter) { + next = iter->next; + asbuf_free(iter->buf); + kfree(iter->buf); + kfree(iter); + iter = next; + } +} + +ssize_t rm_by_inode(unsigned long ino) { + struct buf_list *iter = buffers; + struct buf_list *save_prev; + + if (!buffers) + return 0; + + 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; +} + +static struct file_operations file_ops = { + .read = device_read, + .write = device_write, + .open = device_open, + .release = device_release +}; + + +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); +} + +static ssize_t device_write(struct file *flip, const char *buffer, size_t len, loff_t *offset) { + if (len == 0) + return 0; + + return asbuf_from_user(find_by_inode(flip->f_inode->i_ino), buffer, len, offset); +} + +static int device_open(struct inode *inode, struct file *file) { + struct asbuf *newbuf; + + if (device_open_count) + return -EBUSY; + + newbuf = kzalloc(sizeof(*newbuf), GFP_KERNEL); + if (!newbuf) + return -ENOMEM; + + printk(KERN_INFO "opened for inode %lu", inode->i_ino); + newbuf->ino = inode->i_ino; + add_buf (newbuf); + 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); + device_open_count--; + module_put(THIS_MODULE); + return 0; +} + +static int __init mod_add_init(void) { + buffers = kzalloc(sizeof(*buffers), GFP_KERNEL); + + 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; + } else { + printk(KERN_INFO "mod_add loaded. dev maj = %d\n", major_num); + return 0; + } +} +static void __exit mod_add_exit(void) { + unregister_chrdev(major_num, DEV_NAME); + free_buf_list(); + printk(KERN_INFO "okay, bye\n"); +} + +module_init(mod_add_init); +module_exit(mod_add_exit); |