diff --git a/README.md b/README.md index 7fc847f..61c7813 100644 --- a/README.md +++ b/README.md @@ -319,6 +319,7 @@ But TODO I don't think you can see where you are in the kernel source code and l 1. [panic](kernel_module/panic.c) 1. [params](kernel_module/params.c) 1. [fops](kernel_module/fops.c) + 1. [ioctl](ioctl.c) 1. [poll](poll.c) 1. Asynchronous 1. [workqueue](kernel_module/workqueue.c) diff --git a/kernel_module/fops.c b/kernel_module/fops.c index d5ef0c7..e5e457a 100644 --- a/kernel_module/fops.c +++ b/kernel_module/fops.c @@ -28,10 +28,9 @@ Here we use debugfs. MODULE_LICENSE("GPL"); static struct dentry *dir; - static char data[] = {'a', 'b', 'c', 'd'}; -static int fop_open(struct inode *inode, struct file *file) +static int open(struct inode *inode, struct file *filp) { printk(KERN_INFO "open\n"); return 0; @@ -42,7 +41,7 @@ static int fop_open(struct inode *inode, struct file *file) * Then when userland reads the same file descriptor again, * we start from that point instead. * */ -static ssize_t fop_read(struct file *file, char __user *buf, size_t len, loff_t *off) +static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off) { ssize_t ret; printk(KERN_INFO "read\n"); @@ -67,7 +66,7 @@ static ssize_t fop_read(struct file *file, char __user *buf, size_t len, loff_t * we must return ENOSPC if the user tries to write more * than the size of our buffer. Otherwise, Bash > just * keeps trying to write to it infinitely. */ -static ssize_t fop_write(struct file *file, const char __user *buf, size_t len, loff_t *off) +static ssize_t write(struct file *filp, const char __user *buf, size_t len, loff_t *off) { ssize_t ret; printk(KERN_INFO "write\n"); @@ -96,13 +95,13 @@ static ssize_t fop_write(struct file *file, const char __user *buf, size_t len, Called on the last close: http://stackoverflow.com/questions/11393674/why-is-the-close-function-is-called-release-in-struct-file-operations-in-the-l */ -static int fop_release (struct inode *inode, struct file *file) +static int release (struct inode *inode, struct file *filp) { printk(KERN_INFO "release\n"); return 0; } -static loff_t fop_llseek(struct file *filp, loff_t off, int whence) +static loff_t llseek(struct file *filp, loff_t off, int whence) { loff_t newpos; printk(KERN_INFO "llseek\n"); @@ -129,26 +128,17 @@ static loff_t fop_llseek(struct file *filp, loff_t off, int whence) } static const struct file_operations fops = { - .llseek = fop_llseek, - .open = fop_open, - .read = fop_read, - .release = fop_release, - .write = fop_write, + .llseek = llseek, + .open = open, + .read = read, + .release = release, + .write = write, }; static int myinit(void) { - struct dentry *file; dir = debugfs_create_dir("lkmc_fops", 0); - if (!dir) { - printk(KERN_ALERT "debugfs_create_dir failed"); - return -1; - } - file = debugfs_create_file("f", 0666, dir, NULL, &fops); - if (!file) { - printk(KERN_ALERT "debugfs_create_file failed"); - return -1; - } + debugfs_create_file("f", 0666, dir, NULL, &fops); return 0; } diff --git a/kernel_module/ioctl.c b/kernel_module/ioctl.c new file mode 100644 index 0000000..98b2089 --- /dev/null +++ b/kernel_module/ioctl.c @@ -0,0 +1,36 @@ +/* +Give integer and a pointer to the kernel, and get one positive integer out. +*/ + +#include +#include +#include /* printk */ + +MODULE_LICENSE("GPL"); + +static struct dentry *dir; + +static long unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + pr_info("cmd = %u\n", cmd); + return cmd + 1; +} + +static const struct file_operations fops = { + .unlocked_ioctl = unlocked_ioctl +}; + +static int myinit(void) +{ + dir = debugfs_create_dir("lkmc_ioctl", 0); + debugfs_create_file("f", 0666, dir, NULL, &fops); + return 0; +} + +static void myexit(void) +{ + debugfs_remove_recursive(dir); +} + +module_init(myinit) +module_exit(myexit) diff --git a/kernel_module/test/ioctl.c b/kernel_module/test/ioctl.c new file mode 100644 index 0000000..b90683f --- /dev/null +++ b/kernel_module/test/ioctl.c @@ -0,0 +1,33 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + int fd, ret; + + if (argc < 4) { + puts("Usage: ./prog "); + return EXIT_FAILURE; + } + fd = open(argv[1], O_RDONLY); + if (fd == -1) { + perror("open"); + return EXIT_FAILURE; + } + ret = ioctl(fd, strtoul(argv[2], NULL, 10), argv[3]); + if (ret == -1) { + perror("ioctl"); + return EXIT_FAILURE; + } + printf("ret = %d\n", ret); + printf("errno = %d\n", errno); + close(fd); + return EXIT_SUCCESS; +} diff --git a/rootfs_overlay/ioctl.sh b/rootfs_overlay/ioctl.sh new file mode 100755 index 0000000..3e7c2be --- /dev/null +++ b/rootfs_overlay/ioctl.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -e +insmod /ioctl.ko +cd /sys/kernel/debug/lkmc_ioctl/ +/ioctl.out f 2 1 +#/ioctl.out f 1 0 +rmmod ioctl