2012-06-12 97 views
1

我想從SATA HDD /dev/sdd製作基本的read()。 A write()似乎工作。另外read()write()工作沒有O_DIRECT標誌。我讀過,它必須與塊大小對齊。所以我用它來得到塊大小:從帶有O_DIRECT的HDD讀取()失敗,出現22(EINVAL,無效的參數)

root$ blockdev --getsize /dev/sdd 
488397168 

root$ blockdev --getsize64 /dev/sdd 
250059350016 

root$ python -c "print 250059350016.0/488397168" 
512.0 

正如你所看到的我有根。 HDD通過PCIe SATA卡連接,lspci -vv給我看,它使用基本的ahci(drivers/ata/ahci.c)驅動程序。 我使用64位Power Architecture上的3.2.0 Linux內核。

這裏是我的代碼:

#define _GNU_SOURCE 

#include <stdio.h> 
#include <string.h> 
#include <fcntl.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 

int main() { 

    int r; 
    char *buffer, *tmp_buffer; 
    // alloc more than necesarry to align the real buffer 
    tmp_buffer = malloc(2*512*sizeof(char)); 
    long align = (unsigned long)tmp_buffer%512; 
    printf("tmp_buffer is at: %x \% 512 = %d\n",tmp_buffer,align); 

    buffer = tmp_buffer+(512-align); 
    printf("buffer is at: %x \% 512 = %d\n",buffer,(unsigned long)buffer%512); 

    memset(buffer,0,sizeof(512)); 

    // OPEN 
    int fd = open("/dev/sdd",O_DIRECT | O_RDWR | O_SYNC); 
    if(fd!=3) printf("fd = %d\n",fd); 

    // READ 
    printf("try to read and then dump buffer:\n"); 

    r = read(fd,buffer,sizeof(512)); 
    if(r == -1) printf("Error: %s\n",strerror(errno)); 
    else { 
     // DUMP BUFFER 
     int i; 
     for(i=0; i<sizeof(512); i++) 
      printf("%c",buffer[i]); 
    } 
    printf("\n"); 
    return 0; 
} 

輸出是:

tmp_buffer is at: 1cc80010 % 512 = 16 
buffer is at: 1cc80200 % 512 = 0 
try to read and then dump buffer: 
Error: Invalid argument 

編輯: 我已經更新了我的源代碼由Brett硬朗的答案的建議。不幸的是我仍然得到錯誤。我的方法是找出塊大小好嗎?我有沒有完成對齊的權利?

非常感謝您的閱讀,
費邊

回答

4

直接DMA傳輸通常需要對齊的緩衝區。從man

的O_DIRECT標誌可以在長度強加對齊限制並解決用戶空間緩衝區和文件I/O的偏移量的 。 ...在Linux 2.6下,對齊到512字節的邊界就足夠了。

因此char buffer[512];可能需要對齊到一個512字節的地址。

它可能無法實現棧上對齊,所以像:

static char buffer[512] __attribute__ ((__aligned__ (512)));

可能工作。或者也許這種對齊將在堆棧上工作。或者,如果您使用x86,則可以使用<mm_malloc.h>內在支持功能:_mm_malloc_mm_free

+0

啊我必須調整我的緩衝區?我認爲filepointer的位置總是必須對齊(所以0是可以的)並且512字節對齊向後纔是正確的方法。我更新了我的源代碼,但仍然收到錯誤消息。你會如此善良,並檢查我所做的? :) – samuirai

+0

@samuirai,有一個有趣的線程[這裏](http://kerneltrap.org/node/7563)(2.6.x)與老闆的意見。 –

+0

是的,我讀過這個。對於這個項目來說,速度和停電證明是非常重要的。我必須確定時間我們可以寫多快。我太不知道,質疑這個:/ – samuirai

0

順便說一下,對齊總是不需要512字節的倍數。它取決於設備塊的大小。你應該使用帶有BLKSSZGET的ioctl來找到它。如果讀取在使用O_DIRECT時未與此值對齊,則read()將失敗,並顯示EINVAL。

相關問題