git: e20ed58d265c - main - lockf: Truncate the active lock list earlier in lf_purgelocks()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 21 Sep 2026 14:23:47 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=e20ed58d265cd6eba9b28efc8e8956324937d4c3
commit e20ed58d265cd6eba9b28efc8e8956324937d4c3
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-09-21 14:14:45 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-09-21 14:14:45 +0000
lockf: Truncate the active lock list earlier in lf_purgelocks()
Otherwise vfs_report_lockf() can race with lf_purgelocks() while the
latter is freeing active lock entries without any locks held.
Reviewed by: kib
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D59768
---
sys/kern/kern_lockf.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/sys/kern/kern_lockf.c b/sys/kern/kern_lockf.c
index a1aee233fdbd..a318c26484b4 100644
--- a/sys/kern/kern_lockf.c
+++ b/sys/kern/kern_lockf.c
@@ -752,6 +752,7 @@ lf_purgelocks(struct vnode *vp, struct lockf **statep)
{
struct lockf *state;
struct lockf_entry *lock, *nlock;
+ struct lockf_entry_list active;
/*
* For this to work correctly, the caller must ensure that no
@@ -778,6 +779,7 @@ lf_purgelocks(struct vnode *vp, struct lockf **statep)
state->ls_threads++;
VI_UNLOCK(vp);
+ LIST_INIT(&active);
sx_xlock(&state->ls_lock);
sx_xlock(&lf_owner_graph_lock);
LIST_FOREACH_SAFE(lock, &state->ls_pending, lf_link, nlock) {
@@ -797,6 +799,7 @@ lf_purgelocks(struct vnode *vp, struct lockf **statep)
wakeup(lock);
}
}
+ LIST_SWAP(&active, &state->ls_active, lockf_entry, lf_link);
sx_xunlock(&lf_owner_graph_lock);
sx_xunlock(&state->ls_lock);
@@ -810,19 +813,17 @@ lf_purgelocks(struct vnode *vp, struct lockf **statep)
VI_UNLOCK(vp);
/*
- * We can just free all the active locks since they
- * will have no dependencies (we removed them all
- * above). We don't need to bother locking since we
- * are the last thread using this state structure.
+ * We can just free all the active locks since they will have no
+ * dependencies (we removed them all above).
*/
- KASSERT(LIST_EMPTY(&state->ls_pending),
- ("lock pending for %p", state));
- LIST_FOREACH_SAFE(lock, &state->ls_active, lf_link, nlock) {
+ LIST_FOREACH_SAFE(lock, &active, lf_link, nlock) {
LIST_REMOVE(lock, lf_link);
lf_free_lock(lock);
}
out_free:
sx_xlock(&lf_lock_states_lock);
+ KASSERT(LIST_EMPTY(&state->ls_pending), ("lock pending for %p", state));
+ KASSERT(LIST_EMPTY(&state->ls_active), ("lock active for %p", state));
LIST_REMOVE(state, ls_link);
sx_xunlock(&lf_lock_states_lock);
sx_destroy(&state->ls_lock);