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 されたバッファの処理方法に問題があるようです。回避策は何ですか?EFAULT
get_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 されたバッファでは問題ないのはなぜですか? どんな助けでも大歓迎です。