summaryrefslogtreecommitdiffstats
path: root/mod_add.c
diff options
context:
space:
mode:
Diffstat (limited to 'mod_add.c')
-rw-r--r--mod_add.c195
1 files changed, 82 insertions, 113 deletions
diff --git a/mod_add.c b/mod_add.c
index cfabc50..c259605 100644
--- a/mod_add.c
+++ b/mod_add.c
@@ -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);