Linux 内核模块:是否可以在我的模块的另一个打开函数中使用一个打开函数?

Linux kernel module : Is it possible to use an open function inside another open function for my module?

也许这个问题没有意义,但我想知道是否有 "recommended practice" 关于如何在创建模块的打开函数中打开设备的文件描述符。

事实上,我开发了一个简单的 Linux 内核模块,它的基本功能是:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>  
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>

MODULE_LICENSE("GPL");      
MODULE_AUTHOR("Gaston");  
MODULE_DESCRIPTION("A simple Linux char driver"); 
MODULE_VERSION("0.1"); 


ssize_t exer_open(struct inode *pinode, struct file *pfile) {

    printk(KERN_INFO "Device has been opened\n");

    return 0;
}



ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {

    return 0;
}



ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {

    return 0;

}   




ssize_t exer_close(struct inode *pinode, struct file *pfile) {

    printk(KERN_INFO "Device successfully closed\n");
    return 0;
}


struct file_operations exer_file_operations = { 
    .owner = THIS_MODULE,
    .open = exer_open,
    .read = exer_read,
    .write = exer_write,
    .release = exer_close,
};


int exer_simple_module_init(void) {

    printk(KERN_INFO "Initializing the LKM\n");
    register_chrdev(240, "Simple Char Drv", &exer_file_operations);
    return 0;
}


void exer_simple_module_exit(void) {

    unregister_chrdev(240, "Simple Char Drv");
}


module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);

我编译了一下,没有出错。

现在我想打开我的设备 ( BUTTON ) 的文件描述符,以便稍后从用户 space 程序中对其进行操作,因此我通过添加 BUTTON 设备路径和另一个打开函数进行了一些修改,例如这 :

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>  
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/input.h>

MODULE_LICENSE("GPL");      
MODULE_AUTHOR("Gaston");  
MODULE_DESCRIPTION("A simple Linux char driver"); 
MODULE_VERSION("0.1"); 

#define BTN_FILE_PATH "/dev/input/event0"

int file;
char *str = BTN_FILE_PATH;


ssize_t exer_open(struct inode *pinode, struct file *pfile) {

    printk(KERN_INFO "Device has been opened\n");

    if((file = open(str, O_RDONLY)) < 0) {
        printk("simplekey: File can not open");
        return(-1);
    }
    return 0;
}



ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {

    return 0;
}


ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {

    return 0;

}   


ssize_t exer_close(struct inode *pinode, struct file *pfile) {

    printk(KERN_INFO "Device successfully closed\n");
    return 0;
}


struct file_operations exer_file_operations = { 
    .owner = THIS_MODULE,
    .open = exer_open,
    .read = exer_read,
    .write = exer_write,
    .release = exer_close,
};


int exer_simple_module_init(void) {

    printk(KERN_INFO "Initializing the LKM\n");
    register_chrdev(240, "Simple Char Drv", &exer_file_operations);
    return 0;
}


void exer_simple_module_exit(void) {

    unregister_chrdev(240, "Simple Char Drv");
}


module_init(exer_simple_module_init);
module_exit(exer_simple_module_exit);

但问题是,当我现在尝试编译模块时会打印错误:

/home/gaston/ledshared/exer_simple_char_drv.c: In function ‘exer_open’: /home/gaston/ledshared/exer_simple_char_drv.c:32:13: error: implicit declaration of function ‘open’ [-Werror=implicit-function-declaration]

if((file = open(str,O_RDONLY)) < 0) {

请问我该如何解决这个问题?

open() 是用户-space 函数。等效的 kernel-space 函数是 filp_open(),但它 returns 是 struct file * 而不是 int 文件描述符。返回的 struct file * 可能是错误代码而不是有效指针。使用 IS_ERR(ptr) 宏进行检查,并使用 PTR_ERR(ptr) 宏提取错误代码(这将是一个否定的 errno 值)。

不鼓励使用 filp_open 函数,但这里对您的代码进行了一些修改以使用此函数:

int exer_open(struct inode *pinode, struct file *pfile) {
    struct file *f;

    f = filp_open(str, O_RDONLY);
    if (IS_ERR(f)) {
        printk("simplekey: File can not open");
        return(PTR_ERR(f));
    }
    pfile->private_data = f;

    printk(KERN_INFO "Device has been opened\n");
    return 0;
}

关闭函数应如下所示:

int exer_close(struct inode *pinode, struct file *pfile) {
    struct file *f = pfile->private_data;
    int rc;

    rc = filp_close(f, NULL);
    if (rc == 0) {
        printk(KERN_INFO "Device successfully closed\n");
    }
    return rc;
}

没有合法的方法可以让模块从 struct file * 直接读取到 user-space 缓冲区或从 user-space 缓冲区写入 struct file *,所以需要在内核内存中有一个中间缓冲区,这样就可以使用kernel_read()kernel_write()来读取或写入文件:

ssize_t exer_read(struct file *pfile, char __user *buffer, size_t length, loff_t *offset) {
    struct file *f = pfile->private_data;
    enum { MAX_BUF_SIZE = 4096 };
    size_t buf_size = 0;
    char *buf = NULL;
    ssize_t total = 0;
    ssize_t rc = 0;

    /* Allocate temporary buffer. */
    if (length) {
        buf_size = min_t(size_t, MAX_BUF_SIZE, length);
        buf = kmalloc(buf_size, GFP_KERNEL);
        if (buf == NULL) {
            return -ENOMEM;
        }
    }

    /* Read file to buffer in chunks. */
    do {
        size_t amount = min_t(size_t, length, buf_size);

        rc = kernel_read(f, buf, amount, offset);
        if (rc > 0) {
            /* Have read some data from file. */
            if (copy_to_user(buffer, buf, rc) != 0) {
                /* Bad user memory! */
                rc = -EFAULT;
            } else {
                /* Update totals. */
                total += rc;
                buffer += rc;
                *offset += rc;
                length -= rc;
                if (rc < amount) {
                    /* Didn't read the full amount, so terminate early. */
                    rc = 0;
                }
            }
        }
    } while (rc > 0 && length > 0);

    /* Free temporary buffer. */
    kfree(buf);

    if (total > 0) {
        return total;
    }
    return rc;
}


ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
    struct file *f = pfile->private_data;
    enum { MAX_BUF_SIZE = 4096 };
    size_t buf_size = 0;
    char *buf = NULL;
    ssize_t total = 0;
    ssize_t rc = 0;

    /* Allocate temporary buffer. */
    if (length) {
        buf_size = min_t(size_t, MAX_BUF_SIZE, length);
        buf = kmalloc(buf_size, GFP_KERNEL);
        if (buf == NULL) {
            return -ENOMEM;
        }
    }

    /* Write file from buffer in chunks. */
    do {
        size_t amount = min_t(size_t, length, buf_size);

        if (copy_from_user(buf, buffer, amount) != 0) {
            /* Bad user memory! */
            rc = -EFAULT;
        } else {
            rc = kernel_write(f, buf, amount, offset);
            if (rc > 0) {
                /* Have written some data to file. */
                /* Update totals. */
                total += rc;
                buffer += rc;
                *offset += rc;
                length -= rc;
                if (rc < amount) {
                    /* Didn't write the full amount, so terminate early. */
                    rc = 0;
                }
            }
        }
    } while (rc > 0 && length > 0);

    /* Free temporary buffer. */
    kfree(buf);

    if (total > 0) {
        return total;
    }
    return rc;
}