path: root/sys/sys/unpcb.h
diff options
authorJason A. Harmening <jah@FreeBSD.org>2020-01-25 08:57:26 +0000
committerJason A. Harmening <jah@FreeBSD.org>2020-01-25 08:57:26 +0000
commita9aa06f7b1c607cd2410886aee467a8e79b74461 (patch)
tree6dffe34e90fd0a45ab0e2ed60e296851aa2bc0fa /sys/sys/unpcb.h
parent0db2ca0c31983b2ca94e57b695a0b29277ab2daf (diff)
Implement cycle-detecting garbage collector for AF_UNIX sockets
The existing AF_UNIX socket garbage collector destroys any socket which may potentially be in a cycle, as indicated by its file reference count being equal to its enqueue count. However, this can produce false positives for in-flight sockets which aren't part of a cycle but are part of one or more SCM_RIGHTS mssages and which have been closed on the sending side. If the garbage collector happens to run at exactly the wrong time, destruction of these sockets will render them unusable on the receiving side, such that no previously-written data may be read. This change rewrites the garbage collector to precisely detect cycles: 1. The existing check of msgcount==f_count is still used to determine whether the socket is potentially in a cycle. 2. The socket is now placed on a local "dead list", which is used to reduce iteration time (and therefore contention on the global unp_link_rwlock). 3. The first pass through the dead list removes each potentially-dead socket's outgoing references from the graph of potentially-dead sockets, using a gc-specific copy of the original reference count. 4. The second series of passes through the dead list removes from the list any socket whose remaining gc refcount is non-zero, as this indicates the socket is actually accessible outside of any possible cycle. Iteration is repeated until no further sockets are removed from the dead list. 5. Sockets remaining in the dead list are destroyed as before. PR: 227285 Submitted by: jan.kokemueller@gmail.com (prior version) Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D23142
Notes: svn path=/head/; revision=357110
Diffstat (limited to 'sys/sys/unpcb.h')
1 files changed, 4 insertions, 4 deletions
diff --git a/sys/sys/unpcb.h b/sys/sys/unpcb.h
index 6bd36e8e5801..515355e80374 100644
--- a/sys/sys/unpcb.h
+++ b/sys/sys/unpcb.h
@@ -86,7 +86,9 @@ struct unpcb {
unp_gen_t unp_gencnt; /* generation count of this instance */
struct file *unp_file; /* back-pointer to file for gc. */
u_int unp_msgcount; /* references from message queue */
+ u_int unp_gcrefs; /* garbage collector refcount */
ino_t unp_ino; /* fake inode number */
+ LIST_ENTRY(unpcb) unp_dead; /* link in dead list */
} __aligned(CACHE_LINE_SIZE);
@@ -113,10 +115,8 @@ struct unpcb {
* Flags in unp_gcflag.
-#define UNPGC_REF 0x1 /* unpcb has external ref. */
-#define UNPGC_DEAD 0x2 /* unpcb might be dead. */
-#define UNPGC_SCANNED 0x4 /* Has been scanned. */
-#define UNPGC_IGNORE_RIGHTS 0x8 /* Attached rights are freed */
+#define UNPGC_DEAD 0x1 /* unpcb might be dead. */
+#define UNPGC_IGNORE_RIGHTS 0x2 /* Attached rights are freed */
#define sotounpcb(so) ((struct unpcb *)((so)->so_pcb))