mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-12 09:58:36 +00:00
Protect against a race between granting a lock and accessing
other parts of the lock. Submitted by: davidxu
This commit is contained in:
parent
0eda4c08a5
commit
c72cd7c9e2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=114680
@ -65,6 +65,7 @@ _lock_init(struct lock *lck, enum lock_type ltype,
|
||||
lck->l_head->lr_watcher = NULL;
|
||||
lck->l_head->lr_owner = NULL;
|
||||
lck->l_head->lr_waiting = 0;
|
||||
lck->l_head->lr_handshake = 0;
|
||||
lck->l_tail = lck->l_head;
|
||||
}
|
||||
return (0);
|
||||
@ -84,6 +85,7 @@ _lockuser_init(struct lockuser *lu, void *priv)
|
||||
lu->lu_myreq->lr_watcher = NULL;
|
||||
lu->lu_myreq->lr_owner = lu;
|
||||
lu->lu_myreq->lr_waiting = 0;
|
||||
lu->lu_myreq->lr_handshake = 0;
|
||||
lu->lu_watchreq = NULL;
|
||||
lu->lu_priority = 0;
|
||||
lu->lu_private = priv;
|
||||
@ -169,6 +171,12 @@ _lock_acquire(struct lock *lck, struct lockuser *lu, int prio)
|
||||
while (lu->lu_watchreq->lr_locked != 0)
|
||||
lck->l_wait(lck, lu);
|
||||
atomic_store_rel_long(&lu->lu_watchreq->lr_waiting, 0);
|
||||
/*
|
||||
* Wait for original owner to stop accessing the
|
||||
* lockreq object.
|
||||
*/
|
||||
while (lu->lu_watchreq->lr_handshake)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -232,19 +240,24 @@ _lock_release(struct lock *lck, struct lockuser *lu)
|
||||
}
|
||||
}
|
||||
if (lu_h != NULL) {
|
||||
lu_h->lu_watchreq->lr_handshake = 1;
|
||||
/* Give the lock to the highest priority user. */
|
||||
atomic_store_rel_long(&lu_h->lu_watchreq->lr_locked, 0);
|
||||
if ((lu_h->lu_watchreq->lr_waiting != 0) &&
|
||||
(lck->l_wakeup != NULL))
|
||||
/* Notify the sleeper */
|
||||
lck->l_wakeup(lck, lu_h->lu_myreq->lr_watcher);
|
||||
atomic_store_rel_long(&lu_h->lu_watchreq->lr_handshake,
|
||||
0);
|
||||
} else {
|
||||
myreq->lr_handshake = 1;
|
||||
/* Give the lock to the previous request. */
|
||||
atomic_store_rel_long(&myreq->lr_locked, 0);
|
||||
if ((myreq->lr_waiting != 0) &&
|
||||
(lck->l_wakeup != NULL))
|
||||
/* Notify the sleeper */
|
||||
lck->l_wakeup(lck, myreq->lr_watcher);
|
||||
atomic_store_rel_long(&myreq->lr_handshake, 0);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@ -257,12 +270,19 @@ _lock_release(struct lock *lck, struct lockuser *lu)
|
||||
lu->lu_watchreq = NULL;
|
||||
lu->lu_myreq->lr_locked = 1;
|
||||
lu->lu_myreq->lr_waiting = 0;
|
||||
/* Give the lock to the previous request. */
|
||||
atomic_store_rel_long(&myreq->lr_locked, 0);
|
||||
if ((myreq->lr_waiting != 0) &&
|
||||
(lck->l_wakeup != NULL))
|
||||
/* Notify the sleeper */
|
||||
lck->l_wakeup(lck, myreq->lr_watcher);
|
||||
|
||||
if (lck->l_wakeup) {
|
||||
/* Start wakeup */
|
||||
myreq->lr_handshake = 1;
|
||||
/* Give the lock to the previous request. */
|
||||
atomic_store_rel_long(&myreq->lr_locked, 0);
|
||||
if (myreq->lr_waiting != 0) {
|
||||
/* Notify the sleeper */
|
||||
lck->l_wakeup(lck, myreq->lr_watcher);
|
||||
}
|
||||
/* Stop wakeup */
|
||||
atomic_store_rel_long(&myreq->lr_handshake, 0);
|
||||
} else {
|
||||
atomic_store_rel_long(&myreq->lr_locked, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ struct lockreq {
|
||||
struct lockuser *lr_watcher; /* only used for priority locks */
|
||||
struct lockuser *lr_owner; /* only used for priority locks */
|
||||
long lr_waiting; /* non-zero when wakeup needed */
|
||||
volatile long lr_handshake; /* non-zero when wakeup in progress */
|
||||
};
|
||||
|
||||
struct lockuser {
|
||||
|
@ -65,6 +65,7 @@ _lock_init(struct lock *lck, enum lock_type ltype,
|
||||
lck->l_head->lr_watcher = NULL;
|
||||
lck->l_head->lr_owner = NULL;
|
||||
lck->l_head->lr_waiting = 0;
|
||||
lck->l_head->lr_handshake = 0;
|
||||
lck->l_tail = lck->l_head;
|
||||
}
|
||||
return (0);
|
||||
@ -84,6 +85,7 @@ _lockuser_init(struct lockuser *lu, void *priv)
|
||||
lu->lu_myreq->lr_watcher = NULL;
|
||||
lu->lu_myreq->lr_owner = lu;
|
||||
lu->lu_myreq->lr_waiting = 0;
|
||||
lu->lu_myreq->lr_handshake = 0;
|
||||
lu->lu_watchreq = NULL;
|
||||
lu->lu_priority = 0;
|
||||
lu->lu_private = priv;
|
||||
@ -169,6 +171,12 @@ _lock_acquire(struct lock *lck, struct lockuser *lu, int prio)
|
||||
while (lu->lu_watchreq->lr_locked != 0)
|
||||
lck->l_wait(lck, lu);
|
||||
atomic_store_rel_long(&lu->lu_watchreq->lr_waiting, 0);
|
||||
/*
|
||||
* Wait for original owner to stop accessing the
|
||||
* lockreq object.
|
||||
*/
|
||||
while (lu->lu_watchreq->lr_handshake)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -232,19 +240,24 @@ _lock_release(struct lock *lck, struct lockuser *lu)
|
||||
}
|
||||
}
|
||||
if (lu_h != NULL) {
|
||||
lu_h->lu_watchreq->lr_handshake = 1;
|
||||
/* Give the lock to the highest priority user. */
|
||||
atomic_store_rel_long(&lu_h->lu_watchreq->lr_locked, 0);
|
||||
if ((lu_h->lu_watchreq->lr_waiting != 0) &&
|
||||
(lck->l_wakeup != NULL))
|
||||
/* Notify the sleeper */
|
||||
lck->l_wakeup(lck, lu_h->lu_myreq->lr_watcher);
|
||||
atomic_store_rel_long(&lu_h->lu_watchreq->lr_handshake,
|
||||
0);
|
||||
} else {
|
||||
myreq->lr_handshake = 1;
|
||||
/* Give the lock to the previous request. */
|
||||
atomic_store_rel_long(&myreq->lr_locked, 0);
|
||||
if ((myreq->lr_waiting != 0) &&
|
||||
(lck->l_wakeup != NULL))
|
||||
/* Notify the sleeper */
|
||||
lck->l_wakeup(lck, myreq->lr_watcher);
|
||||
atomic_store_rel_long(&myreq->lr_handshake, 0);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@ -257,12 +270,19 @@ _lock_release(struct lock *lck, struct lockuser *lu)
|
||||
lu->lu_watchreq = NULL;
|
||||
lu->lu_myreq->lr_locked = 1;
|
||||
lu->lu_myreq->lr_waiting = 0;
|
||||
/* Give the lock to the previous request. */
|
||||
atomic_store_rel_long(&myreq->lr_locked, 0);
|
||||
if ((myreq->lr_waiting != 0) &&
|
||||
(lck->l_wakeup != NULL))
|
||||
/* Notify the sleeper */
|
||||
lck->l_wakeup(lck, myreq->lr_watcher);
|
||||
|
||||
if (lck->l_wakeup) {
|
||||
/* Start wakeup */
|
||||
myreq->lr_handshake = 1;
|
||||
/* Give the lock to the previous request. */
|
||||
atomic_store_rel_long(&myreq->lr_locked, 0);
|
||||
if (myreq->lr_waiting != 0) {
|
||||
/* Notify the sleeper */
|
||||
lck->l_wakeup(lck, myreq->lr_watcher);
|
||||
}
|
||||
/* Stop wakeup */
|
||||
atomic_store_rel_long(&myreq->lr_handshake, 0);
|
||||
} else {
|
||||
atomic_store_rel_long(&myreq->lr_locked, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ struct lockreq {
|
||||
struct lockuser *lr_watcher; /* only used for priority locks */
|
||||
struct lockuser *lr_owner; /* only used for priority locks */
|
||||
long lr_waiting; /* non-zero when wakeup needed */
|
||||
volatile long lr_handshake; /* non-zero when wakeup in progress */
|
||||
};
|
||||
|
||||
struct lockuser {
|
||||
|
Loading…
Reference in New Issue
Block a user