svn commit: r265847 - head/lib/libc/gen

Konstantin Belousov kib at FreeBSD.org
Sat May 10 19:08:08 UTC 2014


Author: kib
Date: Sat May 10 19:08:07 2014
New Revision: 265847
URL: http://svnweb.freebsd.org/changeset/base/265847

Log:
  Invalidate the cache for the named posix semaphore when opened and
  actual file storing the semaphore object is different from the file
  created on the first open.  Store the file st_dev and st_ino members
  of the struct stat in the semaphore structure on open, and compare
  them with the attributes of the opened file to detect unlink and
  re-creation.
  
  This fixes an issue of sem_unlink(3) failing to flush the named entry
  in the semaphore list for the current or remote process, making
  sem_unlink(3) not correctly operating if the unlinked semaphore is
  still opened.
  
  Reported by:	Joris Giovannangeli <joris at giovannangeli.fr>
  PR:	standards/189353
  Reviewed by:	jilles (previous version)
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week

Modified:
  head/lib/libc/gen/sem_new.c

Modified: head/lib/libc/gen/sem_new.c
==============================================================================
--- head/lib/libc/gen/sem_new.c	Sat May 10 19:06:36 2014	(r265846)
+++ head/lib/libc/gen/sem_new.c	Sat May 10 19:08:07 2014	(r265847)
@@ -66,6 +66,8 @@ __weak_reference(_sem_wait, sem_wait);
 struct sem_nameinfo {
 	int open_count;
 	char *name;
+	dev_t dev;
+	ino_t ino;
 	sem_t *sem;
 	LIST_ENTRY(sem_nameinfo) next;
 };
@@ -151,37 +153,46 @@ _sem_open(const char *name, int flags, .
 		return (SEM_FAILED);
 	}
 	name++;
-
+	strcpy(path, SEM_PREFIX);
+	if (strlcat(path, name, sizeof(path)) >= sizeof(path)) {
+		errno = ENAMETOOLONG;
+		return (SEM_FAILED);
+	}
 	if (flags & ~(O_CREAT|O_EXCL)) {
 		errno = EINVAL;
 		return (SEM_FAILED);
 	}
-
+	if ((flags & O_CREAT) != 0) {
+		va_start(ap, flags);
+		mode = va_arg(ap, int);
+		value = va_arg(ap, int);
+		va_end(ap);
+	}
+	fd = -1;
 	_pthread_once(&once, sem_module_init);
 
 	_pthread_mutex_lock(&sem_llock);
 	LIST_FOREACH(ni, &sem_list, next) {
-		if (strcmp(name, ni->name) == 0) {
-			if ((flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) {
-				_pthread_mutex_unlock(&sem_llock);
-				errno = EEXIST;
-				return (SEM_FAILED);
-			} else {
-				ni->open_count++;
-				sem = ni->sem;
-				_pthread_mutex_unlock(&sem_llock);
-				return (sem);
+		if (ni->name != NULL && strcmp(name, ni->name) == 0) {
+			fd = _open(path, flags | O_RDWR | O_CLOEXEC |
+			    O_EXLOCK, mode);
+			if (fd == -1 || _fstat(fd, &sb) == -1)
+				goto error;
+			if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT |
+			    O_EXCL) || ni->dev != sb.st_dev ||
+			    ni->ino != sb.st_ino) {
+				ni->name = NULL;
+				ni = NULL;
+				break;
 			}
+			ni->open_count++;
+			sem = ni->sem;
+			_pthread_mutex_unlock(&sem_llock);
+			_close(fd);
+			return (sem);
 		}
 	}
 
-	if (flags & O_CREAT) {
-		va_start(ap, flags);
-		mode = va_arg(ap, int);
-		value = va_arg(ap, int);
-		va_end(ap);
-	}
-
 	len = sizeof(*ni) + strlen(name) + 1;
 	ni = (struct sem_nameinfo *)malloc(len);
 	if (ni == NULL) {
@@ -192,17 +203,11 @@ _sem_open(const char *name, int flags, .
 	ni->name = (char *)(ni+1);
 	strcpy(ni->name, name);
 
-	strcpy(path, SEM_PREFIX);
-	if (strlcat(path, name, sizeof(path)) >= sizeof(path)) {
-		errno = ENAMETOOLONG;
-		goto error;
+	if (fd == -1) {
+		fd = _open(path, flags | O_RDWR | O_CLOEXEC | O_EXLOCK, mode);
+		if (fd == -1 || _fstat(fd, &sb) == -1)
+			goto error;
 	}
-
-	fd = _open(path, flags|O_RDWR|O_CLOEXEC|O_EXLOCK, mode);
-	if (fd == -1)
-		goto error;
-	if (_fstat(fd, &sb))
-		goto error;
 	if (sb.st_size < sizeof(sem_t)) {
 		sem_t tmp;
 
@@ -228,6 +233,8 @@ _sem_open(const char *name, int flags, .
 	}
 	ni->open_count = 1;
 	ni->sem = sem;
+	ni->dev = sb.st_dev;
+	ni->ino = sb.st_ino;
 	LIST_INSERT_HEAD(&sem_list, ni, next);
 	_close(fd);
 	_pthread_mutex_unlock(&sem_llock);


More information about the svn-src-head mailing list