diff options
author | Kurt Miller <kurt@cvs.openbsd.org> | 2008-06-03 14:45:06 +0000 |
---|---|---|
committer | Kurt Miller <kurt@cvs.openbsd.org> | 2008-06-03 14:45:06 +0000 |
commit | 4af9874148b61feb347eb59c1200da38653576c1 (patch) | |
tree | b435ad4a013d336332b7c2542765b8c2d4276f67 | |
parent | e70f08b5652c86aa41ffd6d501e1cd28172dc64b (diff) |
Don't grab the fd read lock for getsockopt(2), setsockopt(2),
getpeername(2) or getsockname(2). Its not needed and causes
threads to block when another thread is blocked and holding the
read lock. Instead just protect against fd state transitions.
Blocking problem reported by David S H Rosenthal from lockss.org
okay beck@ "looks sane" deraadt@
-rw-r--r-- | lib/libpthread/uthread/uthread_getpeername.c | 22 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_getsockname.c | 22 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_getsockopt.c | 20 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_setsockopt.c | 20 |
4 files changed, 66 insertions, 18 deletions
diff --git a/lib/libpthread/uthread/uthread_getpeername.c b/lib/libpthread/uthread/uthread_getpeername.c index 378f23f7416..7a026a6885c 100644 --- a/lib/libpthread/uthread/uthread_getpeername.c +++ b/lib/libpthread/uthread/uthread_getpeername.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_getpeername.c,v 1.4 1999/11/25 07:01:36 d Exp $ */ +/* $OpenBSD: uthread_getpeername.c,v 1.5 2008/06/03 14:45:05 kurt Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -32,6 +32,7 @@ * * $FreeBSD: uthread_getpeername.c,v 1.5 1999/08/28 00:03:34 peter Exp $ */ +#include <errno.h> #include <sys/types.h> #include <sys/socket.h> #ifdef _THREAD_SAFE @@ -41,12 +42,23 @@ int getpeername(int fd, struct sockaddr * peer, socklen_t *paddrlen) { - int ret; + int ret; + struct fd_table_entry *entry; - if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { - ret = _thread_sys_getpeername(fd, peer, paddrlen); - _FD_UNLOCK(fd, FD_READ); + ret = _thread_fd_table_init(fd, FD_INIT_UNKNOWN, NULL); + if (ret == 0) { + entry = _thread_fd_table[fd]; + + _SPINLOCK(&entry->lock); + if (entry->state == FD_ENTRY_OPEN) { + ret = _thread_sys_getpeername(fd, peer, paddrlen); + } else { + ret = -1; + errno = EBADF; + } + _SPINUNLOCK(&entry->lock); } + return ret; } #endif diff --git a/lib/libpthread/uthread/uthread_getsockname.c b/lib/libpthread/uthread/uthread_getsockname.c index 683cc910f15..22ad8075c8e 100644 --- a/lib/libpthread/uthread/uthread_getsockname.c +++ b/lib/libpthread/uthread/uthread_getsockname.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_getsockname.c,v 1.4 1999/11/25 07:01:36 d Exp $ */ +/* $OpenBSD: uthread_getsockname.c,v 1.5 2008/06/03 14:45:05 kurt Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -32,6 +32,7 @@ * * $FreeBSD: uthread_getsockname.c,v 1.5 1999/08/28 00:03:36 peter Exp $ */ +#include <errno.h> #include <sys/types.h> #include <sys/socket.h> #ifdef _THREAD_SAFE @@ -39,14 +40,25 @@ #include "pthread_private.h" int -getsockname(int s, struct sockaddr * name, socklen_t *namelen) +getsockname(int fd, struct sockaddr * name, socklen_t *namelen) { int ret; + struct fd_table_entry *entry; - if ((ret = _FD_LOCK(s, FD_READ, NULL)) == 0) { - ret = _thread_sys_getsockname(s, name, namelen); - _FD_UNLOCK(s, FD_READ); + ret = _thread_fd_table_init(fd, FD_INIT_UNKNOWN, NULL); + if (ret == 0) { + entry = _thread_fd_table[fd]; + + _SPINLOCK(&entry->lock); + if (entry->state == FD_ENTRY_OPEN) { + ret = _thread_sys_getsockname(fd, name, namelen); + } else { + ret = -1; + errno = EBADF; + } + _SPINUNLOCK(&entry->lock); } + return ret; } #endif diff --git a/lib/libpthread/uthread/uthread_getsockopt.c b/lib/libpthread/uthread/uthread_getsockopt.c index f73b54780ea..09d31955652 100644 --- a/lib/libpthread/uthread/uthread_getsockopt.c +++ b/lib/libpthread/uthread/uthread_getsockopt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_getsockopt.c,v 1.4 1999/11/25 07:01:36 d Exp $ */ +/* $OpenBSD: uthread_getsockopt.c,v 1.5 2008/06/03 14:45:05 kurt Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -32,6 +32,7 @@ * * $FreeBSD: uthread_getsockopt.c,v 1.5 1999/08/28 00:03:36 peter Exp $ */ +#include <errno.h> #include <sys/types.h> #include <sys/socket.h> #ifdef _THREAD_SAFE @@ -42,11 +43,22 @@ int getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) { int ret; + struct fd_table_entry *entry; - if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { - ret = _thread_sys_getsockopt(fd, level, optname, optval, optlen); - _FD_UNLOCK(fd, FD_RDWR); + ret = _thread_fd_table_init(fd, FD_INIT_UNKNOWN, NULL); + if (ret == 0) { + entry = _thread_fd_table[fd]; + + _SPINLOCK(&entry->lock); + if (entry->state == FD_ENTRY_OPEN) { + ret = _thread_sys_getsockopt(fd, level, optname, optval, optlen); + } else { + ret = -1; + errno = EBADF; + } + _SPINUNLOCK(&entry->lock); } + return ret; } #endif diff --git a/lib/libpthread/uthread/uthread_setsockopt.c b/lib/libpthread/uthread/uthread_setsockopt.c index 77cda0a65c1..bf6041985be 100644 --- a/lib/libpthread/uthread/uthread_setsockopt.c +++ b/lib/libpthread/uthread/uthread_setsockopt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uthread_setsockopt.c,v 1.4 1999/11/25 07:01:44 d Exp $ */ +/* $OpenBSD: uthread_setsockopt.c,v 1.5 2008/06/03 14:45:05 kurt Exp $ */ /* * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> * All rights reserved. @@ -32,6 +32,7 @@ * * $FreeBSD: uthread_setsockopt.c,v 1.5 1999/08/28 00:03:47 peter Exp $ */ +#include <errno.h> #include <sys/types.h> #include <sys/socket.h> #ifdef _THREAD_SAFE @@ -42,11 +43,22 @@ int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) { int ret; + struct fd_table_entry *entry; - if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { - ret = _thread_sys_setsockopt(fd, level, optname, optval, optlen); - _FD_UNLOCK(fd, FD_RDWR); + ret = _thread_fd_table_init(fd, FD_INIT_UNKNOWN, NULL); + if (ret == 0) { + entry = _thread_fd_table[fd]; + + _SPINLOCK(&entry->lock); + if (entry->state == FD_ENTRY_OPEN) { + ret = _thread_sys_setsockopt(fd, level, optname, optval, optlen); + } else { + ret = -1; + errno = EBADF; + } + _SPINUNLOCK(&entry->lock); } + return ret; } #endif |