MODULE_VERSION("1.0.0");
#define BUFFER_SIZE 4096
-
-/* Message buffer we send to upstream */
-static char *hello_message;
-static char *goodbye_message;
+#define DEVICE_NUMBER 2
struct message {
char *text;
size_t len;
};
+/* Message buffer we send to upstream */
+static struct message *hello_message[DEVICE_NUMBER];
+
static int helloc_open(struct inode *ino, struct file *filp)
{
struct message *msg;
printk(KERN_INFO "Opened file with minor %d\n", iminor(ino));
- msg = kmalloc(sizeof(struct message), GFP_KERNEL);
- if (!msg)
- return -ENOMEM;
- if (iminor(ino) == 0) {
- msg->text = hello_message;
- msg->len = BUFFER_SIZE;
- } else {
- msg->text = goodbye_message;
- msg->len = BUFFER_SIZE;
- }
+ if (iminor(ino) >= DEVICE_NUMBER)
+ return -ENODEV;
+ msg = hello_message[iminor(ino)];
filp->private_data = msg;
+ if (filp->f_flags & O_TRUNC) {
+ memset(msg->text, 0, msg->len);
+ msg->len = 0;
+ printk(KERN_INFO "File opened with truncate flags\n");
+ }
+ if (filp->f_flags & O_APPEND) {
+ filp->f_pos = msg->len;
+ }
return 0;
}
static int helloc_release(struct inode *ino, struct file *filp)
{
- kfree(filp->private_data);
return 0;
}
int r;
struct message *msg = filp->private_data;
/* do not read pass through the size of the message */
- if (*pos >= msg->len)
+ if (*pos >= BUFFER_SIZE)
/* return end of file */
return 0;
/* if len is bigger than the rest of the message, clamp it */
- if (len > msg->len - *pos)
- len = msg->len - *pos;
+ if (len > BUFFER_SIZE - *pos)
+ len = BUFFER_SIZE - *pos;
+
/* copy message to user space and return error if it fails */
r = copy_from_user(msg->text + *pos, buf, len);
- if (r)
+ if (r) {
+ if (*pos + len > msg->len)
+ memset(msg->text + msg->len, 0, *pos + len - msg->len);
return -EFAULT;
+ }
/* update the file position */
*pos += len;
+ if (msg->len < *pos) {
+ printk(KERN_DEBUG "Updating size from %d to %lld\n", msg->len, *pos);
+ msg->len = *pos;
+ }
+
return len;
}
static dev_t dev;
static struct cdev *cdev;
+static void helloc_free(void)
+{
+ int i;
+ for (i = 0; i < DEVICE_NUMBER; i++) {
+ if (hello_message[i])
+ kfree(hello_message[i]->text);
+ kfree(hello_message[i]);
+ }
+}
+
+static int __init helloc_alloc(void)
+{
+ int i;
+ for (i = 0; i < DEVICE_NUMBER; i++) {
+ hello_message[i] = kzalloc(sizeof(struct message), GFP_KERNEL);
+ if (!hello_message[i])
+ goto out;
+ hello_message[i]->text = kzalloc(BUFFER_SIZE, GFP_KERNEL);
+ if (!hello_message[i]->text)
+ goto out;
+ }
+ return 0;
+out:
+ for (; i >= 0; i--) {
+ if (hello_message[i])
+ kfree(hello_message[i]->text);
+ kfree(hello_message[i]);
+ }
+ return -ENOMEM;
+}
+
static int __init helloc_init(void)
{
- int r = -ENOMEM;
+ int r;
+ r = helloc_alloc();
+ if (r)
+ goto out_alloc2;
/* allocate any major number with only one minor */
- hello_message = kzalloc(BUFFER_SIZE, GFP_KERNEL);
- if (!hello_message)
- goto out_hello;
- goodbye_message = kzalloc(BUFFER_SIZE, GFP_KERNEL);
- if (!goodbye_message)
- goto out_goodbye;
- r = alloc_chrdev_region(&dev, 0, 2, "helloc");
+ r = alloc_chrdev_region(&dev, 0, DEVICE_NUMBER, "helloc");
if (r)
goto out_region;
r = -ENOMEM;
cdev->owner = THIS_MODULE;
cdev->ops = &helloc_fops;
/* register the chardev to the system */
- r = cdev_add(cdev, dev, 2);
+ r = cdev_add(cdev, dev, DEVICE_NUMBER);
if (r)
goto out_add;
return 0;
kfree(cdev);
out_alloc:
/* release the device number allocated */
- unregister_chrdev_region(dev, 2);
+ unregister_chrdev_region(dev, DEVICE_NUMBER);
out_region:
- kfree(goodbye_message);
-out_goodbye:
- kfree(hello_message);
-out_hello:
+out_alloc2:
return r;
}
/* remove the chardev from the system */
cdev_del(cdev);
/* release the device number allocated */
- unregister_chrdev_region(dev, 2);
- kfree(goodbye_message);
- kfree(hello_message);
+ unregister_chrdev_region(dev, DEVICE_NUMBER);
+ helloc_free();
}
module_init(helloc_init);