| @@ -1,229 +1,227 @@ | | | @@ -1,229 +1,227 @@ |
1 | /* | | 1 | /* |
2 | * Copyright (C) 2022 Tobias Nygren <tnn@NetBSD.org> | | 2 | * Copyright (C) 2022 Tobias Nygren <tnn@NetBSD.org> |
3 | * | | 3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted. | | 5 | * purpose with or without fee is hereby granted. |
6 | * | | 6 | * |
7 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 7 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 8 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 9 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
10 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 10 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 11 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
12 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 12 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
13 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 13 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | */ | | 14 | */ |
15 | | | 15 | |
16 | #include "../machine.h" | | 16 | #include "../machine.h" |
17 | | | 17 | |
18 | #if defined(HASNCACHE) && defined(USE_LIB_RNMT) | | 18 | #if defined(HASNCACHE) && defined(USE_LIB_RNMT) |
19 | #include <sys/rbtree.h> | | 19 | #include <sys/rbtree.h> |
20 | #include <sys/vnode_impl.h> | | 20 | #include <sys/vnode_impl.h> |
21 | #include <err.h> | | 21 | #include <err.h> |
22 | | | 22 | |
23 | #include "../lsof.h" | | 23 | #include "../lsof.h" |
24 | | | 24 | |
25 | /* | | 25 | /* |
26 | * rnmt.c - read NetBSD=>10-style red-black tree kernel name cache | | 26 | * rnmt.c - read NetBSD=>10-style red-black tree kernel name cache |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | static int lnc_compare_nodes(void *, const void *, const void *); | | 29 | static int lnc_compare_nodes(void *, const void *, const void *); |
30 | static int lnc_compare_key(void *, const void *, const void *); | | 30 | static int lnc_compare_key(void *, const void *, const void *); |
31 | | | 31 | |
32 | static rb_tree_t lnc_rbtree; | | 32 | static rb_tree_t lnc_rbtree; |
33 | | | 33 | |
34 | /* local name cache entry */ | | 34 | /* local name cache entry */ |
35 | struct lnc { | | 35 | struct lnc { |
36 | struct rb_node lnc_tree; /* red-black tree */ | | 36 | struct rb_node lnc_tree; /* red-black tree */ |
37 | KA_T lnc_vp; /* vnode address */ | | 37 | KA_T lnc_vp; /* vnode address */ |
38 | KA_T lnc_pvp; /* parent vnode address */ | | | |
39 | const struct lnc *lnc_plnc; /* parent lnc address */ | | 38 | const struct lnc *lnc_plnc; /* parent lnc address */ |
40 | int lnc_nlen; /* name length */ | | 39 | int lnc_nlen; /* name length */ |
41 | char lnc_name[NCHNAMLEN + 1]; /* name */ | | 40 | char lnc_name[NCHNAMLEN + 1]; /* name */ |
42 | }; | | 41 | }; |
43 | | | 42 | |
44 | static const rb_tree_ops_t lnc_rbtree_ops = { | | 43 | static const rb_tree_ops_t lnc_rbtree_ops = { |
45 | .rbto_compare_nodes = lnc_compare_nodes, | | 44 | .rbto_compare_nodes = lnc_compare_nodes, |
46 | .rbto_compare_key = lnc_compare_key, | | 45 | .rbto_compare_key = lnc_compare_key, |
47 | .rbto_node_offset = offsetof(struct lnc, lnc_tree), | | 46 | .rbto_node_offset = offsetof(struct lnc, lnc_tree), |
48 | .rbto_context = NULL | | 47 | .rbto_context = NULL |
49 | }; | | 48 | }; |
50 | | | 49 | |
51 | static int | | 50 | static int |
52 | lnc_compare_nodes(void *context, const void *node1, const void *node2) | | 51 | lnc_compare_nodes(void *context, const void *node1, const void *node2) |
53 | { | | 52 | { |
54 | const struct lnc *lnc1 = node1; | | 53 | const struct lnc *lnc1 = node1; |
55 | const struct lnc *lnc2 = node2; | | 54 | const struct lnc *lnc2 = node2; |
56 | | | 55 | |
57 | if (lnc1->lnc_vp < lnc2->lnc_vp) { | | 56 | if (lnc1->lnc_vp < lnc2->lnc_vp) { |
58 | return -1; | | 57 | return -1; |
59 | } | | 58 | } |
60 | if (lnc1->lnc_vp > lnc2->lnc_vp) { | | 59 | if (lnc1->lnc_vp > lnc2->lnc_vp) { |
61 | return 1; | | 60 | return 1; |
62 | } | | 61 | } |
63 | | | 62 | |
64 | return 0; | | 63 | return 0; |
65 | } | | 64 | } |
66 | | | 65 | |
67 | static int | | 66 | static int |
68 | lnc_compare_key(void *context, const void *node, const void *key) | | 67 | lnc_compare_key(void *context, const void *node, const void *key) |
69 | { | | 68 | { |
70 | const struct lnc *lnc = node; | | 69 | const struct lnc *lnc = node; |
71 | const KA_T vp = (KA_T)key; | | 70 | const KA_T vp = (KA_T)key; |
72 | | | 71 | |
73 | if (lnc->lnc_vp < vp) { | | 72 | if (lnc->lnc_vp < vp) { |
74 | return -1; | | 73 | return -1; |
75 | } | | 74 | } |
76 | if (lnc->lnc_vp > vp) { | | 75 | if (lnc->lnc_vp > vp) { |
77 | return 1; | | 76 | return 1; |
78 | } | | 77 | } |
79 | | | 78 | |
80 | return 0; | | 79 | return 0; |
81 | } | | 80 | } |
82 | | | 81 | |
83 | static struct lnc * | | 82 | static struct lnc * |
84 | ncache_enter_local(KA_T vp, KA_T pvp, const struct lnc *plnc, const struct namecache *nc) | | 83 | ncache_enter_local(KA_T vp, const struct lnc *plnc, const struct namecache *nc) |
85 | { | | 84 | { |
86 | struct lnc *lnc; | | 85 | struct lnc *lnc; |
87 | | | 86 | |
88 | lnc = malloc(sizeof(*lnc)); | | 87 | lnc = malloc(sizeof(*lnc)); |
89 | if (!lnc) { | | 88 | if (!lnc) { |
90 | errx(1, "can't allocate local name cache entry\n"); | | 89 | errx(1, "can't allocate local name cache entry\n"); |
91 | } | | 90 | } |
92 | lnc->lnc_vp = vp; | | 91 | lnc->lnc_vp = vp; |
93 | lnc->lnc_pvp = pvp; | | | |
94 | lnc->lnc_plnc = plnc; | | 92 | lnc->lnc_plnc = plnc; |
95 | lnc->lnc_nlen = nc->nc_nlen; | | 93 | lnc->lnc_nlen = nc->nc_nlen; |
96 | memcpy(lnc->lnc_name, nc->nc_name, lnc->lnc_nlen); | | 94 | memcpy(lnc->lnc_name, nc->nc_name, lnc->lnc_nlen); |
97 | lnc->lnc_name[lnc->lnc_nlen] = 0; | | 95 | lnc->lnc_name[lnc->lnc_nlen] = 0; |
98 | | | 96 | |
99 | rb_tree_insert_node(&lnc_rbtree, lnc); | | 97 | rb_tree_insert_node(&lnc_rbtree, lnc); |
100 | | | 98 | |
101 | return lnc; | | 99 | return lnc; |
102 | } | | 100 | } |
103 | | | 101 | |
104 | static int | | 102 | static int |
105 | sanity_check_vnode_impl(const struct vnode_impl *vi) | | 103 | sanity_check_vnode_impl(const struct vnode_impl *vi) |
106 | { | | 104 | { |
107 | if (vi->vi_vnode.v_type >= VBAD) | | 105 | if (vi->vi_vnode.v_type >= VBAD) |
108 | return -1; | | 106 | return -1; |
109 | | | 107 | |
110 | return 0; | | 108 | return 0; |
111 | } | | 109 | } |
112 | | | 110 | |
113 | static int | | 111 | static int |
114 | sanity_check_namecache(const struct namecache *nc) | | 112 | sanity_check_namecache(const struct namecache *nc) |
115 | { | | 113 | { |
116 | if (nc->nc_vp == NULL) | | 114 | if (nc->nc_vp == NULL) |
117 | return -1; | | 115 | return -1; |
118 | | | 116 | |
119 | if (nc->nc_nlen > NCHNAMLEN) | | 117 | if (nc->nc_nlen > NCHNAMLEN) |
120 | return -1; | | 118 | return -1; |
121 | | | 119 | |
122 | if (nc->nc_nlen == 1 && nc->nc_name[0] == '.') | | 120 | if (nc->nc_nlen == 1 && nc->nc_name[0] == '.') |
123 | return -1; | | 121 | return -1; |
124 | | | 122 | |
125 | if (nc->nc_nlen == 2 && nc->nc_name[0] == '.' && nc->nc_name[1] == '.') | | 123 | if (nc->nc_nlen == 2 && nc->nc_name[0] == '.' && nc->nc_name[1] == '.') |
126 | return -1; | | 124 | return -1; |
127 | | | 125 | |
128 | return 0; | | 126 | return 0; |
129 | } | | 127 | } |
130 | | | 128 | |
131 | static void | | 129 | static void |
132 | ncache_walk(KA_T ncp, KA_T pvp, const struct lnc *plnc) | | 130 | ncache_walk(KA_T ncp, const struct lnc *plnc) |
133 | { | | 131 | { |
134 | struct l_nch *lc; | | 132 | struct l_nch *lc; |
135 | static struct vnode_impl vi; | | 133 | static struct vnode_impl vi; |
136 | static struct namecache nc; | | 134 | static struct namecache nc; |
137 | struct lnc *lnc; | | 135 | struct lnc *lnc; |
138 | KA_T vp; | | 136 | KA_T vp; |
139 | KA_T left, right; | | 137 | KA_T left, right; |
140 | | | 138 | |
141 | if (kread(ncp, (char *)&nc, sizeof(nc))) { | | 139 | if (kread(ncp, (char *)&nc, sizeof(nc))) { |
142 | return; | | 140 | return; |
143 | } | | 141 | } |
144 | vp = (KA_T)nc.nc_vp; | | 142 | vp = (KA_T)nc.nc_vp; |
145 | if (kread(vp, (char *)&vi, sizeof(vi))) { | | 143 | if (kread(vp, (char *)&vi, sizeof(vi))) { |
146 | vi.vi_vnode.v_type = VBAD; | | 144 | vi.vi_vnode.v_type = VBAD; |
147 | } | | 145 | } |
148 | left = (KA_T)nc.nc_tree.rb_nodes[0]; | | 146 | left = (KA_T)nc.nc_tree.rb_nodes[0]; |
149 | right = (KA_T)nc.nc_tree.rb_nodes[1]; | | 147 | right = (KA_T)nc.nc_tree.rb_nodes[1]; |
150 | if (sanity_check_vnode_impl(&vi) == 0 && sanity_check_namecache(&nc) == 0) { | | 148 | if (sanity_check_vnode_impl(&vi) == 0 && sanity_check_namecache(&nc) == 0) { |
151 | lnc = ncache_enter_local(vp, pvp, plnc, &nc); | | 149 | lnc = ncache_enter_local(vp, plnc, &nc); |
152 | if (vi.vi_vnode.v_type == VDIR && vi.vi_nc_tree.rbt_root != NULL) { | | 150 | if (vi.vi_vnode.v_type == VDIR && vi.vi_nc_tree.rbt_root != NULL) { |
153 | ncache_walk((KA_T)vi.vi_nc_tree.rbt_root, ncp, lnc); | | 151 | ncache_walk((KA_T)vi.vi_nc_tree.rbt_root, lnc); |
154 | } | | 152 | } |
155 | } | | 153 | } |
156 | if (left) | | 154 | if (left) |
157 | ncache_walk(left, pvp, plnc); | | 155 | ncache_walk(left, plnc); |
158 | if (right) | | 156 | if (right) |
159 | ncache_walk(right, pvp, plnc); | | 157 | ncache_walk(right, plnc); |
160 | } | | 158 | } |
161 | | | 159 | |
162 | void | | 160 | void |
163 | ncache_load() | | 161 | ncache_load() |
164 | { | | 162 | { |
165 | KA_T rootvnode_addr; | | 163 | KA_T rootvnode_addr; |
166 | struct vnode_impl vi; | | 164 | struct vnode_impl vi; |
167 | | | 165 | |
168 | rootvnode_addr = (KA_T)0; | | 166 | rootvnode_addr = (KA_T)0; |
169 | if (get_Nl_value("rootvnode", (struct drive_Nl *)NULL, &rootvnode_addr) < 0 | | 167 | if (get_Nl_value("rootvnode", (struct drive_Nl *)NULL, &rootvnode_addr) < 0 |
170 | || !rootvnode_addr | | 168 | || !rootvnode_addr |
171 | || kread((KA_T)rootvnode_addr, (char *)&rootvnode_addr, sizeof(rootvnode_addr)) | | 169 | || kread((KA_T)rootvnode_addr, (char *)&rootvnode_addr, sizeof(rootvnode_addr)) |
172 | || kread((KA_T)rootvnode_addr, (char *)&vi, sizeof(vi))) { | | 170 | || kread((KA_T)rootvnode_addr, (char *)&vi, sizeof(vi))) { |
173 | errx(1, "can't read rootvnode\n"); | | 171 | errx(1, "can't read rootvnode\n"); |
174 | } | | 172 | } |
175 | | | 173 | |
176 | rb_tree_init(&lnc_rbtree, &lnc_rbtree_ops); | | 174 | rb_tree_init(&lnc_rbtree, &lnc_rbtree_ops); |
177 | ncache_walk((KA_T)vi.vi_nc_tree.rbt_root, 0, 0); | | 175 | ncache_walk((KA_T)vi.vi_nc_tree.rbt_root, 0); |
178 | } | | 176 | } |
179 | | | 177 | |
180 | static void | | 178 | static void |
181 | build_path(char **buf, size_t *remaining, const struct lnc *lnc) | | 179 | build_path(char **buf, size_t *remaining, const struct lnc *lnc) |
182 | { | | 180 | { |
183 | size_t len; | | 181 | size_t len; |
184 | | | 182 | |
185 | if (lnc == NULL) | | 183 | if (lnc == NULL) |
186 | return; | | 184 | return; |
187 | | | 185 | |
188 | build_path(buf, remaining, lnc->lnc_plnc); | | 186 | build_path(buf, remaining, lnc->lnc_plnc); |
189 | if (remaining == 0) { | | 187 | if (remaining == 0) { |
190 | return; | | 188 | return; |
191 | } | | 189 | } |
192 | if (lnc->lnc_plnc != NULL) { | | 190 | if (lnc->lnc_plnc != NULL) { |
193 | **buf = '/'; | | 191 | **buf = '/'; |
194 | (*buf)++; | | 192 | (*buf)++; |
195 | remaining--; | | 193 | remaining--; |
196 | } | | 194 | } |
197 | len = lnc->lnc_nlen; | | 195 | len = lnc->lnc_nlen; |
198 | if (*remaining < len) | | 196 | if (*remaining < len) |
199 | len = *remaining; | | 197 | len = *remaining; |
200 | memcpy(*buf, lnc->lnc_name, len); | | 198 | memcpy(*buf, lnc->lnc_name, len); |
201 | *remaining -= len; | | 199 | *remaining -= len; |
202 | *buf += len; | | 200 | *buf += len; |
203 | } | | 201 | } |
204 | | | 202 | |
205 | char * | | 203 | char * |
206 | ncache_lookup(char *buf, int blen, int *fp) | | 204 | ncache_lookup(char *buf, int blen, int *fp) |
207 | { | | 205 | { |
208 | const struct lnc *lnc; | | 206 | const struct lnc *lnc; |
209 | char *p; | | 207 | char *p; |
210 | size_t remaining; | | 208 | size_t remaining; |
211 | | | 209 | |
212 | *fp = 0; | | 210 | *fp = 0; |
213 | lnc = rb_tree_find_node(&lnc_rbtree, (void*)Lf->na); | | 211 | lnc = rb_tree_find_node(&lnc_rbtree, (void*)Lf->na); |
214 | if (lnc != NULL) { | | 212 | if (lnc != NULL) { |
215 | p = buf; | | 213 | p = buf; |
216 | remaining = blen; | | 214 | remaining = blen; |
217 | build_path(&p, &remaining, lnc); | | 215 | build_path(&p, &remaining, lnc); |
218 | if (remaining == 0) { | | 216 | if (remaining == 0) { |
219 | buf[blen - 1] = 0; | | 217 | buf[blen - 1] = 0; |
220 | } else { | | 218 | } else { |
221 | *p = 0; | | 219 | *p = 0; |
222 | } | | 220 | } |
223 | *fp = 1; | | 221 | *fp = 1; |
224 | return buf; | | 222 | return buf; |
225 | } | | 223 | } |
226 | | | 224 | |
227 | return NULL; | | 225 | return NULL; |
228 | } | | 226 | } |
229 | #endif | | 227 | #endif |