[PATCH] uts_sem as RW semaphore

Jakub Jelinek jakub en redhat.com
Jue Ene 27 07:05:30 CST 2000


Hi!

system_utsname is accessed mostly read-only, so it makes tons of sense
to make uts_sem a rw semaphore, especially when inside of uts_sem guarded
sections is usually code to copy it to userland which may sleep.
Like that uname and friends scale much better, because
setdomainname/sethostname happen usually during bootup only.
This patch also adds DECLARE_RWSEM(), DECLARE_RWSEM_READ_LOCKED() and
DECLARE_RWSEM_WRITE_LOCKED() in similar spirit to DECLARE_MUTEX(), so that
no code has to know the details of __RWSEM_INITIALIZER.
Please apply.

--- linux/arch/alpha/kernel/osf_sys.c.jj	Fri Jan 14 08:29:40 2000
+++ linux/arch/alpha/kernel/osf_sys.c	Thu Jan 27 10:45:16 2000
@@ -504,7 +504,7 @@ asmlinkage int osf_utsname(char *name)
 {
 	int error;
 
-	down(&uts_sem);
+	down_read(&uts_sem);
 	error = -EFAULT;
 	if (copy_to_user(name + 0, system_utsname.sysname, 32))
 		goto out;
@@ -519,7 +519,7 @@ asmlinkage int osf_utsname(char *name)
 
 	error = 0;
 out:
-	up(&uts_sem);	
+	up_read(&uts_sem);	
 	return error;
 }
 
