Implement shmat(2) flag SHM_REMAP.

Based on the description in Linux man page.

Reviewed by:	markj, ngie (previous version)
Sponsored by:	Mellanox Technologies
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D18837
This commit is contained in:
Konstantin Belousov 2019-01-16 05:15:57 +00:00
parent b87850b96e
commit ea7e7006db
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=343082
6 changed files with 106 additions and 11 deletions

View File

@ -47,6 +47,7 @@
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/msg.h>
#include <sys/param.h>
#include <sys/sem.h>
@ -772,17 +773,25 @@ ATF_TC_BODY(shm, tc)
atf_tc_fail("sender: received unexpected signal");
}
ATF_TC_CLEANUP(shm, tc)
static void
shmid_cleanup(const char *name)
{
int sender_shmid;
int shmid;
/*
* Remove the shared memory area if it exists.
*/
sender_shmid = read_int("sender_shmid");
if (sender_shmid != -1)
if (shmctl(sender_shmid, IPC_RMID, NULL) == -1)
shmid = read_int(name);
if (shmid != -1) {
if (shmctl(shmid, IPC_RMID, NULL) == -1)
err(1, "shmctl IPC_RMID");
}
}
ATF_TC_CLEANUP(shm, tc)
{
shmid_cleanup("sender_shmid");
}
void
@ -837,12 +846,53 @@ sharer(void)
exit(0);
}
#ifdef SHM_REMAP
ATF_TC_WITH_CLEANUP(shm_remap);
ATF_TC_HEAD(shm_remap, tc)
{
atf_tc_set_md_var(tc, "descr", "Checks SHM_REMAP");
}
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);
}
ATF_TC_CLEANUP(shm_remap, tc)
{
shmid_cleanup("shmid_remap");
}
#endif /* SHM_REMAP */
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, msg);
ATF_TP_ADD_TC(tp, sem);
ATF_TP_ADD_TC(tp, shm);
#ifdef SHM_REMAP
ATF_TP_ADD_TC(tp, shm_remap);
#endif
return atf_no_error();
}

View File

@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd January 25, 2018
.Dd January 14, 2019
.Dt SHMAT 2
.Os
.Sh NAME
@ -64,17 +64,38 @@ kernel.
.It
If
.Fa addr
is nonzero and SHM_RND is not specified in
is nonzero and
.Va SHM_RND
is not specified in
.Fa flag ,
the segment is attached the specified address.
.It
If
.Fa addr
is specified and SHM_RND is specified,
is specified and
.Va SHM_RND
is specified,
.Fa addr
is rounded down to the nearest multiple of SHMLBA.
.El
.Pp
If the
.Va SHM_REMAP
flag is specified and the passed
.Fa addr
is not
.Dv NULL ,
any existing mappings in the virtual addresses range are
cleared before the segment is attached.
If the flag is not specified,
.Fa addr
is not
.Dv NULL ,
and the virtual address range contains
some pre-existing mappings, the
.Fn shmat
call fails.
.Pp
The
.Fn shmdt
system call
@ -104,6 +125,14 @@ The
.Fa addr
argument
was not an acceptable address.
.It Bq Er ENOMEM
The specified
.Fa addr
cannot be used for mapping, for instance due to the amount of available
space being smaller than the segment size,
or because pre-existing mappings are in the range and no
.Va SHM_REMAP
flag was provided.
.It Bq Er EMFILE
Failed to attach the shared memory segment because the per-process
.Va kern.ipc.shmseg

View File

@ -388,7 +388,7 @@ kern_shmat_locked(struct thread *td, int shmid, const void *shmaddr,
vm_offset_t attach_va;
vm_prot_t prot;
vm_size_t size;
int error, i, rv;
int cow, error, find_space, i, rv;
AUDIT_ARG_SVIPC_ID(shmid);
AUDIT_ARG_VALUE(shmflg);
@ -427,6 +427,7 @@ kern_shmat_locked(struct thread *td, int shmid, const void *shmaddr,
return (EMFILE);
size = round_page(shmseg->u.shm_segsz);
prot = VM_PROT_READ;
cow = MAP_INHERIT_SHARE | MAP_PREFAULT_PARTIAL;
if ((shmflg & SHM_RDONLY) == 0)
prot |= VM_PROT_WRITE;
if (shmaddr != NULL) {
@ -436,6 +437,9 @@ kern_shmat_locked(struct thread *td, int shmid, const void *shmaddr,
attach_va = (vm_offset_t)shmaddr;
else
return (EINVAL);
if ((shmflg & SHM_REMAP) != 0)
cow |= MAP_REMAP;
find_space = VMFS_NO_SPACE;
} else {
/*
* This is just a hint to vm_map_find() about where to
@ -443,12 +447,12 @@ kern_shmat_locked(struct thread *td, int shmid, const void *shmaddr,
*/
attach_va = round_page((vm_offset_t)p->p_vmspace->vm_daddr +
lim_max(td, RLIMIT_DATA));
find_space = VMFS_OPTIMAL_SPACE;
}
vm_object_reference(shmseg->object);
rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->object, 0, &attach_va,
size, 0, shmaddr != NULL ? VMFS_NO_SPACE : VMFS_OPTIMAL_SPACE,
prot, prot, MAP_INHERIT_SHARE | MAP_PREFAULT_PARTIAL);
size, 0, find_space, prot, prot, cow);
if (rv != KERN_SUCCESS) {
vm_object_deallocate(shmseg->object);
return (ENOMEM);

View File

@ -52,6 +52,7 @@
#define SHM_RDONLY 010000 /* Attach read-only (else read-write) */
#define SHM_RND 020000 /* Round attach address to SHMLBA */
#define SHM_REMAP 030000 /* Unmap before mapping */
#define SHMLBA PAGE_SIZE /* Segment low boundary address multiple */
/* "official" access mode definitions; somewhat braindead since you have

View File

@ -1565,6 +1565,8 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
KASSERT((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) == 0 ||
object == NULL,
("vm_map_find: non-NULL backing object for stack"));
MPASS((cow & MAP_REMAP) == 0 || (find_space == VMFS_NO_SPACE &&
(cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) == 0));
if (find_space == VMFS_OPTIMAL_SPACE && (object == NULL ||
(object->flags & OBJ_COLORED) == 0))
find_space = VMFS_ANY_SPACE;
@ -1595,6 +1597,14 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
}
goto done;
}
} else if ((cow & MAP_REMAP) != 0) {
if (*addr < vm_map_min(map) ||
*addr + length > vm_map_max(map) ||
*addr + length <= length) {
rv = KERN_INVALID_ADDRESS;
goto done;
}
vm_map_delete(map, *addr, *addr + length);
}
if ((cow & (MAP_STACK_GROWS_DOWN | MAP_STACK_GROWS_UP)) != 0) {
rv = vm_map_stack_locked(map, *addr, length, sgrowsiz, prot,

View File

@ -342,6 +342,7 @@ long vmspace_resident_count(struct vmspace *vmspace);
#define MAP_DISABLE_COREDUMP 0x0100
#define MAP_PREFAULT_MADVISE 0x0200 /* from (user) madvise request */
#define MAP_VN_WRITECOUNT 0x0400
#define MAP_REMAP 0x0800
#define MAP_STACK_GROWS_DOWN 0x1000
#define MAP_STACK_GROWS_UP 0x2000
#define MAP_ACC_CHARGED 0x4000