be a kernel hacker 里面的源码|也就是之前翻译的那篇文章
2015-10-18 14:28
656 查看
#include <linux/init.h> /* __init and __exit macroses */ #include <linux/kernel.h> /* KERN_INFO macros */ #include <linux/module.h> /* required for all kernel modules */ #include <linux/moduleparam.h> /* module_param() and MODULE_PARM_DESC() */ #include <linux/fs.h> /* struct file_operations, struct file */ #include <linux/miscdevice.h> /* struct miscdevice and misc_[de]register() */ #include <linux/mutex.h> /* mutexes */ #include <linux/string.h> /* memchr() function */ #include <linux/slab.h> /* kzalloc() function */ #include <linux/sched.h> /* wait queues */ #include <linux/uaccess.h> /* copy_{to,from}_user() */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Valentine Sinitsyn <valentine.sinitsyn@gmail.com>"); MODULE_DESCRIPTION("In-kernel phrase reverser"); static unsigned long buffer_size = 8192; module_param(buffer_size, ulong, (S_IRUSR | S_IRGRP | S_IROTH)); MODULE_PARM_DESC(buffer_size, "Internal buffer size"); struct buffer { wait_queue_head_t read_queue; struct mutex lock; char *data, *end; char *read_ptr; unsigned long size; }; static struct buffer *buffer_alloc(unsigned long size) { struct buffer *buf = NULL; buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (unlikely(!buf)) goto out; buf->data = kzalloc(size, GFP_KERNEL); if (unlikely(!buf->data)) goto out_free; init_waitqueue_head(&buf->read_queue); mutex_init(&buf->lock); /* It's unused for now, but may appear useful later */ buf->size = size; out: return buf; out_free: kfree(buf); return NULL; } static void buffer_free(struct buffer *buffer) { kfree(buffer->data); kfree(buffer); } static inline char *reverse_word(char *start, char *end) { char *orig_start = start, tmp; for (; start < end; start++, end--) { tmp = *start; *start = *end; *end = tmp; } return orig_start; } static char *reverse_phrase(char *start, char *end) { char *word_start = start, *word_end = NULL; while ((word_end = memchr(word_start, ' ', end - word_start)) != NULL) { reverse_word(word_start, word_end - 1); word_start = word_end + 1; } reverse_word(word_start, end); return reverse_word(start, end); } static int reverse_open(struct inode *inode, struct file *file) { struct buffer *buf; int err = 0; /* * Real code can use inode to get pointer to the private * device state. */ buf = buffer_alloc(buffer_size); if (unlikely(!buf)) { err = -ENOMEM; goto out; } file->private_data = buf; out: return err; } static ssize_t reverse_read(struct file *file, char __user * out, size_t size, loff_t * off) { struct buffer *buf = file->private_data; ssize_t result; if (mutex_lock_interruptible(&buf->lock)) { result = -ERESTARTSYS; goto out; } while (buf->read_ptr == buf->end) { mutex_unlock(&buf->lock); if (file->f_flags & O_NONBLOCK) { result = -EAGAIN; goto out; } if (wait_event_interruptible (buf->read_queue, buf->read_ptr != buf->end)) { result = -ERESTARTSYS; goto out; } if (mutex_lock_interruptible(&buf->lock)) { result = -ERESTARTSYS; goto out; } } size = min(size, (size_t) (buf->end - buf->read_ptr)); if (copy_to_user(out, buf->read_ptr, size)) { result = -EFAULT; goto out_unlock; } buf->read_ptr += size; result = size; out_unlock: mutex_unlock(&buf->lock); out: return result; } static ssize_t reverse_write(struct file *file, const char __user * in, size_t size, loff_t * off) { struct buffer *buf = file->private_data; ssize_t result; if (size > buffer_size) { result = -EFBIG; goto out; } if (mutex_lock_interruptible(&buf->lock)) { result = -ERESTARTSYS; goto out; } if (copy_from_user(buf->data, in, size)) { result = -EFAULT; goto out_unlock; } buf->end = buf->data + size; buf->read_ptr = buf->data; if (buf->end > buf->data) reverse_phrase(buf->data, buf->end - 1); wake_up_interruptible(&buf->read_queue); result = size; out_unlock: mutex_unlock(&buf->lock); out: return result; } static int reverse_close(struct inode *inode, struct file *file) { struct buffer *buf = file->private_data; buffer_free(buf); return 0; } static struct file_operations reverse_fops = { .owner = THIS_MODULE, .open = reverse_open, .read = reverse_read, .write = reverse_write, .release = reverse_close, .llseek = noop_llseek }; static struct miscdevice reverse_misc_device = { .minor = MISC_DYNAMIC_MINOR, .name = "reverse", .fops = &reverse_fops }; static int __init reverse_init(void) { if (!buffer_size) return -1; misc_register(&reverse_misc_device); printk(KERN_INFO "reverse device has been registered, buffer size is %lu bytes\n", buffer_size); return 0; } static void __exit reverse_exit(void) { misc_deregister(&reverse_misc_device); printk(KERN_INFO "reverse device has been unregistered\n"); } module_init(reverse_init); module_exit(reverse_exit);
makefile
obj-m += reverse.o CFLAGS_reverse.o += -DDEBUG all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
相关文章推荐
- Linux socket 初步
- linux lsof详解
- linux 文件权限
- Linux 执行数学运算
- 10 篇对初学者和专家都有用的 Linux 命令教程
- Linux 与 Windows 对UNICODE 的处理方式
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- 解決Linux下Android开发真机调试设备不被识别问题
- 运维入门
- 运维提升
- Linux 自检和 SystemTap
- Ubuntu Linux使用体验
- c语言实现hashmap(转载)
- Linux 信号signal处理机制
- linux下mysql添加用户
- Scientific Linux 5.5 图形安装教程
- 基于 Linux 集群环境上 GPFS 的问题诊断
- 谁是桌面王者?Win PK Linux三大镇山之宝
- vivi下重新调整分区