2017-12-18 242 views
0

我爲我的內核模塊實現了一個char設備併爲其實現了一個讀取函數。讀函數調用copy_to_user將數據返回給調用者。我最初以阻塞的方式實現了讀取功能(使用wait_event_interruptible),但即使以非阻塞方式實現讀取,問題也會再現。我的代碼在MIPS處理器上運行。copy_to_user在char設備讀取函數中返回一個錯誤

用戶空間程序打開char設備並讀入堆棧中分配的緩衝區。

我發現的是偶爾copy_to_user將無法​​複製任何字節。此外,即使我用(僅用於檢查......我知道這不是正確的做法)調用替換copy_to_user,然後立即打印目標緩衝區,我看到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

你的代碼有問題,但你不顯示它。 – Tsyvarev

+0

@Tsyvarev添加了一些僞代碼,希望能夠說明代碼所做的工作。不幸的是,我還沒有能夠縮小到一個小的,再現的例子。 – YSK

+0

@YSK你已經聲明瞭兩次'int rc'。從'int rc = copy_to_user(output_buffer,internal_buffer,bytes_to_copy)''行中刪除'int'。 – Gaurav

回答

0

它進行了相當多的調試,但最終Tsyvarev的提示(關於不採用自旋鎖調用copy_to_user的評論)似乎是原因。

我們的程序有一個後臺線程,偶爾會啓動一個新進程(fork + exec)。當我們禁用此線程時,一切運行良好。我們擁有的最好理論是,fork使我們所有的內存頁面都可以在寫入時進行復制,所以當我們試圖複製它們時,內核必須做一些無法使用自旋鎖執行的工作。希望它至少有一定意義(儘管我已經猜到這隻適用於子進程,並且父進程頁面仍然是可寫的,但是誰知道......)。

我們重寫了我們的代碼,使其無法鎖定,問題消失。

現在我們只需要驗證我們的無鎖代碼在不同的架構上確實是安全的。易如反掌。