Fixed the race condition in acquire_advisory_lock() by using the new switch_sem() function.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@11888 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-03-17 22:55:20 +00:00
parent 34e92cad76
commit 0a99f533c2
+16 -16
View File
@@ -113,7 +113,7 @@ struct fs_mount {
}; };
struct advisory_locking { struct advisory_locking {
struct mutex mutex; sem_id lock;
sem_id wait_sem; sem_id wait_sem;
struct list locks; struct list locks;
}; };
@@ -845,9 +845,11 @@ create_advisory_locking(struct vnode *vnode)
goto err1; goto err1;
} }
status = mutex_init(&locking->mutex, "advisory locking"); locking->lock = create_sem(1, "advisory locking");
if (status < B_OK) if (locking->lock < B_OK) {
status = locking->lock;
goto err2; goto err2;
}
list_init(&locking->locks); list_init(&locking->locks);
vnode->advisory_locking = locking; vnode->advisory_locking = locking;
@@ -864,7 +866,7 @@ err1:
static inline void static inline void
put_advisory_locking(struct advisory_locking *locking) put_advisory_locking(struct advisory_locking *locking)
{ {
mutex_unlock(&locking->mutex); release_sem(locking->lock);
} }
@@ -875,7 +877,7 @@ get_advisory_locking(struct vnode *vnode)
struct advisory_locking *locking = vnode->advisory_locking; struct advisory_locking *locking = vnode->advisory_locking;
if (locking != NULL) if (locking != NULL)
mutex_lock(&locking->mutex); acquire_sem(locking->lock);
mutex_unlock(&sVnodeMutex); mutex_unlock(&sVnodeMutex);
return locking; return locking;
@@ -933,21 +935,21 @@ release_advisory_lock(struct vnode *vnode, struct flock *flock)
mutex_lock(&sVnodeMutex); mutex_lock(&sVnodeMutex);
locking = vnode->advisory_locking; locking = vnode->advisory_locking;
if (locking != NULL) if (locking != NULL)
mutex_lock(&locking->mutex); acquire_sem(locking->lock);
// the locking could have been changed in the mean time // the locking could have been changed in the mean time
if (list_is_empty(&locking->locks)) if (list_is_empty(&locking->locks))
vnode->advisory_locking = NULL; vnode->advisory_locking = NULL;
else { else {
removeLocking = false; removeLocking = false;
mutex_unlock(&locking->mutex); release_sem_etc(locking->lock, 1, B_DO_NOT_RESCHEDULE);
} }
mutex_unlock(&sVnodeMutex); mutex_unlock(&sVnodeMutex);
} }
if (removeLocking) { if (removeLocking) {
// we've detached the locking from the vnode, so we can safely delete it // we've detached the locking from the vnode, so we can safely delete it
mutex_destroy(&locking->mutex); delete_sem(locking->lock);
delete_sem(locking->wait_sem); delete_sem(locking->wait_sem);
free(locking); free(locking);
} }
@@ -986,7 +988,8 @@ restart:
} }
} }
put_advisory_locking(locking); if (waitForLock < B_OK || !wait)
put_advisory_locking(locking);
} }
// wait for the lock if we have to, or else return immediately // wait for the lock if we have to, or else return immediately
@@ -995,10 +998,7 @@ restart:
if (!wait) if (!wait)
status = B_PERMISSION_DENIED; status = B_PERMISSION_DENIED;
else { else {
// ToDo: this is the standard condvar problem; there is a big race status = switch_sem_etc(locking->lock, waitForLock, 1, B_CAN_INTERRUPT, 0);
// condition here: between here and the put_advisory_locking() call
// above, a release could already have happened!
status = acquire_sem_etc(waitForLock, 1, B_CAN_INTERRUPT, 0);
if (status == B_OK) { if (status == B_OK) {
// see if we're still colliding // see if we're still colliding
goto restart; goto restart;
@@ -1020,7 +1020,7 @@ restart:
} }
if (locking != NULL) if (locking != NULL)
mutex_lock(&locking->mutex); acquire_sem(locking->lock);
mutex_unlock(&sVnodeMutex); mutex_unlock(&sVnodeMutex);
@@ -1031,7 +1031,7 @@ restart:
if (lock == NULL) { if (lock == NULL) {
if (waitForLock >= B_OK) if (waitForLock >= B_OK)
release_sem_etc(waitForLock, 1, B_RELEASE_ALL); release_sem_etc(waitForLock, 1, B_RELEASE_ALL);
mutex_unlock(&locking->mutex); release_sem(locking->lock);
return B_NO_MEMORY; return B_NO_MEMORY;
} }
@@ -1042,7 +1042,7 @@ restart:
lock->shared = shared; lock->shared = shared;
list_add_item(&locking->locks, lock); list_add_item(&locking->locks, lock);
mutex_unlock(&locking->mutex); release_sem(locking->lock);
return status; return status;
} }