@@ -569,7 +569,6 @@ asmlinkage int osf_getdomainname(char *n
 	unsigned len;
 	int i, error;
 
-	lock_kernel();
 	error = verify_area(VERIFY_WRITE, name, namelen);
 	if (error)
 		goto out;
@@ -578,15 +577,14 @@ asmlinkage int osf_getdomainname(char *n
 	if (namelen > 32)
 		len = 32;
 
-	down(&uts_sem);
+	down_read(&uts_sem);
 	for (i = 0; i < len; ++i) {
 		__put_user(system_utsname.domainname[i], name + i);
 		if (system_utsname.domainname[i] == '\0')
 			break;
 	}
-	up(&uts_sem);
+	up_read(&uts_sem);
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -810,7 +808,6 @@ asmlinkage long osf_sysinfo(int command,
 	char *res;
 	long len, err = -EINVAL;
 
-	lock_kernel();
 	offset = command-1;
 	if (offset >= sizeof(sysinfo_table)/sizeof(char *)) {
 		/* Digital UNIX has a few unpublished interfaces here */
@@ -818,7 +815,7 @@ asmlinkage long osf_sysinfo(int command,
 		goto out;
 	}
 	
-	down(&uts_sem);
+	down_read(&uts_sem);
 	res = sysinfo_table[offset];
 	len = strlen(res)+1;
 	if (len > count)
@@ -827,9 +824,8 @@ asmlinkage long osf_sysinfo(int command,
 		err = -EFAULT;
 	else
 		err = 0;
-	up(&uts_sem);
+	up_read(&uts_sem);
 out:
-	unlock_kernel();
 	return err;
 }
 
--- linux/arch/arm/kernel/sys_arm.c.jj	Fri Jan 14 08:42:06 2000
+++ linux/arch/arm/kernel/sys_arm.c	Thu Jan 27 10:46:30 2000
@@ -286,9 +286,9 @@ asmlinkage int sys_uname(struct old_utsn
 
 	if(!name)
 		return -EFAULT;
-	down(&uts_sem);
+	down_read(&uts_sem);
 	err=copy_to_user (name, &system_utsname, sizeof (*name));
-	up(&uts_sem);
+	up_read(&uts_sem);
 	return err?-EFAULT:0;
 }
 
@@ -309,7 +309,7 @@ asmlinkage int sys_olduname(struct oldol
 	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
 		return -EFAULT;
 
-	down(&uts_sem);
+	down_read(&uts_sem);
 	
 	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
 	error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
@@ -322,7 +322,7 @@ asmlinkage int sys_olduname(struct oldol
 	error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
 	error |= __put_user(0,name->machine+__OLD_UTS_LEN);
 	
-	up(&uts_sem);
+	up_read(&uts_sem);
 	
 	error = error ? -EFAULT : 0;
 
--- linux/arch/i386/kernel/sys_i386.c.jj	Mon Dec 20 09:12:31 1999
+++ linux/arch/i386/kernel/sys_i386.c	Thu Jan 27 10:47:06 2000
@@ -218,9 +218,9 @@ asmlinkage int sys_uname(struct old_utsn
 	int err;
 	if (!name)
 		return -EFAULT;
-	down(&uts_sem);
+	down_read(&uts_sem);
 	err=copy_to_user(name, &system_utsname, sizeof (*name));
-	up(&uts_sem);
+	up_read(&uts_sem);
 	return err?-EFAULT:0;
 }
 
@@ -233,7 +233,7 @@ asmlinkage int sys_olduname(struct oldol
 	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
 		return -EFAULT;
   
-  	down(&uts_sem);
+  	down_read(&uts_sem);
 	
 	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
 	error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
@@ -246,7 +246,7 @@ asmlinkage int sys_olduname(struct oldol
 	error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
 	error |= __put_user(0,name->machine+__OLD_UTS_LEN);
 	
-	up(&uts_sem);
+	up_read(&uts_sem);
 	
 	error = error ? -EFAULT : 0;
 
--- linux/arch/sh/kernel/sys_sh.c.jj	Thu Dec  9 11:45:25 1999
+++ linux/arch/sh/kernel/sys_sh.c	Thu Jan 27 10:47:38 2000
@@ -170,9 +170,9 @@ asmlinkage int sys_uname(struct old_utsn
 	int err;
 	if (!name)
 		return -EFAULT;
-	down(&uts_sem);
+	down_read(&uts_sem);
 	err=copy_to_user(name, &system_utsname, sizeof (*name));
-	up(&uts_sem);
+	up_read(&uts_sem);
 	return err?-EFAULT:0;
 }
 
--- linux/arch/sparc/kernel/sys_sparc.c.jj	Fri Jan 21 12:38:42 2000
+++ linux/arch/sparc/kernel/sys_sparc.c	Thu Jan 27 10:48:44 2000
@@ -368,7 +368,7 @@ asmlinkage int sys_getdomainname(char *n
  	int nlen;
  	int err = -EFAULT;
  	
- 	down(&uts_sem);
+ 	down_read(&uts_sem);
  	
 	nlen = strlen(system_utsname.domainname) + 1;
 
@@ -380,7 +380,7 @@ asmlinkage int sys_getdomainname(char *n
 		goto done;
 	err = 0;
 done:
-	up(&uts_sem);
+	up_read(&uts_sem);
 	return err;
 }
 
--- linux/arch/sparc/kernel/sys_sunos.c.jj	Sun Jan 23 05:53:10 2000
+++ linux/arch/sparc/kernel/sys_sunos.c	Thu Jan 27 10:49:09 2000
@@ -581,7 +581,7 @@ struct sunos_utsname {
 asmlinkage int sunos_uname(struct sunos_utsname *name)
 {
 	int ret;
-	down(&uts_sem);
+	down_read(&uts_sem);
 	ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
 	if (!ret) {
 		ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
@@ -590,7 +590,7 @@ asmlinkage int sunos_uname(struct sunos_
 		ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
 		ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
 	}
-	up(&uts_sem);
+	up_read(&uts_sem);
 	return ret;
 }
 
--- linux/arch/sparc64/kernel/sys_sparc.c.jj	Fri Jan 21 12:39:06 2000
+++ linux/arch/sparc64/kernel/sys_sparc.c	Thu Jan 27 10:49:42 2000
@@ -248,7 +248,7 @@ asmlinkage int sys_getdomainname(char *n
         int nlen;
 	int err = -EFAULT;
 
- 	down(&uts_sem);
+ 	down_read(&uts_sem);
  	
 	nlen = strlen(system_utsname.domainname) + 1;
 
@@ -260,7 +260,7 @@ asmlinkage int sys_getdomainname(char *n
 		goto done;
 	err = 0;
 done:
-	up(&uts_sem);
+	up_read(&uts_sem);
 	return err;
 }
 
--- linux/arch/sparc64/kernel/sys_sunos32.c.jj	Fri Jan 21 12:39:03 2000
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Thu Jan 27 10:50:00 2000
@@ -543,14 +543,14 @@ asmlinkage int sunos_uname(struct sunos_
 {
 	int ret;
 
-	down(&uts_sem);
+	down_read(&uts_sem);
 	ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
 	ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
 	ret |= put_user('\0', &name->nname[8]);
 	ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
 	ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
 	ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
-	up(&uts_sem);
+	up_read(&uts_sem);
 	return ret;
 }
 
--- linux/arch/sparc64/solaris/misc.c.jj	Wed Jan 12 09:16:36 2000
+++ linux/arch/sparc64/solaris/misc.c	Thu Jan 27 10:53:22 2000
@@ -242,8 +242,10 @@ asmlinkage int solaris_utssys(u32 buf, u
 		/* Let's cheat */
 		set_utsfield(((struct sol_uname *)A(buf))->sysname, 
 			"SunOS", 1, 0);
+		down_read(&uts_sem);
 		set_utsfield(((struct sol_uname *)A(buf))->nodename, 
 			system_utsname.nodename, 1, 1);
+		up_read(&uts_sem);
 		set_utsfield(((struct sol_uname *)A(buf))->release, 
 			"2.6", 0, 0);
 		set_utsfield(((struct sol_uname *)A(buf))->version, 
@@ -263,7 +265,7 @@ asmlinkage int solaris_utssys(u32 buf, u
 asmlinkage int solaris_utsname(u32 buf)
 {
 	/* Why should we not lie a bit? */
-	down(&uts_sem);
+	down_read(&uts_sem);
 	set_utsfield(((struct sol_utsname *)A(buf))->sysname, 
 			"SunOS", 0, 0);
 	set_utsfield(((struct sol_utsname *)A(buf))->nodename, 
@@ -274,7 +276,7 @@ asmlinkage int solaris_utsname(u32 buf)
 			"Generic", 0, 0);
 	set_utsfield(((struct sol_utsname *)A(buf))->machine, 
 			machine(), 0, 0);
-	up(&uts_sem);
+	up_read(&uts_sem);
 	return 0;
 }
 
@@ -300,8 +302,10 @@ asmlinkage int solaris_sysinfo(int cmd, 
 	case SI_SYSNAME: r = "SunOS"; break;
 	case SI_HOSTNAME:
 		r = buffer + 256;
+		down_read(&uts_sem);
 		for (p = system_utsname.nodename, q = buffer; 
 		     q < r && *p && *p != '.'; *q++ = *p++);
+		up_read(&uts_sem);
 		*q = 0;
 		r = buffer;
 		break;
--- linux/drivers/sound/soundcard.c.jj	Thu Dec 16 07:48:08 1999
+++ linux/drivers/sound/soundcard.c	Thu Jan 27 10:54:05 2000
@@ -164,7 +164,7 @@ static int sound_proc_get_info(char *buf
 #define MODULEPROCSTRING "Driver compiled into kernel"
 #endif
 
-	down(&uts_sem);	
+	down_read(&uts_sem);	
 
 	len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n"
 		      "Load type: " MODULEPROCSTRING "\n"
@@ -172,7 +172,7 @@ static int sound_proc_get_info(char *buf
 		      "Config options: %x\n\nInstalled drivers: \n", 
 		      system_utsname.sysname, system_utsname.nodename, system_utsname.release, 
 		      system_utsname.version, system_utsname.machine, SELECTED_SOUND_OPTIONS);
-	up(&uts_sem);
+	up_read(&uts_sem);
 	
 	for (i = 0; (i < num_sound_drivers) && (pos <= offset + length); i++) {
 		if (!sound_drivers[i].card_type)
--- linux/include/asm-i386/semaphore.h.jj	Fri Jan  7 15:38:52 2000
+++ linux/include/asm-i386/semaphore.h	Thu Jan 27 10:36:26 2000
@@ -238,10 +238,17 @@ struct rw_semaphore {
 #define __RWSEM_DEBUG_INIT	/* */
 #endif
 
-#define __RWSEM_INITIALIZER(name) \
-{ ATOMIC_INIT(RW_LOCK_BIAS), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
+#define __RWSEM_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), 0, 0, 0, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
 	__WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
 	__SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
+
+#define __DECLARE_RWSEM_GENERIC(name,count) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
+
+#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
+#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
+#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
 
 extern inline void init_rwsem(struct rw_semaphore *sem)
 {
--- linux/include/asm-sparc/semaphore.h.jj	Tue Dec 28 12:12:11 1999
+++ linux/include/asm-sparc/semaphore.h	Thu Jan 27 10:35:20 2000
@@ -250,10 +250,17 @@ struct rw_semaphore {
 #define __RWSEM_DEBUG_INIT	/* */
 #endif
 
-#define __RWSEM_INITIALIZER(name) \
-{ RW_LOCK_BIAS, 0, 0xff, 0xff, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
+#define __RWSEM_INITIALIZER(name,count) \
+{ (count), 0, 0xff, 0xff, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
   __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
   __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
+
+#define __DECLARE_RWSEM_GENERIC(name,count) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
+
+#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
+#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
+#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
 
 extern inline void init_rwsem(struct rw_semaphore *sem)
 {
--- linux/include/asm-sparc64/semaphore.h.jj	Mon Jan 24 12:39:17 2000
+++ linux/include/asm-sparc64/semaphore.h	Thu Jan 27 10:35:39 2000
@@ -253,10 +253,17 @@ struct rw_semaphore {
 #define __RWSEM_DEBUG_INIT	/* */
 #endif
 
-#define __RWSEM_INITIALIZER(name) \
-{ RW_LOCK_BIAS, 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
+#define __RWSEM_INITIALIZER(name,count) \
+{ (count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
   __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
   __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
+
+#define __DECLARE_RWSEM_GENERIC(name,count) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
+
+#define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
+#define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
+#define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
 
 extern inline void init_rwsem(struct rw_semaphore *sem)
 {
--- linux/include/linux/utsname.h.jj	Wed Oct 13 08:11:41 1999
+++ linux/include/linux/utsname.h	Thu Jan 27 10:54:41 2000
@@ -32,5 +32,5 @@ struct new_utsname {
 
 extern struct new_utsname system_utsname;
 
-extern struct semaphore uts_sem;
+extern struct rw_semaphore uts_sem;
 #endif
--- linux/kernel/sys.c.jj	Fri Jan 21 10:58:47 2000
+++ linux/kernel/sys.c	Thu Jan 27 10:38:52 2000
@@ -821,21 +821,16 @@ out:
 	return 1;
 }
 
-/*
- * This should really be a blocking read-write lock
- * rather than a semaphore. Anybody want to implement
- * one?
- */
-DECLARE_MUTEX(uts_sem);
+DECLARE_RWSEM(uts_sem);
 
 asmlinkage long sys_newuname(struct new_utsname * name)
 {
 	int errno = 0;
 
-	down(&uts_sem);
+	down_read(&uts_sem);
 	if (copy_to_user(name,&system_utsname,sizeof *name))
 		errno = -EFAULT;
-	up(&uts_sem);
+	up_read(&uts_sem);
 	return errno;
 }
 
@@ -847,13 +842,13 @@ asmlinkage long sys_sethostname(char *na
 		return -EPERM;
 	if (len < 0 || len > __NEW_UTS_LEN)
 		return -EINVAL;
-	down(&uts_sem);
+	down_write(&uts_sem);
 	errno = -EFAULT;
 	if (!copy_from_user(system_utsname.nodename, name, len)) {
 		system_utsname.nodename[len] = 0;
 		errno = 0;
 	}
-	up(&uts_sem);
+	up_write(&uts_sem);
 	return errno;
 }
 
@@ -863,14 +858,14 @@ asmlinkage long sys_gethostname(char *na
 
 	if (len < 0)
 		return -EINVAL;
-	down(&uts_sem);
+	down_read(&uts_sem);
 	i = 1 + strlen(system_utsname.nodename);
 	if (i > len)
 		i = len;
 	errno = 0;
 	if (copy_to_user(name, system_utsname.nodename, i))
 		errno = -EFAULT;
-	up(&uts_sem);
+	up_read(&uts_sem);
 	return errno;
 }
 
@@ -887,13 +882,13 @@ asmlinkage long sys_setdomainname(char *
 	if (len < 0 || len > __NEW_UTS_LEN)
 		return -EINVAL;
 
-	down(&uts_sem);
+	down_write(&uts_sem);
 	errno = -EFAULT;
 	if (!copy_from_user(system_utsname.domainname, name, len)) {
 		errno = 0;
 		system_utsname.domainname[len] = 0;
 	}
-	up(&uts_sem);
+	up_write(&uts_sem);
 	return errno;
 }
 
--- linux/kernel/sysctl.c.jj	Fri Jan 14 09:44:36 2000
+++ linux/kernel/sysctl.c	Thu Jan 27 11:05:20 2000
@@ -722,9 +722,16 @@ static int proc_doutsstring(ctl_table *t
 		  void *buffer, size_t *lenp)
 {
 	int r;
-	down(&uts_sem);
-	r=proc_dostring(table,write,filp,buffer,lenp);
-	up(&uts_sem);
+
+	if (!write) {
+		down_read(&uts_sem);
+		r=proc_dostring(table,0,filp,buffer,lenp);
+		up_read(&uts_sem);
+	} else {
+		down_write(&uts_sem);
+		r=proc_dostring(table,1,filp,buffer,lenp);
+		up_write(&uts_sem);
+	}
 	return r;
 }
 

Cheers,
    Jakub
___________________________________________________________________
Jakub Jelinek | jakub en redhat.com | http://sunsite.mff.cuni.cz/~jj
Linux version 2.3.41 on a sparc64 machine (1343.49 BogoMips)
___________________________________________________________________

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo en vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



Más información sobre la lista de distribución Ayuda