svn commit: r343082 - in head: contrib/netbsd-tests/kernel lib/libc/sys sys/kern sys/sys sys/vm

Konstantin Belousov kib at FreeBSD.org
Wed Jan 16 05:16:00 UTC 2019


Author: kib
Date: Wed Jan 16 05:15:57 2019
New Revision: 343082
URL: https://svnweb.freebsd.org/changeset/base/343082

Log:
  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

Modified:
  head/contrib/netbsd-tests/kernel/t_sysv.c
  head/lib/libc/sys/shmat.2
  head/sys/kern/sysv_shm.c
  head/sys/sys/shm.h
  head/sys/vm/vm_map.c
  head/sys/vm/vm_map.h

Modified: head/contrib/netbsd-tests/kernel/t_sysv.c
==============================================================================
--- head/contrib/netbsd-tests/kernel/t_sysv.c	Wed Jan 16 05:09:29 2019	(r343081)
+++ head/contrib/netbsd-tests/kernel/t_sysv.c	Wed Jan 16 05:15:57 2019	(r343082)
@@ -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,19 +773,27 @@ 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
 print_shmid_ds(struct shmid_ds *sp, mode_t mode)
 {
@@ -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();
 }

Modified: head/lib/libc/sys/shmat.2
==============================================================================
--- head/lib/libc/sys/shmat.2	Wed Jan 16 05:09:29 2019	(r343081)
+++ head/lib/libc/sys/shmat.2	Wed Jan 16 05:15:57 2019	(r343082)
@@ -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

Modified: head/sys/kern/sysv_shm.c
==============================================================================
--- head/sys/kern/sysv_shm.c	Wed Jan 16 05:09:29 2019	(r343081)
+++ head/sys/kern/sysv_shm.c	Wed Jan 16 05:15:57 2019	(r343082)
@@ -388,7 +388,7 @@ kern_shmat_locked(struct thread *td, int shmid, const 
 	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 
 		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 
 			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 
 		 */
 		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);

Modified: head/sys/sys/shm.h
==============================================================================
--- head/sys/sys/shm.h	Wed Jan 16 05:09:29 2019	(r343081)
+++ head/sys/sys/shm.h	Wed Jan 16 05:15:57 2019	(r343082)
@@ -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

Modified: head/sys/vm/vm_map.c
==============================================================================
--- head/sys/vm/vm_map.c	Wed Jan 16 05:09:29 2019	(r343081)
+++ head/sys/vm/vm_map.c	Wed Jan 16 05:15:57 2019	(r343082)
@@ -1565,6 +1565,8 @@ vm_map_find(vm_map_t map, vm_object_t object, vm_ooffs
 	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 @@ again:
 			}
 			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,

Modified: head/sys/vm/vm_map.h
==============================================================================
--- head/sys/vm/vm_map.h	Wed Jan 16 05:09:29 2019	(r343081)
+++ head/sys/vm/vm_map.h	Wed Jan 16 05:15:57 2019	(r343082)
@@ -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


More information about the svn-src-head mailing list