[PATCH] uts_sem as RW semaphore

From: Jakub Jelinek (jakub@redhat.com)
Date: Thu Jan 27 2000 - 06:04:05 EST


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@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@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Mon Jan 31 2000 - 21:00:18 EST