Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/dev/sdev_netops.c
+++ new/usr/src/uts/common/fs/dev/sdev_netops.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * vnode ops for the /dev/net directory
28 28 *
29 29 * The lookup is based on the internal vanity naming node table. We also
30 30 * override readdir in order to delete net nodes no longer in-use.
31 31 */
32 32
33 33 #include <sys/types.h>
34 34 #include <sys/param.h>
35 35 #include <sys/sysmacros.h>
36 36 #include <sys/sunndi.h>
37 37 #include <fs/fs_subr.h>
38 38 #include <sys/fs/dv_node.h>
39 39 #include <sys/fs/sdev_impl.h>
40 40 #include <sys/policy.h>
41 41 #include <sys/zone.h>
42 42 #include <sys/dls.h>
43 43
44 44 struct vnodeops *devnet_vnodeops;
45 45
46 46 /*
47 47 * Check if a net sdev_node is still valid - i.e. it represents a current
48 48 * network link.
49 49 * This serves two purposes
50 50 * - only valid net nodes are returned during lookup() and readdir().
51 51 * - since net sdev_nodes are not actively destroyed when a network link
52 52 * goes away, we use the validator to do deferred cleanup i.e. when such
53 53 * nodes are encountered during subsequent lookup() and readdir().
54 54 */
55 55 int
56 56 devnet_validate(struct sdev_node *dv)
57 57 {
58 58 datalink_id_t linkid;
59 59 zoneid_t zoneid;
60 60
61 61 ASSERT(dv->sdev_state == SDEV_READY);
62 62
63 63 if (dls_mgmt_get_linkid(dv->sdev_name, &linkid) != 0)
64 64 return (SDEV_VTOR_INVALID);
65 65 if (SDEV_IS_GLOBAL(dv))
66 66 return (SDEV_VTOR_VALID);
67 67 zoneid = getzoneid();
68 68 return (zone_check_datalink(&zoneid, linkid) == 0 ?
69 69 SDEV_VTOR_VALID : SDEV_VTOR_INVALID);
70 70 }
71 71
72 72 /*
73 73 * This callback is invoked from devname_lookup_func() to create
74 74 * a net entry when the node is not found in the cache.
75 75 */
76 76 static int
77 77 devnet_create_rvp(const char *nm, struct vattr *vap, dls_dl_handle_t *ddhp)
78 78 {
79 79 timestruc_t now;
80 80 dev_t dev;
81 81 int error;
82 82
83 83 if ((error = dls_devnet_open(nm, ddhp, &dev)) != 0) {
84 84 sdcmn_err12(("devnet_create_rvp: not a valid vanity name "
85 85 "network node: %s\n", nm));
86 86 return (error);
87 87 }
88 88
89 89 /*
90 90 * This is a valid network device (at least at this point in time).
91 91 * Create the node by setting the attribute; the rest is taken care
92 92 * of by devname_lookup_func().
93 93 */
94 94 *vap = sdev_vattr_chr;
95 95 vap->va_mode |= 0666;
96 96 vap->va_rdev = dev;
97 97
98 98 gethrestime(&now);
99 99 vap->va_atime = now;
100 100 vap->va_mtime = now;
101 101 vap->va_ctime = now;
102 102 return (0);
103 103 }
104 104
105 105 /*
106 106 * Lookup for /dev/net directory
107 107 * If the entry does not exist, the devnet_create_rvp() callback
108 108 * is invoked to create it. Nodes do not persist across reboot.
109 109 */
110 110 /*ARGSUSED3*/
111 111 static int
112 112 devnet_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
113 113 struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
114 114 caller_context_t *ct, int *direntflags, pathname_t *realpnp)
115 115 {
116 116 struct sdev_node *ddv = VTOSDEV(dvp);
117 117 struct sdev_node *dv = NULL;
118 118 dls_dl_handle_t ddh = NULL;
119 119 struct vattr vattr;
120 120 int nmlen;
121 121 int error = ENOENT;
122 122
123 123 if (SDEVTOV(ddv)->v_type != VDIR)
124 124 return (ENOTDIR);
125 125
126 126 /*
127 127 * Empty name or ., return node itself.
128 128 */
129 129 nmlen = strlen(nm);
130 130 if ((nmlen == 0) || ((nmlen == 1) && (nm[0] == '.'))) {
131 131 *vpp = SDEVTOV(ddv);
132 132 VN_HOLD(*vpp);
133 133 return (0);
134 134 }
135 135
136 136 /*
137 137 * .., return the parent directory
138 138 */
139 139 if ((nmlen == 2) && (strcmp(nm, "..") == 0)) {
140 140 *vpp = SDEVTOV(ddv->sdev_dotdot);
141 141 VN_HOLD(*vpp);
142 142 return (0);
143 143 }
144 144
145 145 rw_enter(&ddv->sdev_contents, RW_WRITER);
146 146
147 147 /*
148 148 * directory cache lookup:
149 149 */
150 150 if ((dv = sdev_cache_lookup(ddv, nm)) != NULL) {
151 151 ASSERT(dv->sdev_state == SDEV_READY);
152 152 if (!(dv->sdev_flags & SDEV_ATTR_INVALID))
153 153 goto found;
154 154 }
155 155
156 156 /*
157 157 * ZOMBIED parent does not allow new node creation, bail out early.
158 158 */
159 159 if (ddv->sdev_state == SDEV_ZOMBIE)
160 160 goto failed;
161 161
162 162 error = devnet_create_rvp(nm, &vattr, &ddh);
163 163 if (error != 0)
164 164 goto failed;
165 165
166 166 error = sdev_mknode(ddv, nm, &dv, &vattr, NULL, NULL, cred, SDEV_READY);
167 167 if (error != 0) {
168 168 dls_devnet_close(ddh);
169 169 goto failed;
170 170 }
171 171
172 172 ASSERT(dv != NULL);
173 173
174 174 rw_enter(&dv->sdev_contents, RW_WRITER);
175 175 if (dv->sdev_flags & SDEV_ATTR_INVALID) {
176 176 /*
177 177 * SDEV_ATTR_INVALID means that this device has been
178 178 * detached, and its dev_t might've been changed too.
179 179 * Therefore, sdev_node's 'vattr' needs to be updated.
180 180 */
181 181 SDEVTOV(dv)->v_rdev = vattr.va_rdev;
182 182 ASSERT(dv->sdev_attr != NULL);
183 183 dv->sdev_attr->va_rdev = vattr.va_rdev;
184 184 dv->sdev_flags &= ~SDEV_ATTR_INVALID;
185 185 }
186 186 ASSERT(dv->sdev_private == NULL);
187 187 dv->sdev_private = ddh;
188 188 rw_exit(&dv->sdev_contents);
189 189
190 190 found:
191 191 ASSERT(SDEV_HELD(dv));
192 192 rw_exit(&ddv->sdev_contents);
193 193 return (sdev_to_vp(dv, vpp));
194 194
195 195 failed:
196 196 rw_exit(&ddv->sdev_contents);
197 197
198 198 if (dv != NULL)
199 199 SDEV_RELE(dv);
200 200
201 201 *vpp = NULL;
202 202 return (error);
203 203 }
204 204
205 205 static int
206 206 devnet_filldir_datalink(datalink_id_t linkid, void *arg)
207 207 {
208 208 struct sdev_node *ddv = arg;
209 209 struct vattr vattr;
210 210 struct sdev_node *dv;
211 211 dls_dl_handle_t ddh = NULL;
212 212 char link[MAXLINKNAMELEN];
213 213
214 214 ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));
215 215
216 216 if (dls_mgmt_get_linkinfo(linkid, link, NULL, NULL, NULL) != 0)
217 217 return (0);
218 218
219 219 if ((dv = sdev_cache_lookup(ddv, (char *)link)) != NULL)
220 220 goto found;
221 221
222 222 if (devnet_create_rvp(link, &vattr, &ddh) != 0)
223 223 return (0);
224 224
225 225 ASSERT(ddh != NULL);
226 226 dls_devnet_close(ddh);
227 227
228 228 if (sdev_mknode(ddv, (char *)link, &dv, &vattr, NULL, NULL, kcred,
229 229 SDEV_READY) != 0) {
230 230 return (0);
231 231 }
232 232
233 233 /*
234 234 * As there is no reference holding the network device, it could be
235 235 * detached. Set SDEV_ATTR_INVALID so that the 'vattr' will be updated
236 236 * later.
237 237 */
238 238 rw_enter(&dv->sdev_contents, RW_WRITER);
239 239 dv->sdev_flags |= SDEV_ATTR_INVALID;
240 240 rw_exit(&dv->sdev_contents);
241 241
242 242 found:
243 243 SDEV_SIMPLE_RELE(dv);
244 244 return (0);
245 245 }
246 246
247 247 static void
248 248 devnet_filldir(struct sdev_node *ddv)
249 249 {
250 250 sdev_node_t *dv, *next;
251 251 datalink_id_t linkid;
252 252
253 253 ASSERT(RW_READ_HELD(&ddv->sdev_contents));
254 254 if (rw_tryupgrade(&ddv->sdev_contents) == NULL) {
255 255 rw_exit(&ddv->sdev_contents);
256 256 rw_enter(&ddv->sdev_contents, RW_WRITER);
257 257 }
258 258
259 259 for (dv = SDEV_FIRST_ENTRY(ddv); dv; dv = next) {
260 260 next = SDEV_NEXT_ENTRY(ddv, dv);
261 261
262 262 /* validate and prune only ready nodes */
263 263 if (dv->sdev_state != SDEV_READY)
264 264 continue;
265 265
266 266 switch (devnet_validate(dv)) {
267 267 case SDEV_VTOR_VALID:
268 268 case SDEV_VTOR_SKIP:
269 269 continue;
270 270 case SDEV_VTOR_INVALID:
271 271 case SDEV_VTOR_STALE:
272 272 sdcmn_err12(("devnet_filldir: destroy invalid "
273 273 "node: %s(%p)\n", dv->sdev_name, (void *)dv));
274 274 break;
275 275 }
276 276
277 277 if (SDEVTOV(dv)->v_count > 0)
278 278 continue;
279 279 SDEV_HOLD(dv);
280 280 /* remove the cache node */
281 281 (void) sdev_cache_update(ddv, &dv, dv->sdev_name,
282 282 SDEV_CACHE_DELETE);
283 283 SDEV_RELE(dv);
284 284 }
285 285
286 286 if (((ddv->sdev_flags & SDEV_BUILD) == 0) && !dls_devnet_rebuild())
287 287 goto done;
288 288
289 289 if (SDEV_IS_GLOBAL(ddv)) {
290 290 linkid = DATALINK_INVALID_LINKID;
291 291 do {
292 292 linkid = dls_mgmt_get_next(linkid, DATALINK_CLASS_ALL,
293 293 DATALINK_ANY_MEDIATYPE, DLMGMT_ACTIVE);
294 294 if (linkid != DATALINK_INVALID_LINKID)
295 295 (void) devnet_filldir_datalink(linkid, ddv);
296 296 } while (linkid != DATALINK_INVALID_LINKID);
297 297 } else {
298 298 (void) zone_datalink_walk(getzoneid(),
299 299 devnet_filldir_datalink, ddv);
300 300 }
301 301
302 302 ddv->sdev_flags &= ~SDEV_BUILD;
303 303
304 304 done:
305 305 rw_downgrade(&ddv->sdev_contents);
306 306 }
307 307
308 308 /*
309 309 * Display all instantiated network datalink device nodes.
310 310 * A /dev/net entry will be created only after the first lookup of
311 311 * the network datalink device succeeds.
312 312 */
313 313 /*ARGSUSED4*/
314 314 static int
315 315 devnet_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred,
316 316 int *eofp, caller_context_t *ct, int flags)
317 317 {
318 318 struct sdev_node *sdvp = VTOSDEV(dvp);
319 319
320 320 ASSERT(sdvp);
321 321
322 322 if (uiop->uio_offset == 0)
323 323 devnet_filldir(sdvp);
324 324
325 325 return (devname_readdir_func(dvp, uiop, cred, eofp, 0));
326 326 }
327 327
328 328 /*
329 329 * This callback is invoked from devname_inactive_func() to release
330 330 * the net entry which was held in devnet_create_rvp().
331 331 */
332 332 static void
333 333 devnet_inactive_callback(struct vnode *dvp)
334 334 {
335 335 struct sdev_node *sdvp = VTOSDEV(dvp);
336 336 dls_dl_handle_t ddh;
337 337
338 338 if (dvp->v_type == VDIR)
339 339 return;
340 340
341 341 ASSERT(dvp->v_type == VCHR);
342 342 rw_enter(&sdvp->sdev_contents, RW_WRITER);
343 343 ddh = sdvp->sdev_private;
344 344 sdvp->sdev_private = NULL;
345 345 sdvp->sdev_flags |= SDEV_ATTR_INVALID;
346 346 rw_exit(&sdvp->sdev_contents);
347 347
348 348 /*
349 349 * "ddh" (sdev_private) could be NULL if devnet_lookup fails.
350 350 */
351 351 if (ddh != NULL)
352 352 dls_devnet_close(ddh);
353 353 }
354 354
355 355 /*ARGSUSED*/
356 356 static void
↓ open down ↓ |
356 lines elided |
↑ open up ↑ |
357 357 devnet_inactive(struct vnode *dvp, struct cred *cred, caller_context_t *ct)
358 358 {
359 359 devname_inactive_func(dvp, cred, devnet_inactive_callback);
360 360 }
361 361
362 362 /*
363 363 * We override lookup and readdir to build entries based on the
364 364 * in kernel vanity naming node table.
365 365 */
366 366 const fs_operation_def_t devnet_vnodeops_tbl[] = {
367 - VOPNAME_READDIR, { .vop_readdir = devnet_readdir },
368 - VOPNAME_LOOKUP, { .vop_lookup = devnet_lookup },
369 - VOPNAME_INACTIVE, { .vop_inactive = devnet_inactive },
370 - VOPNAME_CREATE, { .error = fs_nosys },
371 - VOPNAME_REMOVE, { .error = fs_nosys },
372 - VOPNAME_MKDIR, { .error = fs_nosys },
373 - VOPNAME_RMDIR, { .error = fs_nosys },
374 - VOPNAME_SYMLINK, { .error = fs_nosys },
375 - VOPNAME_SETSECATTR, { .error = fs_nosys },
376 - NULL, NULL
367 + { VOPNAME_READDIR, { .vop_readdir = devnet_readdir } },
368 + { VOPNAME_LOOKUP, { .vop_lookup = devnet_lookup } },
369 + { VOPNAME_INACTIVE, { .vop_inactive = devnet_inactive } },
370 + { VOPNAME_CREATE, { .error = fs_nosys } },
371 + { VOPNAME_REMOVE, { .error = fs_nosys } },
372 + { VOPNAME_MKDIR, { .error = fs_nosys } },
373 + { VOPNAME_RMDIR, { .error = fs_nosys } },
374 + { VOPNAME_SYMLINK, { .error = fs_nosys } },
375 + { VOPNAME_SETSECATTR, { .error = fs_nosys } },
376 + { NULL, { NULL } }
377 377 };
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX