Linux-kernel mailing list archive 2000-04,: [PATCH] uts_sem as RW semaphore

# [PATCH] uts_sem as RW semaphore

Jakub Jelinek (jakub@redhat.com)
Thu, 27 Jan 2000 12:04:05 +0100

- Messages sorted by: [ date ][ thread ][ subject ][ author ]
- Next message: Catalin BOIE: "Re: 2GB limit (more info)?"
- Previous message: Martin Schulz: "Re: 2GB limit?"

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/

- Next message: Catalin BOIE: "Re: 2GB limit (more info)?"
- Previous message: Martin Schulz: "Re: 2GB limit?"