2015-05-04 27 views
10

như tôi biết, để thông báo cho không gian người dùng từ không gian hạt nhân, một cách là sử dụng cuộc thăm dò ý kiến. Điều đó có nghĩa là trình điều khiển nhân nên cung cấp phương thức thăm dò ý kiến ​​trước. Dưới đây là mã được tìm thấy từ internet, và nó thực sự hoạt động!Làm thế nào để thêm chức năng thăm dò vào mã mô-đun hạt nhân?

#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/proc_fs.h> 
#include <linux/string.h> 
#include <linux/vmalloc.h> 
#include <asm/uaccess.h> 

MODULE_LICENSE("GPL"); 
MODULE_DESCRIPTION("Fortune Cookie Kernel Module"); 
MODULE_AUTHOR("M. Tim Jones"); 

#define MAX_COOKIE_LENGTH  PAGE_SIZE 

static struct proc_dir_entry *proc_entry; 
static char *cookie_buf; // Space for fortune strings 
static int write_index; // Index to write next fortune 
static int read_index; // Index to read next fortune 

ssize_t fortune_write(struct file *filp, const char __user *buff, 
         unsigned long len, void *data) 
// Refer to: ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 
{ 
    int space_available = (MAX_COOKIE_LENGTH-write_index); 

    if (len > space_available) { 
    printk(KERN_INFO "fortune: cookie buffer is full!\n"); 
    return -ENOSPC; 
    } 

    if (copy_from_user(&cookie_buf[write_index], buff, len)) { 
    return -EFAULT; 
    } 

    write_index += len; 
    cookie_buf[write_index-1] = 0; 

    return len; 
} 

ssize_t fortune_read(struct file *file, char *buf, size_t count, loff_t *f_pos){ 
// Refer to: ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 
    int len; 

    //there's no fortune or a fortune has already been read 
    //the *f_pos > 0 hack is needed because `cat /proc/fortune` would otherwise 
    //display every thing in the cookie_buf 
    if(write_index == 0 || *f_pos > 0){ 
     return 0; 
    } 

    // cicle through fortunes 
    if(read_index >= write_index){ 
     read_index = 0; 
    } 

    len = sprintf(buf, "%s\n", &cookie_buf[read_index]); 

    read_index += len; 
    *f_pos += len; 

    return len; 
} 

static const struct file_operations proc_test_fops = { 
    .owner  = THIS_MODULE, 
// .open  = led_proc_open, 
    .read  = fortune_read, 
// .llseek  = seq_lseek, 
// .release = single_release, 
    .write  = fortune_write, 
// unsigned int (*poll) (struct file *, struct poll_table_struct *); 
// int (*fasync) (int, struct file *, int); 
}; 

int __init init_fortune_module(void) 
{ 
    int ret = 0; 
    cookie_buf = (char *)vmalloc(MAX_COOKIE_LENGTH); 
    if (!cookie_buf) { 
     ret = -ENOMEM; 
    } else { 
     memset(cookie_buf, 0, MAX_COOKIE_LENGTH); 
//  proc_entry = create_proc_entry("fortune", 0644, NULL); 
     proc_entry = proc_create("fortune", 0644, NULL, &proc_test_fops); 

     if (proc_entry == NULL) { 
      ret = -ENOMEM; 
      vfree(cookie_buf); 
      printk(KERN_INFO "fortune: Couldn't create proc entry\n"); 
     } else { 
      write_index = 0; 
      read_index = 0; 
      printk(KERN_INFO "fortune: Module loaded.\n"); 
     } 
    } 

    return ret; 
} 

void __exit exit_fortune_module(void) 
{ 
// remove_proc_entry("fortune", &proc_entry); 
    proc_remove(proc_entry); 
    vfree(cookie_buf); 
    printk(KERN_INFO "fortune: Module unloaded.\n"); 
} 

module_init(init_fortune_module); 
module_exit(exit_fortune_module); 

tôi có thể làm như thế này để làm cho nó hoạt:

echo "hello" > /proc/fortune 

Và sau đó

cat /proc/fortune 

để xem kết quả.

Nhưng cách thêm phương thức thăm dò ý kiến ​​vào nó? Tôi đã thử một số lần, nhưng vẫn thất bại. Có ai giúp được không? Cảm ơn!

Trả lời

9

Bạn có thể tìm thấy một số ví dụ hay về hạt nhân. Hãy nhìn vào các tập tiếp theo:

Để thêm poll() chức năng để mã của bạn làm theo các bước tiếp theo.

  1. tiêu đề Bao gồm cần thiết:

    #include <linux/wait.h> 
    #include <linux/poll.h> 
    
  2. Declare waitqueue biến:

    static DECLARE_WAIT_QUEUE_HEAD(fortune_wait); 
    
  3. Thêm fortune_poll() chức năng và thêm nó (như .poll gọi lại) để cơ cấu hoạt động tập tin của bạn:

    static unsigned int fortune_poll(struct file *file, poll_table *wait) 
    { 
        poll_wait(file, &fortune_wait, wait); 
        if (new-data-is-ready) 
         return POLLIN | POLLRDNORM; 
        return 0; 
    } 
    
    static const struct file_operations proc_test_fops = { 
        .... 
        .poll = fortune_poll, 
    }; 
    

    Lưu ý rằng bạn nên trả lại POLLIN | POLLRDNORM nếu bạn có một số dữ liệu mới để đọc và 0 trong trường hợp không có dữ liệu mới để đọc (poll() hết giờ cuộc gọi). Xem man 2 poll để biết chi tiết.

  4. Thông báo waitqueue của bạn một khi bạn có dữ liệu mới:

    wake_up_interruptible(&fortune_wait); 
    

