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
This commit is contained in:
parent
8207fd5f81
commit
ca5e4fe970
@ -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,36 +153,45 @@ _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);
|
||||
}
|
||||
|
||||
_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 (flags & O_CREAT) {
|
||||
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 (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);
|
||||
}
|
||||
}
|
||||
|
||||
len = sizeof(*ni) + strlen(name) + 1;
|
||||
ni = (struct sem_nameinfo *)malloc(len);
|
||||
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user