【问题标题】:Linux kernel module : Is it possible to use an open function inside another open function for my module?Linux内核模块:是否可以在我的模块的另一个开放函数中使用一个开放函数?
【发布时间】:2019-10-25 14:15:55
【问题描述】:

也许这个问题没有意义,但我想知道是否有关于如何在已创建模块的打开函数内为设备打开文件描述符的“推荐做法”。

事实上,我开发了一个简单的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 ) 以便以后从用户空间程序中对其进行操作,所以我通过添加 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:在函数中 ‘exer_open’:/home/gaston/ledshared/exer_simple_char_drv.c:32:13: 错误:函数“open”的隐式声明 [-Werror=隐式函数声明]

if((file = open(str,O_RDONLY))

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

【问题讨论】:

    标签: c compiler-errors linux-device-driver kernel-module


    【解决方案1】:

    open() 是一个用户空间函数。等效的内核空间函数是filp_open(),但它返回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 *直接读取到用户空间缓冲区或从用户空间缓冲区写入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;
    }   
    

    【讨论】:

      猜你喜欢
      • 2016-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-24
      • 1970-01-01
      • 2016-01-22
      • 2019-05-02
      • 2021-04-19
      相关资源
      最近更新 更多