2012-02-23 93 views
0

我的司机必须从用户缓冲区写入称为味精字符数组,这是在全球范围内防止覆盖编写字符设备驱动程序的Linux

//global scope 
... 
#define SIZE 64; 
char msg[SIZE]; 
... 

所以这是写功能函数。

static ssize_t Dev_Write(struct file *flip, const char __user *buffer, size_t length, loff_t *offset) 
    { 

     copy_from_user(msg + *offset, buffer, length); //I hope *offset = 0 at the first call 
     printk(KERN_INFO "message from UserSpace is: %s \n", msg); 
     *offset += length; 

     return length; 
    } 

当我按顺序调用这个函数两次,它会覆盖msg中的第一个数据。我希望它只是从最后的位置继续。 我想我必须做一些事情*偏移

这是用户程序:

#include <stdlib.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <iostream> 
using namespace std; 

#define BUFFER_SIZE 64 

int main (int argc, char ** argv) 
{ 
    int fd; 
    ssize_t read_bytes; 
    ssize_t written_bytes; 
    char buffer[BUFFER_SIZE] = "aaaaaa"; 
    char buffer1[BUFFER_SIZE] = "bbbbbb"; 
    char buffer2[BUFFER_SIZE]; 
    fd = open ("/dev/2", O_RDWR); 
    if (fd < 0) 
    { 
     fprintf (stderr, "Cannot open file\n"); 
     exit (1); 
    } 


    written_bytes = write (fd, buffer, BUFFER_SIZE); 
    write (fd, buffer1, BUFFER_SIZE); 
    read_bytes = read (fd, buffer2, BUFFER_SIZE); 
    cout<<buffer<<endl; 
    if(written_bytes < 0) 
    { 
     fprintf (stderr, "myread: Cannot write to file\n"); 
     exit (1); 
    } 
    if (read_bytes < 0) 
    { 
     fprintf (stderr, "myread: Cannot read from file\n"); 
     exit (1); 
    } 
    close (fd); 
    exit (0); 
} 

谢谢。

+0

你的问题不清楚你在做什么。当你说“我依次调用这个函数两次”,你的意思是你的内核模式异步调用它两次吗?或者响应来自用户空间的一个呼叫?或者响应来自用户空间的两个呼叫?我们没有上下文来理解你的问题,不知道你的写功能是什么或你的设备驱动程序驱动。 – 2012-02-23 10:26:04

+0

你是对的。抱歉。它响应来自用户空间的呼叫。在我的用户程序中,我写入**/dev **中的一个文件,该文件绑定到我的设备上,并显示它的主编号。这是简单的字符设备驱动程序。在用户空间中写入两个函数后,我的驱动程序Dev_Write函数会覆盖数据,而不是继续。 – 2012-02-23 10:35:54

+0

然后问题可能是用户空间传递两次相同的缓冲区。 – 2012-02-23 10:44:24

回答

0

我解决了我的问题。

我不得不添加*补偿缓冲区中的实际数据长度。

copy_from_user(msg + *offset, buffer, length); 
printk(KERN_INFO "message from UserSpace is: %s \n", msg); 
*offset += strlen(buffer); 

非常感谢您。

1

我想我必须做一些事情*偏移

是的,你确实应该。也就是说,如果驱动程序没有文件位置的概念(如管道或套接字),则可以忽略设置文件位置。为了能够设置此文件位置,offset是一个指针,以便您可以修改该值,使其在外部可见。 (您还需要在代码中进行更多的安全检查,以确保您不会超出缓冲区的末尾。)*offset += whatever恰到好处。请注意,文件偏移量不需要以字节为单位进行度量,您还可以计入“记录”或其他任何浮动您的船只。

1

虽然根本问题并不完全清楚,但确实有一个错误会将您推向未定义的行为。你的用户空间程序每次写入64字节(BUFFER_SIZE),但你的内核缓冲区只有64字节长。第二次写入会导致溢出。

要调试您的问题,请执行以下步骤。在进入你写功能调试长度和您的邮件偏移:

printk(KERN_INFO "Size from userspace is: %d offset %d\n", length, *offset); 

此外,夹紧你的复印尺寸,这样你就不会覆盖缓冲区:

if (*offset > SIZE) 
    return -ENOSPC; 
if (*offset + length > SIZE) 
    length = SIZE - *offset; 

这些测试后就可以执行您的copy_from_user。测试是必要的,但我不确定它们是否足够修复。调试线可能会揭示其他事情正在混淆这种情况。