2012年6月7日 星期四

Hello, World! 使用 /dev/hello_world

多了個 write =.=
Question: How to check memory leak 冏
hello.c
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <asm/uaccess.h>
//#include <linux/uaccess.h>
#include <linux/slab.h>

static char *buf_dev=NULL;
static size_t buf_len;
static DEFINE_MUTEX(buf_mutex);

static int hello_open(struct inode *inode, struct file *file)
{
    return 0;
}

static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
    ssize_t retval = -ENOMEM;
    mutex_lock(&buf_mutex);
 
    if (buf_dev)
 kfree(buf_dev);

    buf_dev = kmalloc(count, GFP_KERNEL);
    memset(buf_dev, '\0', count);
 
    if (!buf_dev)
 goto out;
 
    if (copy_from_user(buf_dev, buf, count))
    {
 kfree(buf_dev);
 retval = -EFAULT;
 goto out;
    }

    printk(KERN_INFO "count=%zu\n", count);

    *ppos = count;
    retval = count;
    buf_len = count;

out:
    mutex_unlock(&buf_mutex);
    return retval;
}

static ssize_t hello_read(struct file * file, char * buf, size_t count, loff_t *ppos)
{
    ssize_t retval = 0;
    char *start;

    mutex_lock(&buf_mutex);

    if (!buf_dev)
    {
        retval = -EINVAL; /* Or whatever you want to do here... */
        goto out;
    }

    if (*ppos >= buf_len)
        goto out; /* EOF */

    start = buf_dev + *ppos;
    retval = buf_len - *ppos;

    if (retval > count)
        retval = count;

    if (copy_to_user(buf, start, retval))
    {
        retval = -EFAULT;
        goto out;
    }

    *ppos += retval;

out:
    mutex_unlock(&buf_mutex);
    return retval;
}

static int hello_release(struct inode *inode, struct file *file)
{
 return 0;
}

static const struct file_operations hello_fops = {
    .owner      = THIS_MODULE,
    .open       = hello_open, 
    .read       = hello_read,
    .write      = hello_write,
    .release    = hello_release,
};
static struct miscdevice hello_dev = {
    MISC_DYNAMIC_MINOR,
    "hello",
    &hello_fops
};
static int __init hello_init(void){
    int ret;
    ret = misc_register(&hello_dev);
    if (ret)
        printk(KERN_INFO "Unable to register Hello\n");
    return ret;
}
static void __exit hello_exit(void)
{
    kfree(buf_dev);
    misc_deregister(&hello_dev);
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Hello, world! minimal module");
MODULE_VERSION("dev");
Makefile
#disable module verification failed: signature and/or required key missing - tainting kernel after insmod hello.ko
CONFIG_MODULE_SIG=n

PWD := $(shell pwd) 
KVERSION := $(shell uname -r)
KERNEL_DIR = /usr/src/linux-headers-$(KVERSION)/

MODULE_NAME = hello
obj-m := $(MODULE_NAME).o

all:
  make -C $(KERNEL_DIR) M=$(PWD) modules
clean:
  make -C $(KERNEL_DIR) M=$(PWD) clean

不要用 sudo echo 321 > /dev/hello
要用su切換到root

沒有留言:

張貼留言