summaryrefslogtreecommitdiffstats
path: root/mod_add.c
diff options
context:
space:
mode:
authorsyn <isaqtm@gmail.com>2020-01-30 20:31:23 +0300
committersyn <isaqtm@gmail.com>2020-01-30 20:31:23 +0300
commit6662cea6b2572cd70a60aadfb28312e2bbef6ecc (patch)
tree1a4a527af10c11ba47224efd14cf866158ca774e /mod_add.c
downloadsad-6662cea6b2572cd70a60aadfb28312e2bbef6ecc.tar.gz
Faulty first implementation of echo module
Diffstat (limited to 'mod_add.c')
-rw-r--r--mod_add.c162
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);