I'm experimenting a bit with kiobuffers in 2.4.22-1.2174.nptlsmp [plain rpm kernel]
- I took arch/cris/drivers/examples/kiobuftest.c
- compiled and insmod'd it
- mknod /dev/kiobuftest c <major> 0
- run the user-mode test ktest.c (attached)
[note: O_DIRECT in open is just a trie, it doesn't modify the result. It is there to test whether the O_DIRECT code path does something better...]
problem is that map_user_kiobuf() often puts 0's in maplist[i] for some/all i.
[root@xeone driver]# ./ktest buf=0xbf403008 addr=0xbf404000 len=8192 [root@xeone driver]# ./ktest buf=0xbf4c6008 addr=0xbf4c7000 len=8192 [root@xeone driver]# ./ktest buf=0xbf48f008 addr=0xbf490000 len=8192 [root@xeone driver]# dmesg nr_pages == 2 offset == 0 length == 8192 buf == 0xbf404000 page_add(maplist[0]) == 0xff8cd000 page_add(maplist[1]) == 0x00000000 nr_pages == 2 offset == 0 length == 8192 buf == 0xbf4c7000 page_add(maplist[0]) == 0x00000000 page_add(maplist[1]) == 0xff9cb000 nr_pages == 2 offset == 0 length == 8192 buf == 0xbf490000 page_add(maplist[0]) == 0xffa90000 page_add(maplist[1]) == 0x00000000
[root@xeone driver]# dd if=/dev/kiobuftest of=miao bs=8192 count=1 1+0 records in 1+0 records out [root@xeone driver]# dmesg |tail nr_pages == 2 offset == 0 length == 8192 buf == 0x09650000 page_add(maplist[0]) == 0xffa91000 page_add(maplist[1]) == 0x00000000
[root@xeone driver]# dd if=/dev/kiobuftest of=miao bs=$[2*8192] count=1 1+0 records in 1+0 records out [root@xeone driver]# dmesg |tail nr_pages == 4 offset == 0 length == 16384 buf == 0x08ee8000 page_add(maplist[0]) == 0xffaa9000 page_add(maplist[1]) == 0xff8d9000 page_add(maplist[2]) == 0x00000000 page_add(maplist[3]) == 0x00000000
so it seems that sometimes I get a kernel virtual address = 0...
it is strange as the code in memory.c:get_user_pages(), called by map_user_kiobuf(), has guards against it happening:
if (pages) {
pages[i] = get_page_map(map);
/* FIXME: call the correct function,
* depending on the type of the found page
*/
if (!pages[i])
goto bad_page;
page_cache_get(pages[i]);
}
seems like there is an error which is not propagated up to the caller of map_user_kiobuf()
I'm compiling a plain 2.4.25 + dprintk active to double check....
regards
#define _GNU_SOURCE #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define PAGE_SHIFT 12 #define PAGE_SIZE (1UL << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) int main(int argc, char* argv[]) { int fd, ret; fd = open("/dev/kiobuftest", O_RDWR|O_DIRECT); char* buf = malloc(1024*1024); char* addr = (u_int32_t)(buf+PAGE_SIZE-1)&PAGE_MASK; int len = 2*4096; printf("buf=0x%08x addr=0x%08x len=%d\n", buf, addr, len); ret = read(fd, addr, len); if(ret != len) { perror("ret!=len\n"); } free(buf); close(fd); return 0; }