1

memmap=nn[KMG]$ss[KMG]カーネル コマンド ライン パラメータで数 GB のメモリを予約しました。また、構造体からmmap()andを使用し、カスタム PCIe デバイスに対して DMA 操作を実行するカスタム char デバイス ドライバーもあります。一般的なDMA APIを使用してスキャッター/ギャザー リストを作成します。write()file_operations

私のドライバーでは成功しており、ユーザー空間から一日中このメモリmmap()に読み書きできます。io_remap_pfn_range()私のドライバーのwrite()関数は、mmap されたバッファーを使用してスキャッター ギャザー リストを作成することになっています。

ただし、呼び出し時にドライバーのwrite()機能が失敗し、その理由を説明できません。ユーザー空間からの mmap バッファーの代わりに malloc バッファーを使用すると、すべてが期待どおりに機能します。 mmap されたバッファの処理方法に問題があるようです。回避策は何ですか?EFAULTget_user_pages_fast()get_user_pages_fast()

例えば、

/* From user-space
 * What currently works but has poor performance
 */

int fd;
FILE *fdat;
char *buf;
ssize_t rc;
size_t len = 4*1024*1024*1024; /* 4GB */

fd = open("/dev/mycooldev", O_RDWR|O_SYNC);
rc = posix_memalign(&buf, 4096, len);
fdat = fopen("mydat.bin", "r");
fread(buf, 1, len, fdat);
fclose(fdat);
rc = write(fd, buf, len);
close(fd);
/* From user-space
 * What I want to do, i.e. use the many GB of contiguous reserved memory
 */

int fd;
FILE *fdat;
char *buf;
ssize_t rc;
size_t len = 4*1024*1024*1024; /* 4GB */

fd = open("/dev/mycooldev", O_RDWR|O_SYNC);
buf = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
fdat = fopen("mydat.bin", "r");
fread(buf, 1, len, fdat);
fclose(fdat);
rc = write(fd, buf, len);
close(fd);

write()デバイスドライバーの関連機能:

/* From the char device driver
 * buf is a pointer to the buffer returned from either 
 * posix_memalign() or mmap(), but mmap() doesn't work
 * because of get_user_pages_fast()
 */

ssize_t mycooldev_write(struct file *file, char __user *buf, size_t len, loff_t *pos)
{
    int rc;
    struct page **pages;
    size_t npages;
    struct sg_table sgt;
    unsigned long uaddr, start, end;

    ...

    /* EDIT: I added this call per a request in comments */
    if (access_ok(VERIFY_WRITE, buf, len) == 0) {
        pr_err("Not allowed to access user address\n");
        return -EFAULT;
    }

    uaddr = (unsigned long)buf;
    start = uaddr & PAGE_MASK_64; /* (0xFFFFFFFF00000000 | PAGE_MASK) */
    end = uaddr + len + PAGE_SIZE - 1;
    npages = (end - start) >> PAGE_SHIFT;

    pages = kcalloc(npages, sizeof(struct page *), GFP_KERNEL);

    /* This call fails with EFAULT when user passes in a buffer
     * obtained with a call to mmap(). If user calls posix_memalign()
     * to obtain their buffer, get_user_pages_fast() is successful.
     */
    rc = get_user_pages_fast(uaddr, npages, 1, pages);

    rc = sg_alloc_table_from_pages(&sgt, pages, npages, pos, len, GFP_KERNEL);

    ...
}

get_user_pages_fast()mmap されたバッファが気に入らないのに、malloc されたバッファでは問題ないのはなぜですか? どんな助けでも大歓迎です。

4

0 に答える 0