From ae2a352825bc6dd824d2a7e82cd946cf1b75a6fe Mon Sep 17 00:00:00 2001 From: trasz Date: Sat, 14 Sep 2019 19:16:07 +0000 Subject: [PATCH] Make pseudofs(9) create directory entries in order, instead of the reverse. This fixes Linux sysctl(8) binary - it assumes the first two directory entries are always "." and "..". There might be other Linux apps affected by this. NB it might be a good idea to rewrite it using queue(3). Reviewed by: kib MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D21550 --- sys/fs/pseudofs/pseudofs.c | 27 ++++++++++++++++++++++++--- sys/fs/pseudofs/pseudofs.h | 1 + 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/sys/fs/pseudofs/pseudofs.c b/sys/fs/pseudofs/pseudofs.c index 73d3c7cbdd9..c013de14771 100644 --- a/sys/fs/pseudofs/pseudofs.c +++ b/sys/fs/pseudofs/pseudofs.c @@ -135,10 +135,21 @@ pfs_add_node(struct pfs_node *parent, struct pfs_node *pn) pfs_fileno_alloc(pn); pfs_lock(parent); - pn->pn_next = parent->pn_nodes; if ((parent->pn_flags & PFS_PROCDEP) != 0) pn->pn_flags |= PFS_PROCDEP; - parent->pn_nodes = pn; + if (parent->pn_nodes == NULL) { + KASSERT(parent->pn_last_node == NULL, + ("%s(): pn_last_node not NULL", __func__)); + parent->pn_nodes = pn; + parent->pn_last_node = pn; + } else { + KASSERT(parent->pn_last_node != NULL, + ("%s(): pn_last_node is NULL", __func__)); + KASSERT(parent->pn_last_node->pn_next == NULL, + ("%s(): pn_last_node->pn_next not NULL", __func__)); + parent->pn_last_node->pn_next = pn; + parent->pn_last_node = pn; + } pfs_unlock(parent); } @@ -148,7 +159,7 @@ pfs_add_node(struct pfs_node *parent, struct pfs_node *pn) static void pfs_detach_node(struct pfs_node *pn) { - struct pfs_node *parent = pn->pn_parent; + struct pfs_node *node, *parent = pn->pn_parent; struct pfs_node **iter; KASSERT(parent != NULL, ("%s(): node has no parent", __func__)); @@ -156,6 +167,16 @@ pfs_detach_node(struct pfs_node *pn) ("%s(): parent has different pn_info", __func__)); pfs_lock(parent); + if (pn == parent->pn_last_node) { + if (pn == pn->pn_nodes) { + parent->pn_last_node = NULL; + } else { + for (node = parent->pn_nodes; + node->pn_next != pn; node = node->pn_next) + continue; + parent->pn_last_node = node; + } + } iter = &parent->pn_nodes; while (*iter != NULL) { if (*iter == pn) { diff --git a/sys/fs/pseudofs/pseudofs.h b/sys/fs/pseudofs/pseudofs.h index 602e1fbfa37..3dbd5435f04 100644 --- a/sys/fs/pseudofs/pseudofs.h +++ b/sys/fs/pseudofs/pseudofs.h @@ -237,6 +237,7 @@ struct pfs_node { struct pfs_node *pn_parent; /* (o) */ struct pfs_node *pn_nodes; /* (o) */ + struct pfs_node *pn_last_node; /* (o) */ struct pfs_node *pn_next; /* (p) */ }; -- 2.39.5