首页 > 解决方案 > 跨用户的字符设备 I/O

问题描述

我正在学习 Linux,但我有我无法处理的任务。我必须创建字符设备并使跨用户读写成为可能。例如,我打开第一个终端并使用echo 'test' > /tmp/ringdevringdev我的字符设备在哪里)。我还打开第二个终端并使用cat /tmp/ringdev,我希望输出为test. 我已经阅读了一些示例片段,但所有这些都只是我已经拥有的基础知识。

问题是如何跨用户读取/写入字符设备?

#define pr_fmt(fmt) "ringdev: " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
#include <linux/sched.h>


DECLARE_WAIT_QUEUE_HEAD(head);
/*                                  
 * mutex used for access synchronization to buffer (ringdev_buf and ringdev_len)
 */ 
static struct mutex ringdev_lock;

/*          
 * buffer and number of written bytes in the buffer
 */         
static char ringdev_buf[4096];
static size_t ringdev_len;

static int ringdev_open(struct inode *inode, struct file *filp)
{             
    printk("device_open called \n");    
    return 0;
}

static ssize_t ringdev_read(struct file *filp, char __user *buf, size_t count,
        loff_t *off)
{                                           
    ssize_t ret = 0;

     printk("device_read called \n");                  
    /*
     * access to ringdev_buf i ringdev_len is protected by ringdev_lock,
     * take that lock
     */


    //wait_event_interruptible(head,ringdev_len!=0);
    mutex_lock(&ringdev_lock);

    if (*off > ringdev_len)
        count = 0;
    else if (count >= ringdev_len - *off)
        count = ringdev_len - *off;

    /*
     * for access to user memory special functions must be used,
     * to copy to user memory copy_to_user must be used.
     */
    ret = -EFAULT;
    if (copy_to_user(buf, ringdev_buf + *off, count))
        goto out_unlock;
    ret = count;
    *off += ret;

out_unlock:
    mutex_unlock(&ringdev_lock);
    ringdev_len=0;
    return ret;

}                            
static ssize_t ringdev_write(struct file *filp, const char __user *buf,
        size_t count, loff_t *off)
{                    
    ssize_t ret=0;
    ringdev_len=0;
    printk("device_write called \n");
    mutex_lock(&ringdev_lock);
    ret=-EFAULT;


    if(copy_from_user(ringdev_buf+ringdev_len ,buf, count)==0){
        ringdev_len= ringdev_len + count;
        ret=count;
        wake_up_interruptible(&head);
        goto out_unlock;
    }
    else{
      ret=-ENOSPC;
    }
    /*
     * not supported yet. Do not forget about copy_from_user().
     */

out_unlock:
    mutex_unlock(&ringdev_lock);
    return ret;

}

static int ringdev_release(struct inode *inode, struct file *filp)
{                                      
    mutex_unlock(&ringdev_lock);
    printk("device_release called \n");
    return 0;
}

static const struct file_operations ringdev_fops = {
    .owner = THIS_MODULE,
    .open = ringdev_open,
    .read = ringdev_read,
    .write = ringdev_write,
    .release = ringdev_release,
};

static struct miscdevice ringdev_miscdevice = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "ringdev",
    .fops = &ringdev_fops
};

static int __init ringdev_init(void)
{                                         
    int ret;

    mutex_init(&ringdev_lock);

    ret = misc_register(&ringdev_miscdevice);
    if (ret < 0) {
        pr_err("can't register miscdevice.\n");
        return ret;
    }

    pr_info("minor %d\n", ringdev_miscdevice.minor);

    return 0;
}

static void __exit ringdev_exit(void)
{                                                       
    misc_deregister(&ringdev_miscdevice);
    mutex_destroy(&ringdev_lock);
}

module_init(ringdev_init);
module_exit(ringdev_exit);

MODULE_DESCRIPTION("Device");
MODULE_AUTHOR("xxx");
MODULE_LICENSE("GPL");

标签: clinux

解决方案


推荐阅读