sysvshm: replace Giant with a local sx lock

From: Mateusz Guzik <mjguzik_at_gmail.com>
Date: Tue, 23 Apr 2013 22:38:23 +0200
Hello,

I would like to replace Giant with a local sx lock in sysvshm code.
Looked really straightforward so maybe I missed something.

Patch: http://people.freebsd.org/~mjg/patches/sysvshm-giant-sx.patch

Inlined version for comments:
diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c
index a1c6b34..480a3b2 100644
--- a/sys/kern/sysv_shm.c
+++ b/sys/kern/sysv_shm.c
_at__at_ -111,6 +111,7 _at__at_ static int shmget_existing(struct thread *td, struct shmget_args *uap,
 #define	SHMSEG_ALLOCATED	0x0800
 #define	SHMSEG_WANTED		0x1000
 
+static struct sx shm_lock;
 static int shm_last_free, shm_nused, shmalloced;
 vm_size_t shm_committed;
 static struct shmid_kernel	*shmsegs;
_at__at_ -181,8 +182,8 _at__at_ SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW,
 SYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RW,
     &shm_allow_removed, 0,
     "Enable/Disable attachment to attached segments marked for removal");
-SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE | CTLFLAG_RD,
-    NULL, 0, sysctl_shmsegs, "",
+SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE | CTLFLAG_RD |
+    CTLFLAG_MPSAFE, NULL, 0, sysctl_shmsegs, "",
     "Current number of shared memory segments allocated");
 
 static int
_at__at_ -191,6 +192,8 _at__at_ shm_find_segment_by_key(key)
 {
 	int i;
 
+	sx_assert(&shm_lock, SA_XLOCKED);
+
 	for (i = 0; i < shmalloced; i++)
 		if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) &&
 		    shmsegs[i].u.shm_perm.key == key)
_at__at_ -204,6 +207,8 _at__at_ shm_find_segment_by_shmid(int shmid)
 	int segnum;
 	struct shmid_kernel *shmseg;
 
+	sx_assert(&shm_lock, SA_XLOCKED);
+
 	segnum = IPCID_TO_IX(shmid);
 	if (segnum < 0 || segnum >= shmalloced)
 		return (NULL);
