代码之家  ›  专栏  ›  技术社区  ›  YSK

copy\u to\u user在char设备读取函数中返回错误

  •  0
  • YSK  · 技术社区  · 7 年前

    我已经为我的内核模块实现了一个char设备,并为它实现了一个read函数。read函数调用 copy_to_user 将数据返回给调用者。我最初以阻塞的方式实现了read函数(使用 wait_event_interruptible )但即使以非阻塞方式实现读取,问题也会再次出现。我的代码正在MIPS处理器上运行。

    用户空间程序打开char设备并读取堆栈上分配的缓冲区。

    我发现偶尔 将\u复制到\u用户 将无法复制任何字节。而且,即使我替换 将\u复制到\u用户 打电话给 memcpy (只是为了检查……我知道这不是正确的做法),然后立即打印出目标缓冲区,我看到 memcpy公司 未能复制任何字节。

    我真的不知道如何进一步调试它-我如何确定为什么没有复制内存?流程上下文是否可能错误?

    编辑 :以下是一些伪代码,概述了代码当前的外观:

    用户模式(重复运行):

    char buf[BUF_LEN];
    FILE *f = fopen(char_device_file, "rb");
    fread(buf, 1, BUF_LEN, f);
    fclose(f);
    

    内核模式:

    char_device = 
        create_char_device(char_device_name,
            NULL,
            read_func,
            NULL,
            NULL);
    
    int read_func(char *output_buffer, int output_buffer_length, loff_t *offset)
    {
        int rc;
        if (*offset == 0)
        {
            spin_lock_irqsave(&lock, flags);
    
            while (get_available_bytes_to_read() == 0)
            {
                spin_unlock_irqrestore(&lock, flags);
                if (wait_event_interruptible(self->wait_queue, get_available_bytes_to_read() != 0))
                {
                    // Got a signal; retry the read
                    return -ERESTARTSYS;
                }
    
                spin_lock_irqsave(&lock, flags);
            }
    
            rc = copy_to_user(output_buffer, internal_buffer, bytes_to_copy);
    
            spin_unlock_irqrestore(&lock, flags);
        } 
        else rc = 0;
    
        return rc;
    }
    
    1 回复  |  直到 7 年前
        1
  •  0
  •   YSK    7 年前

    这花了相当多的时间进行调试,但最终Tsyvarev的提示(关于不打电话的评论 copy_to_user 与旋转锁采取)似乎是原因。

    我们的进程有一个后台线程,偶尔会启动一个新进程( fork + exec ). 当我们禁用此线程时,一切正常。我们拥有的最好的理论是,fork使我们所有的内存页都在写时进行复制,因此当我们试图复制到它们时,内核必须做一些使用自旋锁无法完成的工作。希望它至少有一定的意义(虽然我猜这只适用于子进程,父进程的进程页面将保持可写,但谁知道呢…)。

    我们将代码重写为无锁,问题就消失了。

    现在,我们只需要验证我们的无锁代码在不同的体系结构上确实是安全的。非常简单。