Đó là những thứ cơ bản về thực hiện poll() hoạt động. Tùy thuộc vào công việc của bạn, bạn có thể cần sử dụng một số waitqueue API trong chức năng .read của bạn (như wait_event_interruptible()).


Xem thêm câu hỏi có liên quan: Implementing poll in a Linux kernel module.

+0

Câu hỏi này rất hữu ích cho tôi, nhưng tôi vẫn còn lúng túng. Tôi có một câu hỏi liên quan ở đây: https://stackoverflow.com/questions/34027366/implementing-poll-in-a-linux-kernel-module – zmb

3

Minimal dụ Runnable

Cách sử dụng:

insmod /poll.ko 
mount -t debugfs none /sys/kernel/debug 
/poll.out /sys/kernel/debug/lkmc_poll/f 

Kết quả: mỗi một giây, sau đây được in vào màn hình:

loop 
POLLIN n=10 buf=<jiffies> 

GitHub thượng nguồn với qemu + Buildroot soạn sẵn: poll.ko, poll.out

Trong ví dụ đơn giản này, chúng tôi tạo các sự kiện thăm dò từ một chuỗi riêng biệt. Trong cuộc sống thực, các sự kiện thăm dò ý kiến ​​có khả năng sẽ được kích hoạt bởi các ngắt, khi phần cứng đã hoàn thành một số công việc, và dữ liệu mới đã có sẵn cho userland để đọc.

poll.ko:

#include <asm/uaccess.h> /* copy_from_user, copy_to_user */ 
#include <linux/debugfs.h> 
#include <linux/delay.h> /* usleep_range */ 
#include <linux/errno.h> /* EFAULT */ 
#include <linux/fs.h> 
#include <linux/jiffies.h> 
#include <linux/kernel.h> /* min */ 
#include <linux/kthread.h> 
#include <linux/module.h> 
#include <linux/poll.h> 
#include <linux/printk.h> /* printk */ 
#include <linux/wait.h> /* wait_queue_head_t, wait_event_interruptible, wake_up_interruptible */ 
#include <uapi/linux/stat.h> /* S_IRUSR */ 

MODULE_LICENSE("GPL"); 

static char readbuf[1024]; 
static size_t readbuflen; 
static struct dentry *dir; 
static struct task_struct *kthread; 
static wait_queue_head_t waitqueue; 

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off) 
{ 
    ssize_t ret; 
    if (copy_to_user(buf, readbuf, readbuflen)) { 
     ret = -EFAULT; 
    } else { 
     ret = readbuflen; 
    } 
    /* This is normal pipe behaviour: data gets drained once a reader reads from it. */ 
    /* https://stackoverflow.com/questions/1634580/named-pipes-fifos-on-unix-with-multiple-readers */ 
    readbuflen = 0; 
    return ret; 
} 

/* 
If you return 0 here, then the kernel will sleep until an event happens in the queue. 

This gets called again every time an event happens in the wait queue. 
*/ 
unsigned int poll(struct file *filp, struct poll_table_struct *wait) 
{ 
    poll_wait(filp, &waitqueue, wait); 
    if (readbuflen) 
     return POLLIN; 
    else 
     return 0; 
} 

static int kthread_func(void *data) 
{ 
    while (!kthread_should_stop()) { 
     readbuflen = snprintf(readbuf, sizeof(readbuf), "%llu", (unsigned long long)jiffies); 
     usleep_range(1000000, 1000001); 
     wake_up(&waitqueue); 
    } 
    return 0; 
} 

static const struct file_operations fops = { 
    .owner = THIS_MODULE, 
    .read = read, 
    .poll = poll 
}; 

static int myinit(void) 
{ 
    dir = debugfs_create_dir("lkmc_poll", 0); 
    debugfs_create_file("f", S_IRUSR | S_IWUSR, dir, NULL, &fops); 
    init_waitqueue_head(&waitqueue); 
    kthread = kthread_create(kthread_func, NULL, "mykthread"); 
    wake_up_process(kthread); 
    return 0; 
} 

static void myexit(void) 
{ 
    kthread_stop(kthread); 
    debugfs_remove_recursive(dir); 
} 

module_init(myinit) 
module_exit(myexit) 

poll.out Userland:

#define _XOPEN_SOURCE 700 
#include <fcntl.h> /* creat, O_CREAT */ 
#include <poll.h> /* poll */ 
#include <stdio.h> /* printf, puts, snprintf */ 
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */ 
#include <unistd.h> /* read */ 

int main(int argc, char **argv) { 
    char buf[1024], path[1024]; 
    int fd, i, n; 
    short revents; 
    struct pollfd pfd; 

    fd = open(argv[1], O_RDONLY | O_NONBLOCK); 
    if (fd == -1) { 
     perror("open"); 
     exit(EXIT_FAILURE); 
    } 
    pfd.fd = fd; 
    pfd.events = POLLIN; 
    while (1) { 
     puts("loop"); 
     i = poll(&pfd, 1, -1); 
     if (i == -1) { 
      perror("poll"); 
      exit(EXIT_FAILURE); 
     } 
     revents = pfd.revents; 
     if (revents & POLLIN) { 
      n = read(pfd.fd, buf, sizeof(buf)); 
      printf("POLLIN n=%d buf=%.*s\n", n, n, buf); 
     } 
    } 
} 
Các vấn đề liên quan