_at__at_ -221,6 +226,8 _at__at_ shm_find_segment_by_shmidx(int segnum)
 {
 	struct shmid_kernel *shmseg;
 
+	sx_assert(&shm_lock, SA_XLOCKED);
+
 	if (segnum < 0 || segnum >= shmalloced)
 		return (NULL);
 	shmseg = &shmsegs[segnum];
_at__at_ -237,7 +244,7 _at__at_ shm_deallocate_segment(shmseg)
 {
 	vm_size_t size;
 
-	GIANT_REQUIRED;
+	sx_assert(&shm_lock, SA_XLOCKED);
 
 	vm_object_deallocate(shmseg->object);
 	shmseg->object = NULL;
_at__at_ -261,7 +268,7 _at__at_ shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s)
 	int segnum, result;
 	vm_size_t size;
 
-	GIANT_REQUIRED;
+	sx_assert(&shm_lock, SA_XLOCKED);
 
 	segnum = IPCID_TO_IX(shmmap_s->shmid);
 	shmseg = &shmsegs[segnum];
_at__at_ -299,7 +306,7 _at__at_ sys_shmdt(td, uap)
 
 	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
 		return (ENOSYS);
-	mtx_lock(&Giant);
+	sx_xlock(&shm_lock);
 	shmmap_s = p->p_vmspace->vm_shm;
  	if (shmmap_s == NULL) {
 		error = EINVAL;
_at__at_ -323,7 +330,7 _at__at_ sys_shmdt(td, uap)
 #endif
 	error = shm_delete_mapping(p->p_vmspace, shmmap_s);
 done2:
-	mtx_unlock(&Giant);
+	sx_xunlock(&shm_lock);
 	return (error);
 }
 
_at__at_ -353,7 +360,7 _at__at_ kern_shmat(td, shmid, shmaddr, shmflg)
 
 	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
 		return (ENOSYS);
-	mtx_lock(&Giant);
+	sx_xlock(&shm_lock);
 	shmmap_s = p->p_vmspace->vm_shm;
 	if (shmmap_s == NULL) {
 		shmmap_s = malloc(shminfo.shmseg * sizeof(struct shmmap_state),
_at__at_ -428,7 +435,7 _at__at_ kern_shmat(td, shmid, shmaddr, shmflg)
 	shmseg->u.shm_nattch++;
 	td->td_retval[0] = attach_va;
 done2:
-	mtx_unlock(&Giant);
+	sx_xunlock(&shm_lock);
 	return (error);
 }
 
_at__at_ -454,7 +461,7 _at__at_ kern_shmctl(td, shmid, cmd, buf, bufsz)
 	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
 		return (ENOSYS);
 
-	mtx_lock(&Giant);
+	sx_xlock(&shm_lock);
 	switch (cmd) {
 	/*
 	 * It is possible that kern_shmctl is being called from the Linux ABI
_at__at_ -546,7 +553,7 _at__at_ kern_shmctl(td, shmid, cmd, buf, bufsz)
 		break;
 	}
 done2:
-	mtx_unlock(&Giant);
+	sx_xunlock(&shm_lock);
 	return (error);
 }
 
_at__at_ -611,6 +618,8 _at__at_ shmget_existing(td, uap, mode, segnum)
 	struct shmid_kernel *shmseg;
 	int error;
 
+	sx_assert(&shm_lock, SA_XLOCKED);
+
 	shmseg = &shmsegs[segnum];
 	if (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) {
 		/*
_at__at_ -649,7 +658,7 _at__at_ shmget_allocate_segment(td, uap, mode)
 	struct shmid_kernel *shmseg;
 	vm_object_t shm_object;
 
-	GIANT_REQUIRED;
+	sx_assert(&shm_lock, SA_XLOCKED);
 
 	if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
 		return (EINVAL);
_at__at_ -758,7 +767,7 _at__at_ sys_shmget(td, uap)
 
 	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
 		return (ENOSYS);
-	mtx_lock(&Giant);
+	sx_xlock(&shm_lock);
 	mode = uap->shmflg & ACCESSPERMS;
 	if (uap->key != IPC_PRIVATE) {
 	again:
_at__at_ -776,7 +785,7 _at__at_ sys_shmget(td, uap)
 	}
 	error = shmget_allocate_segment(td, uap, mode);
 done2:
-	mtx_unlock(&Giant);
+	sx_xunlock(&shm_lock);
 	return (error);
 }
 
_at__at_ -788,7 +797,7 _at__at_ shmfork_myhook(p1, p2)
 	size_t size;
 	int i;
 
-	mtx_lock(&Giant);
+	sx_xlock(&shm_lock);
 	size = shminfo.shmseg * sizeof(struct shmmap_state);
 	shmmap_s = malloc(size, M_SHM, M_WAITOK);
 	bcopy(p1->p_vmspace->vm_shm, shmmap_s, size);
_at__at_ -796,7 +805,7 _at__at_ shmfork_myhook(p1, p2)
 	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
 		if (shmmap_s->shmid != -1)
 			shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++;
-	mtx_unlock(&Giant);
+	sx_xunlock(&shm_lock);
 }
 
 static void
_at__at_ -807,12 +816,12 _at__at_ shmexit_myhook(struct vmspace *vm)
 
 	if ((base = vm->vm_shm) != NULL) {
 		vm->vm_shm = NULL;
-		mtx_lock(&Giant);
+		sx_xlock(&shm_lock);
 		for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) {
 			if (shm->shmid != -1)
 				shm_delete_mapping(vm, shm);
 		}
-		mtx_unlock(&Giant);
+		sx_xunlock(&shm_lock);
 		free(base, M_SHM);
 	}
 }
_at__at_ -823,6 +832,8 _at__at_ shmrealloc(void)
 	int i;
 	struct shmid_kernel *newsegs;
 
+	sx_assert(&shm_lock, SA_XLOCKED);
+
 	if (shmalloced >= shminfo.shmmni)
 		return;
 
_at__at_ -918,6 +929,8 _at__at_ shminit()
 	shmexit_hook = &shmexit_myhook;
 	shmfork_hook = &shmfork_myhook;
 
+	sx_init(&shm_lock, "sysvshm");
+
 	error = syscall_helper_register(shm_syscalls);
 	if (error != 0)
 		return (error);
_at__at_ -955,6 +968,7 _at__at_ shmunload()
 			vm_object_deallocate(shmsegs[i].object);
 	}
 	free(shmsegs, M_SHM);
+	sx_destroy(&shm_lock);
 	shmexit_hook = NULL;
 	shmfork_hook = NULL;
 	return (0);
_at__at_ -963,8 +977,12 _at__at_ shmunload()
 static int
 sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
 {
+	int error;
 
-	return (SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0])));
+	sx_xlock(&shm_lock);
+	error = SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0]));
+	sx_xunlock(&shm_lock);
+	return (error);
 }
 
 #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
_at__at_ -996,7 +1014,7 _at__at_ oshmctl(struct thread *td, struct oshmctl_args *uap)
 
 	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
 		return (ENOSYS);
-	mtx_lock(&Giant);
+	sx_xlock(&shm_lock);
 	shmseg = shm_find_segment_by_shmid(uap->shmid);
 	if (shmseg == NULL) {
 		error = EINVAL;
_at__at_ -1030,7 +1048,7 _at__at_ oshmctl(struct thread *td, struct oshmctl_args *uap)
 		break;
 	}
 done2:
-	mtx_unlock(&Giant);
+	sx_xunlock(&shm_lock);
 	return (error);
 #else
 	return (EINVAL);
_at__at_ -1062,9 +1080,9 _at__at_ sys_shmsys(td, uap)
 	if (uap->which < 0 ||
 	    uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
 		return (EINVAL);
-	mtx_lock(&Giant);
+	sx_xlock(&shm_lock);
 	error = (*shmcalls[uap->which])(td, &uap->a2);
-	mtx_unlock(&Giant);
+	sx_xunlock(&shm_lock);
 	return (error);
 }
 
-- 
Mateusz Guzik <mjguzik gmail.com>
Received on Tue Apr 23 2013 - 18:38:28 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:36 UTC