While testing some other SYSV SHM changes, I noticed that the kyua sysv_test:shm_remap fails on CheriBSD.
The test does this:
ATF_TC_BODY(shm_remap, tc)
{
char *shm_buf;
int shmid_remap;
pgsize = sysconf(_SC_PAGESIZE);
shmkey = get_ftok(4160);
ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed");
ATF_REQUIRE_MSG((shmid_remap = shmget(shmkey, pgsize,
IPC_CREAT | 0640)) != -1, "shmget: %d", errno);
write_int("shmid_remap", shmid_remap);
ATF_REQUIRE_MSG((shm_buf = mmap(NULL, pgsize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0)) != MAP_FAILED, "mmap: %d", errno);
ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, 0) == (void *)-1,
"shmat without MAP_REMAP succeeded");
ATF_REQUIRE_MSG(shmat(shmid_remap, shm_buf, SHM_REMAP) == shm_buf,
"shmat(SHM_REMAP): %d", errno);
}
So it maps a single page, then shmat() on top of it with SHM_REMAP. The second call to shmat() fails with ENOMEM:
# kyua test -k /usr/tests/sys/kern/Kyuafile sysv_test:shm_remap
sysv_test:shm_remap -> failed: /usr/home/john/work/cheri/git/cheribsd/contrib/netbsd-tests/kernel/t_sysv.c:800: shmat(SHM_REMAP): 12 [1.660s]
Single stepping in the kernel, I traced this down to this seeming bug in vm_map_find_locked():
if (find_space != VMFS_NO_SPACE) {
...
} else if ((cow & MAP_REMAP) != 0) {
if (!vm_map_range_valid(map, vaddr, vaddr + length))
return (KERN_INVALID_ADDRESS);
rv = vm_map_delete(map, vaddr, vaddr + length, true);
if (rv != KERN_SUCCESS)
return (rv);
}
reservation = vaddr;
rv = vm_map_reservation_create_locked(map, &reservation,
length, max);
if (rv != KERN_SUCCESS)
return (rv);
In this case MAP_REMAP is set, so the old range is deleted, but the existing reservation is left in place, so then the vm_map_reservation_create_locked() fails. Possibly for the SHM_REMAP case we should be using vm_map_fixed instead? Or maybe for the MAP_REMAP case we should try using vm_map_reservation_get?
While testing some other SYSV SHM changes, I noticed that the kyua sysv_test:shm_remap fails on CheriBSD.
The test does this:
So it maps a single page, then shmat() on top of it with SHM_REMAP. The second call to shmat() fails with ENOMEM:
Single stepping in the kernel, I traced this down to this seeming bug in vm_map_find_locked():
In this case MAP_REMAP is set, so the old range is deleted, but the existing reservation is left in place, so then the
vm_map_reservation_create_locked()fails. Possibly for the SHM_REMAP case we should be using vm_map_fixed instead? Or maybe for the MAP_REMAP case we should try using vm_map_reservation_get?