summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2014-05-10 19:08:07 +0000
committerkib <kib@FreeBSD.org>2014-05-10 19:08:07 +0000
commite86f4c348276e0fec90c66af0830ba55e3df88bd (patch)
treee65795625dddc9838ed28b287c6fc0d1ec4da0c8
parent469deb4b788d60bc3320f434808d3b0fac6ffd94 (diff)
downloadFreeBSD-src-e86f4c348276e0fec90c66af0830ba55e3df88bd.zip
FreeBSD-src-e86f4c348276e0fec90c66af0830ba55e3df88bd.tar.gz
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@giovannangeli.fr> PR: standards/189353 Reviewed by: jilles (previous version) Sponsored by: The FreeBSD Foundation MFC after: 1 week
-rw-r--r--lib/libc/gen/sem_new.c65
1 files changed, 36 insertions, 29 deletions
diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c
index f196006..ec1a2fd 100644
--- a/lib/libc/gen/sem_new.c
+++ b/lib/libc/gen/sem_new.c
@@ -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);
OpenPOWER on IntegriCloud