Print this page
OS-3342+co
OS-722
OS-478 -- lint
OS-375-1
OS-328 dlmgmtd/mac_link_flow_add() deadlock
OS-249
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/dlmgmtd/dlmgmt_door.c
+++ new/usr/src/cmd/dlmgmtd/dlmgmt_door.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
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
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 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright (c) 2011, Joyent Inc. All rights reserved.
24 25 */
25 26
26 27 /*
27 28 * Main door handler functions used by dlmgmtd to process the different door
28 29 * call requests. Door call requests can come from the user-land applications,
29 30 * or from the kernel.
30 31 *
31 32 * Note on zones handling:
32 33 *
33 34 * There are two zoneid's associated with a link. One is the zoneid of the
34 35 * zone in which the link was created (ll_zoneid in the dlmgmt_link_t), and
35 36 * the other is the zoneid of the zone where the link is currently assigned
36 37 * (the "zone" link property). The two can be different if a datalink is
37 38 * created in the global zone and subsequently assigned to a non-global zone
38 39 * via zonecfg or via explicitly setting the "zone" link property.
39 40 *
40 41 * Door clients can see links that were created in their zone, and links that
41 42 * are currently assigned to their zone. Door clients in a zone can only
42 43 * modify links that were created in their zone.
43 44 *
44 45 * The datalink ID space is global, while each zone has its own datalink name
45 46 * space. This allows each zone to have complete freedom over the names that
46 47 * they assign to links created within the zone.
47 48 */
48 49
49 50 #include <assert.h>
50 51 #include <alloca.h>
|
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
51 52 #include <errno.h>
52 53 #include <priv_utils.h>
53 54 #include <stdlib.h>
54 55 #include <strings.h>
55 56 #include <syslog.h>
56 57 #include <sys/sysevent/eventdefs.h>
57 58 #include <zone.h>
58 59 #include <libsysevent.h>
59 60 #include <libdlmgmt.h>
60 61 #include <librcm.h>
62 +#include <sys/types.h>
63 +#include <sys/stat.h>
64 +#include <fcntl.h>
65 +#include <unistd.h>
61 66 #include "dlmgmt_impl.h"
62 67
63 68 typedef void dlmgmt_door_handler_t(void *, void *, size_t *, zoneid_t,
64 69 ucred_t *);
65 70
66 71 typedef struct dlmgmt_door_info_s {
67 72 uint_t di_cmd;
68 73 size_t di_reqsz;
69 74 size_t di_acksz;
70 75 dlmgmt_door_handler_t *di_handler;
71 76 } dlmgmt_door_info_t;
72 77
73 78 /*
74 79 * Check if the caller has the required privileges to operate on a link of the
75 80 * given class.
76 81 */
77 82 static int
78 83 dlmgmt_checkprivs(datalink_class_t class, ucred_t *cred)
79 84 {
80 85 const priv_set_t *eset;
81 86
82 87 eset = ucred_getprivset(cred, PRIV_EFFECTIVE);
83 88 if (eset != NULL && ((class == DATALINK_CLASS_IPTUN &&
84 89 priv_ismember(eset, PRIV_SYS_IPTUN_CONFIG)) ||
85 90 priv_ismember(eset, PRIV_SYS_DL_CONFIG) ||
86 91 priv_ismember(eset, PRIV_SYS_NET_CONFIG)))
87 92 return (0);
88 93 return (EACCES);
89 94 }
90 95
91 96 static dlmgmt_link_t *
92 97 dlmgmt_getlink_by_dev(char *devname, zoneid_t zoneid)
93 98 {
94 99 dlmgmt_link_t *linkp = avl_first(&dlmgmt_id_avl);
95 100
96 101 for (; linkp != NULL; linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
97 102 if (link_is_visible(linkp, zoneid) &&
98 103 (linkp->ll_class == DATALINK_CLASS_PHYS) &&
99 104 linkattr_equal(&(linkp->ll_head), FDEVNAME, devname,
100 105 strlen(devname) + 1)) {
101 106 return (linkp);
102 107 }
103 108 }
104 109 return (NULL);
105 110 }
106 111
107 112 /*
108 113 * Post the EC_DATALINK sysevent for the given linkid. This sysevent will
109 114 * be consumed by the datalink sysevent module.
110 115 */
111 116 static void
112 117 dlmgmt_post_sysevent(const char *subclass, datalink_id_t linkid,
113 118 boolean_t reconfigured)
114 119 {
115 120 nvlist_t *nvl = NULL;
116 121 sysevent_id_t eid;
117 122 int err;
118 123
119 124 if (((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0) ||
120 125 ((err = nvlist_add_uint64(nvl, RCM_NV_LINKID, linkid)) != 0) ||
121 126 ((err = nvlist_add_boolean_value(nvl, RCM_NV_RECONFIGURED,
122 127 reconfigured)) != 0)) {
123 128 goto done;
124 129 }
125 130
126 131 if (sysevent_post_event(EC_DATALINK, (char *)subclass, SUNW_VENDOR,
127 132 (char *)progname, nvl, &eid) == -1) {
128 133 err = errno;
129 134 }
130 135
131 136 done:
132 137 if (err != 0) {
133 138 dlmgmt_log(LOG_WARNING, "dlmgmt_post_sysevent(%d) failed: %s",
134 139 linkid, strerror(err));
135 140 }
136 141 nvlist_free(nvl);
137 142 }
138 143
139 144 /* ARGSUSED */
140 145 static void
141 146 dlmgmt_upcall_create(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
142 147 ucred_t *cred)
143 148 {
144 149 dlmgmt_upcall_arg_create_t *create = argp;
145 150 dlmgmt_create_retval_t *retvalp = retp;
146 151 datalink_class_t class;
147 152 uint32_t media;
148 153 dlmgmt_link_t *linkp;
149 154 char link[MAXLINKNAMELEN];
150 155 uint32_t flags;
151 156 int err = 0;
152 157 boolean_t created = B_FALSE;
153 158 boolean_t reconfigured = B_FALSE;
154 159
155 160 /*
156 161 * Determine whether this link is persistent. Note that this request
157 162 * is coming from kernel so this link must be active.
158 163 */
159 164 flags = DLMGMT_ACTIVE | (create->ld_persist ? DLMGMT_PERSIST : 0);
160 165
161 166 class = create->ld_class;
162 167 media = create->ld_media;
163 168
164 169 /*
165 170 * Hold the writer lock to update the link table.
166 171 */
167 172 dlmgmt_table_lock(B_TRUE);
168 173
169 174 if ((err = dlmgmt_checkprivs(class, cred)) != 0)
170 175 goto done;
171 176
172 177 /*
173 178 * Check to see whether this is the reattachment of an existing
174 179 * physical link. If so, return its linkid.
175 180 */
176 181 if ((class == DATALINK_CLASS_PHYS) && (linkp =
177 182 dlmgmt_getlink_by_dev(create->ld_devname, zoneid)) != NULL) {
178 183 if (linkattr_equal(&(linkp->ll_head), FPHYMAJ,
179 184 &create->ld_phymaj, sizeof (uint64_t)) &&
180 185 linkattr_equal(&(linkp->ll_head), FPHYINST,
181 186 &create->ld_phyinst, sizeof (uint64_t)) &&
182 187 (linkp->ll_flags & flags) == flags) {
183 188 /*
184 189 * If nothing has been changed, directly return.
185 190 */
186 191 goto noupdate;
187 192 }
188 193
189 194 err = linkattr_set(&(linkp->ll_head), FPHYMAJ,
190 195 &create->ld_phymaj, sizeof (uint64_t), DLADM_TYPE_UINT64);
191 196 if (err != 0)
192 197 goto done;
193 198
194 199 err = linkattr_set(&(linkp->ll_head), FPHYINST,
195 200 &create->ld_phyinst, sizeof (uint64_t), DLADM_TYPE_UINT64);
196 201 if (err != 0)
197 202 goto done;
198 203
199 204 /*
200 205 * This is a device that is dynamic reconfigured.
201 206 */
202 207 if ((linkp->ll_flags & DLMGMT_ACTIVE) == 0)
203 208 reconfigured = B_TRUE;
204 209
205 210 if ((err = link_activate(linkp)) != 0)
206 211 goto done;
207 212 linkp->ll_flags |= flags;
208 213 linkp->ll_gen++;
209 214
210 215 goto done;
211 216 }
212 217
213 218 if ((err = dlmgmt_create_common(create->ld_devname, class, media,
214 219 zoneid, flags, &linkp)) == EEXIST) {
215 220 /*
216 221 * The link name already exists. Return error if this is a
217 222 * non-physical link (in that case, the link name must be
218 223 * the same as the given name).
219 224 */
220 225 if (class != DATALINK_CLASS_PHYS)
221 226 goto done;
222 227
223 228 /*
224 229 * The physical link's name already exists, request
225 230 * a suggested link name: net<nextppa>
226 231 */
227 232 err = dlmgmt_generate_name("net", link, MAXLINKNAMELEN, zoneid);
228 233 if (err != 0)
229 234 goto done;
230 235
231 236 err = dlmgmt_create_common(link, class, media, zoneid, flags,
232 237 &linkp);
233 238 }
234 239
235 240 if (err != 0)
236 241 goto done;
237 242
238 243 created = B_TRUE;
239 244
240 245 /*
241 246 * This is a new link. Only need to persist link attributes for
242 247 * physical links.
243 248 */
244 249 if (class == DATALINK_CLASS_PHYS &&
245 250 (((err = linkattr_set(&linkp->ll_head, FDEVNAME, create->ld_devname,
246 251 strlen(create->ld_devname) + 1, DLADM_TYPE_STR)) != 0) ||
247 252 ((err = linkattr_set(&linkp->ll_head, FPHYMAJ, &create->ld_phymaj,
248 253 sizeof (uint64_t), DLADM_TYPE_UINT64)) != 0) ||
249 254 ((err = linkattr_set(&linkp->ll_head, FPHYINST, &create->ld_phyinst,
250 255 sizeof (uint64_t), DLADM_TYPE_UINT64)) != 0))) {
251 256 (void) dlmgmt_destroy_common(linkp, flags);
252 257 }
253 258
254 259 done:
255 260 if ((err == 0) && ((err = dlmgmt_write_db_entry(linkp->ll_link, linkp,
256 261 linkp->ll_flags)) != 0) && created) {
257 262 (void) dlmgmt_destroy_common(linkp, flags);
258 263 }
259 264
260 265 noupdate:
261 266 if (err == 0)
262 267 retvalp->lr_linkid = linkp->ll_linkid;
263 268
264 269 dlmgmt_table_unlock();
265 270
266 271 if ((err == 0) && (class == DATALINK_CLASS_PHYS)) {
267 272 /*
268 273 * Post the ESC_DATALINK_PHYS_ADD sysevent. This sysevent
269 274 * is consumed by the datalink sysevent module which in
270 275 * turn generates the RCM_RESOURCE_LINK_NEW RCM event.
271 276 */
272 277 dlmgmt_post_sysevent(ESC_DATALINK_PHYS_ADD,
273 278 retvalp->lr_linkid, reconfigured);
274 279 }
275 280
276 281 retvalp->lr_err = err;
277 282 }
278 283
279 284 /* ARGSUSED */
280 285 static void
281 286 dlmgmt_upcall_update(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
282 287 ucred_t *cred)
283 288 {
284 289 dlmgmt_upcall_arg_update_t *update = argp;
285 290 dlmgmt_update_retval_t *retvalp = retp;
286 291 uint32_t media = update->ld_media;
287 292 dlmgmt_link_t *linkp;
288 293 int err = 0;
289 294
290 295 /*
291 296 * Hold the writer lock to update the link table.
292 297 */
293 298 dlmgmt_table_lock(B_TRUE);
294 299
295 300 /*
296 301 * Check to see whether this is the reattachment of an existing
297 302 * physical link. If so, return its linkid.
298 303 */
299 304 if ((linkp = dlmgmt_getlink_by_dev(update->ld_devname, zoneid)) ==
300 305 NULL) {
301 306 err = ENOENT;
302 307 goto done;
303 308 }
304 309
305 310 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
306 311 goto done;
307 312
308 313 retvalp->lr_linkid = linkp->ll_linkid;
309 314 retvalp->lr_media = media;
310 315 if (linkp->ll_media != media && linkp->ll_media != DL_OTHER) {
311 316 /*
312 317 * Assume a DL_ETHER link ce0, a DL_WIFI link ath0
313 318 * 1. # dladm rename-link ce0 net0
314 319 * 2. DR out ce0. net0 is down.
315 320 * 3. use rename-link to have the ath0 device inherit
316 321 * the configuration from net0
317 322 * # dladm rename-link ath0 net0
318 323 * 4. DR in ath0.
319 324 * As ath0 and ce0 do not have the same media type, ath0
320 325 * cannot inherit the configuration of net0.
321 326 */
322 327 err = EEXIST;
323 328
324 329 /*
325 330 * Return the media type of the existing link to indicate the
326 331 * reason for the name conflict.
327 332 */
328 333 retvalp->lr_media = linkp->ll_media;
329 334 goto done;
330 335 }
331 336
332 337 if (update->ld_novanity &&
333 338 (strcmp(update->ld_devname, linkp->ll_link) != 0)) {
334 339 /*
335 340 * Return an error if this is a physical link that does not
336 341 * support vanity naming, but the link name is not the same
337 342 * as the given device name.
338 343 */
339 344 err = EEXIST;
340 345 goto done;
341 346 }
342 347
343 348 if (linkp->ll_media != media) {
344 349 linkp->ll_media = media;
345 350 linkp->ll_gen++;
346 351 (void) dlmgmt_write_db_entry(linkp->ll_link, linkp,
347 352 linkp->ll_flags);
348 353 }
349 354
350 355 done:
351 356 dlmgmt_table_unlock();
352 357 retvalp->lr_err = err;
353 358 }
354 359
355 360 /* ARGSUSED */
356 361 static void
357 362 dlmgmt_upcall_destroy(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
358 363 ucred_t *cred)
359 364 {
360 365 dlmgmt_upcall_arg_destroy_t *destroy = argp;
361 366 dlmgmt_destroy_retval_t *retvalp = retp;
362 367 datalink_id_t linkid = destroy->ld_linkid;
363 368 dlmgmt_link_t *linkp = NULL;
364 369 uint32_t flags, dflags = 0;
365 370 int err = 0;
366 371
367 372 flags = DLMGMT_ACTIVE | (destroy->ld_persist ? DLMGMT_PERSIST : 0);
368 373
369 374 /*
370 375 * Hold the writer lock to update the link table.
371 376 */
|
↓ open down ↓ |
301 lines elided |
↑ open up ↑ |
372 377 dlmgmt_table_lock(B_TRUE);
373 378
374 379 if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
375 380 err = ENOENT;
376 381 goto done;
377 382 }
378 383
379 384 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
380 385 goto done;
381 386
387 + if (linkp->ll_tomb == B_TRUE) {
388 + err = EINPROGRESS;
389 + goto done;
390 + }
391 +
382 392 if (((linkp->ll_flags & flags) & DLMGMT_ACTIVE) != 0) {
383 393 if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_ACTIVE)) != 0)
384 394 goto done;
385 395 dflags |= DLMGMT_ACTIVE;
386 396 }
387 397
388 398 if (((linkp->ll_flags & flags) & DLMGMT_PERSIST) != 0) {
389 399 if ((err = dlmgmt_delete_db_entry(linkp, DLMGMT_PERSIST)) != 0)
390 400 goto done;
391 401 dflags |= DLMGMT_PERSIST;
392 402 }
393 403
394 404 err = dlmgmt_destroy_common(linkp, flags);
395 405 done:
396 406 if (err != 0 && dflags != 0)
397 407 (void) dlmgmt_write_db_entry(linkp->ll_link, linkp, dflags);
398 408
399 409 dlmgmt_table_unlock();
400 410 retvalp->lr_err = err;
401 411 }
402 412
403 413 /* ARGSUSED */
404 414 static void
405 415 dlmgmt_getname(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
406 416 ucred_t *cred)
407 417 {
408 418 dlmgmt_door_getname_t *getname = argp;
409 419 dlmgmt_getname_retval_t *retvalp = retp;
410 420 dlmgmt_link_t *linkp;
411 421 int err = 0;
412 422
413 423 /*
414 424 * Hold the reader lock to access the link
415 425 */
416 426 dlmgmt_table_lock(B_FALSE);
417 427 if ((linkp = link_by_id(getname->ld_linkid, zoneid)) == NULL) {
418 428 err = ENOENT;
419 429 } else if (strlcpy(retvalp->lr_link, linkp->ll_link, MAXLINKNAMELEN) >=
420 430 MAXLINKNAMELEN) {
421 431 err = ENOSPC;
422 432 } else {
423 433 retvalp->lr_flags = linkp->ll_flags;
424 434 retvalp->lr_class = linkp->ll_class;
425 435 retvalp->lr_media = linkp->ll_media;
426 436 }
427 437
428 438 dlmgmt_table_unlock();
429 439 retvalp->lr_err = err;
430 440 }
431 441
|
↓ open down ↓ |
40 lines elided |
↑ open up ↑ |
432 442 /* ARGSUSED */
433 443 static void
434 444 dlmgmt_getlinkid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
435 445 ucred_t *cred)
436 446 {
437 447 dlmgmt_door_getlinkid_t *getlinkid = argp;
438 448 dlmgmt_getlinkid_retval_t *retvalp = retp;
439 449 dlmgmt_link_t *linkp;
440 450 int err = 0;
441 451
452 + /* Enable the global zone to lookup links it has given away. */
453 + if (zoneid == GLOBAL_ZONEID && getlinkid->ld_zoneid != -1)
454 + zoneid = getlinkid->ld_zoneid;
455 +
442 456 /*
443 457 * Hold the reader lock to access the link
444 458 */
445 459 dlmgmt_table_lock(B_FALSE);
446 460
447 461 if ((linkp = link_by_name(getlinkid->ld_link, zoneid)) == NULL) {
448 462 /*
449 463 * The link does not exist in this zone.
450 464 */
451 465 err = ENOENT;
452 466 goto done;
453 467 }
454 468
455 469 retvalp->lr_linkid = linkp->ll_linkid;
456 470 retvalp->lr_flags = linkp->ll_flags;
457 471 retvalp->lr_class = linkp->ll_class;
458 472 retvalp->lr_media = linkp->ll_media;
459 473
460 474 done:
461 475 dlmgmt_table_unlock();
462 476 retvalp->lr_err = err;
463 477 }
464 478
465 479 /* ARGSUSED */
466 480 static void
467 481 dlmgmt_getnext(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
468 482 ucred_t *cred)
469 483 {
470 484 dlmgmt_door_getnext_t *getnext = argp;
471 485 dlmgmt_getnext_retval_t *retvalp = retp;
472 486 dlmgmt_link_t link, *linkp;
473 487 avl_index_t where;
474 488 int err = 0;
475 489
476 490 /*
477 491 * Hold the reader lock to access the link
478 492 */
479 493 dlmgmt_table_lock(B_FALSE);
480 494
481 495 link.ll_linkid = (getnext->ld_linkid + 1);
482 496 if ((linkp = avl_find(&dlmgmt_id_avl, &link, &where)) == NULL)
483 497 linkp = avl_nearest(&dlmgmt_id_avl, where, AVL_AFTER);
484 498
485 499 for (; linkp != NULL; linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
486 500 if (!link_is_visible(linkp, zoneid))
487 501 continue;
488 502 if ((linkp->ll_class & getnext->ld_class) &&
489 503 (linkp->ll_flags & getnext->ld_flags) &&
490 504 DATALINK_MEDIA_ACCEPTED(getnext->ld_dmedia,
491 505 linkp->ll_media))
492 506 break;
493 507 }
494 508
495 509 if (linkp == NULL) {
496 510 err = ENOENT;
497 511 } else {
498 512 retvalp->lr_linkid = linkp->ll_linkid;
499 513 retvalp->lr_class = linkp->ll_class;
500 514 retvalp->lr_media = linkp->ll_media;
501 515 retvalp->lr_flags = linkp->ll_flags;
502 516 }
503 517
504 518 dlmgmt_table_unlock();
505 519 retvalp->lr_err = err;
506 520 }
507 521
508 522 /* ARGSUSED */
509 523 static void
510 524 dlmgmt_upcall_getattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
511 525 ucred_t *cred)
512 526 {
513 527 dlmgmt_upcall_arg_getattr_t *getattr = argp;
514 528 dlmgmt_getattr_retval_t *retvalp = retp;
515 529 dlmgmt_link_t *linkp;
516 530
517 531 /*
518 532 * Hold the reader lock to access the link
519 533 */
520 534 dlmgmt_table_lock(B_FALSE);
521 535 if ((linkp = link_by_id(getattr->ld_linkid, zoneid)) == NULL) {
522 536 retvalp->lr_err = ENOENT;
523 537 } else {
524 538 retvalp->lr_err = dlmgmt_getattr_common(&linkp->ll_head,
525 539 getattr->ld_attr, retvalp);
526 540 }
527 541 dlmgmt_table_unlock();
528 542 }
529 543
530 544 /* ARGSUSED */
531 545 static void
532 546 dlmgmt_createid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
533 547 ucred_t *cred)
534 548 {
535 549 dlmgmt_door_createid_t *createid = argp;
536 550 dlmgmt_createid_retval_t *retvalp = retp;
537 551 dlmgmt_link_t *linkp;
538 552 datalink_id_t linkid = DATALINK_INVALID_LINKID;
539 553 char link[MAXLINKNAMELEN];
540 554 int err;
541 555
542 556 /*
543 557 * Hold the writer lock to update the dlconf table.
544 558 */
545 559 dlmgmt_table_lock(B_TRUE);
546 560
547 561 if ((err = dlmgmt_checkprivs(createid->ld_class, cred)) != 0)
548 562 goto done;
549 563
550 564 if (createid->ld_prefix) {
551 565 err = dlmgmt_generate_name(createid->ld_link, link,
552 566 MAXLINKNAMELEN, zoneid);
553 567 if (err != 0)
554 568 goto done;
555 569
556 570 err = dlmgmt_create_common(link, createid->ld_class,
557 571 createid->ld_media, zoneid, createid->ld_flags, &linkp);
558 572 } else {
559 573 err = dlmgmt_create_common(createid->ld_link,
560 574 createid->ld_class, createid->ld_media, zoneid,
561 575 createid->ld_flags, &linkp);
562 576 }
563 577
564 578 if (err == 0) {
565 579 /*
566 580 * Keep the active mapping.
567 581 */
568 582 linkid = linkp->ll_linkid;
569 583 if (createid->ld_flags & DLMGMT_ACTIVE) {
570 584 (void) dlmgmt_write_db_entry(linkp->ll_link, linkp,
571 585 DLMGMT_ACTIVE);
572 586 }
573 587 }
574 588
575 589 done:
576 590 dlmgmt_table_unlock();
577 591 retvalp->lr_linkid = linkid;
578 592 retvalp->lr_err = err;
579 593 }
580 594
581 595 /* ARGSUSED */
582 596 static void
583 597 dlmgmt_destroyid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
584 598 ucred_t *cred)
585 599 {
586 600 dlmgmt_door_destroyid_t *destroyid = argp;
587 601 dlmgmt_destroyid_retval_t *retvalp = retp;
588 602 datalink_id_t linkid = destroyid->ld_linkid;
589 603 uint32_t flags = destroyid->ld_flags;
590 604 dlmgmt_link_t *linkp = NULL;
591 605 int err = 0;
592 606
593 607 /*
594 608 * Hold the writer lock to update the link table.
595 609 */
596 610 dlmgmt_table_lock(B_TRUE);
597 611 if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
598 612 err = ENOENT;
599 613 goto done;
600 614 }
601 615
602 616 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
603 617 goto done;
604 618
605 619 /*
606 620 * Delete the active mapping.
607 621 */
608 622 if (flags & DLMGMT_ACTIVE)
609 623 err = dlmgmt_delete_db_entry(linkp, DLMGMT_ACTIVE);
610 624 if (err == 0)
611 625 err = dlmgmt_destroy_common(linkp, flags);
612 626 done:
613 627 dlmgmt_table_unlock();
614 628 retvalp->lr_err = err;
615 629 }
616 630
617 631 /*
618 632 * Remap a linkid to a given link name, i.e., rename an existing link1
619 633 * (ld_linkid) to a non-existent link2 (ld_link): rename link1's name to
620 634 * the given link name.
621 635 */
622 636 /* ARGSUSED */
623 637 static void
624 638 dlmgmt_remapid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
625 639 ucred_t *cred)
626 640 {
627 641 dlmgmt_door_remapid_t *remapid = argp;
628 642 dlmgmt_remapid_retval_t *retvalp = retp;
629 643 dlmgmt_link_t *linkp;
630 644 char oldname[MAXLINKNAMELEN];
631 645 boolean_t renamed = B_FALSE;
632 646 int err = 0;
633 647
634 648 if (!dladm_valid_linkname(remapid->ld_link)) {
635 649 retvalp->lr_err = EINVAL;
636 650 return;
637 651 }
638 652
639 653 /*
640 654 * Hold the writer lock to update the link table.
|
↓ open down ↓ |
189 lines elided |
↑ open up ↑ |
641 655 */
642 656 dlmgmt_table_lock(B_TRUE);
643 657 if ((linkp = link_by_id(remapid->ld_linkid, zoneid)) == NULL) {
644 658 err = ENOENT;
645 659 goto done;
646 660 }
647 661
648 662 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
649 663 goto done;
650 664
665 + if (linkp->ll_tomb == B_TRUE) {
666 + err = EBUSY;
667 + goto done;
668 + }
669 +
670 +
651 671 if (link_by_name(remapid->ld_link, linkp->ll_zoneid) != NULL) {
652 672 err = EEXIST;
653 673 goto done;
654 674 }
655 675
656 676 (void) strlcpy(oldname, linkp->ll_link, MAXLINKNAMELEN);
657 677 avl_remove(&dlmgmt_name_avl, linkp);
658 678 (void) strlcpy(linkp->ll_link, remapid->ld_link, MAXLINKNAMELEN);
659 679 avl_add(&dlmgmt_name_avl, linkp);
660 680 renamed = B_TRUE;
661 681
662 682 if (linkp->ll_flags & DLMGMT_ACTIVE) {
663 683 err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_ACTIVE);
664 684 if (err != 0)
665 685 goto done;
666 686 }
667 687 if (linkp->ll_flags & DLMGMT_PERSIST) {
668 688 err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_PERSIST);
669 689 if (err != 0) {
670 690 if (linkp->ll_flags & DLMGMT_ACTIVE) {
671 691 (void) dlmgmt_write_db_entry(remapid->ld_link,
672 692 linkp, DLMGMT_ACTIVE);
673 693 }
674 694 goto done;
675 695 }
676 696 }
677 697
678 698 dlmgmt_advance(linkp);
679 699 linkp->ll_gen++;
680 700 done:
681 701 if (err != 0 && renamed) {
682 702 avl_remove(&dlmgmt_name_avl, linkp);
683 703 (void) strlcpy(linkp->ll_link, oldname, MAXLINKNAMELEN);
684 704 avl_add(&dlmgmt_name_avl, linkp);
685 705 }
686 706 dlmgmt_table_unlock();
687 707 retvalp->lr_err = err;
688 708 }
689 709
690 710 /* ARGSUSED */
691 711 static void
692 712 dlmgmt_upid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
693 713 ucred_t *cred)
694 714 {
695 715 dlmgmt_door_upid_t *upid = argp;
696 716 dlmgmt_upid_retval_t *retvalp = retp;
697 717 dlmgmt_link_t *linkp;
698 718 int err = 0;
699 719
700 720 /*
701 721 * Hold the writer lock to update the link table.
|
↓ open down ↓ |
41 lines elided |
↑ open up ↑ |
702 722 */
703 723 dlmgmt_table_lock(B_TRUE);
704 724 if ((linkp = link_by_id(upid->ld_linkid, zoneid)) == NULL) {
705 725 err = ENOENT;
706 726 goto done;
707 727 }
708 728
709 729 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
710 730 goto done;
711 731
732 + if (linkp->ll_tomb == B_TRUE) {
733 + err = EBUSY;
734 + goto done;
735 + }
736 +
712 737 if (linkp->ll_flags & DLMGMT_ACTIVE) {
713 738 err = EINVAL;
714 739 goto done;
715 740 }
716 741
717 742 if ((err = link_activate(linkp)) == 0) {
718 743 (void) dlmgmt_write_db_entry(linkp->ll_link, linkp,
719 744 DLMGMT_ACTIVE);
720 745 }
721 746 done:
722 747 dlmgmt_table_unlock();
723 748 retvalp->lr_err = err;
724 749 }
725 750
726 751 /* ARGSUSED */
727 752 static void
728 753 dlmgmt_createconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
729 754 ucred_t *cred)
730 755 {
731 756 dlmgmt_door_createconf_t *createconf = argp;
732 757 dlmgmt_createconf_retval_t *retvalp = retp;
733 758 dlmgmt_dlconf_t *dlconfp;
734 759 int err;
735 760
736 761 /*
737 762 * Hold the writer lock to update the dlconf table.
738 763 */
739 764 dlmgmt_dlconf_table_lock(B_TRUE);
740 765
741 766 if ((err = dlmgmt_checkprivs(createconf->ld_class, cred)) != 0)
742 767 goto done;
743 768
744 769 err = dlconf_create(createconf->ld_link, createconf->ld_linkid,
745 770 createconf->ld_class, createconf->ld_media, zoneid, &dlconfp);
746 771 if (err == 0) {
747 772 avl_add(&dlmgmt_dlconf_avl, dlconfp);
748 773 dlmgmt_advance_dlconfid(dlconfp);
749 774 retvalp->lr_confid = dlconfp->ld_id;
750 775 }
751 776 done:
752 777 dlmgmt_dlconf_table_unlock();
753 778 retvalp->lr_err = err;
754 779 }
755 780
756 781 /* ARGSUSED */
757 782 static void
758 783 dlmgmt_setattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
759 784 ucred_t *cred)
760 785 {
761 786 dlmgmt_door_setattr_t *setattr = argp;
762 787 dlmgmt_setattr_retval_t *retvalp = retp;
763 788 dlmgmt_dlconf_t dlconf, *dlconfp;
764 789 int err = 0;
765 790
766 791 /*
767 792 * Hold the writer lock to update the dlconf table.
768 793 */
769 794 dlmgmt_dlconf_table_lock(B_TRUE);
770 795
771 796 dlconf.ld_id = setattr->ld_confid;
772 797 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
773 798 if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
774 799 err = ENOENT;
775 800 goto done;
776 801 }
777 802
778 803 if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
779 804 goto done;
780 805
781 806 err = linkattr_set(&(dlconfp->ld_head), setattr->ld_attr,
782 807 &setattr->ld_attrval, setattr->ld_attrsz, setattr->ld_type);
783 808
784 809 done:
785 810 dlmgmt_dlconf_table_unlock();
786 811 retvalp->lr_err = err;
787 812 }
788 813
789 814 /* ARGSUSED */
790 815 static void
791 816 dlmgmt_unsetconfattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
792 817 ucred_t *cred)
793 818 {
794 819 dlmgmt_door_unsetattr_t *unsetattr = argp;
795 820 dlmgmt_unsetattr_retval_t *retvalp = retp;
796 821 dlmgmt_dlconf_t dlconf, *dlconfp;
797 822 int err = 0;
798 823
799 824 /*
800 825 * Hold the writer lock to update the dlconf table.
801 826 */
802 827 dlmgmt_dlconf_table_lock(B_TRUE);
803 828
804 829 dlconf.ld_id = unsetattr->ld_confid;
805 830 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
806 831 if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
807 832 err = ENOENT;
808 833 goto done;
809 834 }
810 835
811 836 if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
812 837 goto done;
813 838
814 839 linkattr_unset(&(dlconfp->ld_head), unsetattr->ld_attr);
815 840
816 841 done:
817 842 dlmgmt_dlconf_table_unlock();
818 843 retvalp->lr_err = err;
819 844 }
820 845
821 846 /*
822 847 * Note that dlmgmt_openconf() returns a conf ID of a conf AVL tree entry,
823 848 * which is managed by dlmgmtd. The ID is used to find the conf entry when
824 849 * dlmgmt_write_conf() is called. The conf entry contains an ld_gen value
825 850 * (which is the generation number - ll_gen) of the dlmgmt_link_t at the time
826 851 * of dlmgmt_openconf(), and ll_gen changes every time the dlmgmt_link_t
827 852 * changes its attributes. Therefore, dlmgmt_write_conf() can compare ld_gen
828 853 * in the conf entry against the latest dlmgmt_link_t ll_gen value to see if
829 854 * anything has changed between the dlmgmt_openconf() and dlmgmt_writeconf()
830 855 * calls. If so, EAGAIN is returned. This mechanism can ensures atomicity
831 856 * across the pair of dladm_read_conf() and dladm_write_conf() calls.
832 857 */
833 858 /* ARGSUSED */
834 859 static void
835 860 dlmgmt_writeconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
836 861 ucred_t *cred)
837 862 {
838 863 dlmgmt_door_writeconf_t *writeconf = argp;
839 864 dlmgmt_writeconf_retval_t *retvalp = retp;
840 865 dlmgmt_dlconf_t dlconf, *dlconfp;
841 866 dlmgmt_link_t *linkp;
842 867 dlmgmt_linkattr_t *attrp, *next;
843 868 int err = 0;
844 869
845 870 /*
846 871 * Hold the lock to access the dlconf table.
847 872 */
848 873 dlmgmt_dlconf_table_lock(B_TRUE);
849 874
850 875 dlconf.ld_id = writeconf->ld_confid;
851 876 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
852 877 if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
853 878 err = ENOENT;
854 879 goto done;
855 880 }
856 881
857 882 if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
858 883 goto done;
859 884
860 885 /*
861 886 * Hold the writer lock to update the link table.
862 887 */
863 888 dlmgmt_table_lock(B_TRUE);
864 889 linkp = link_by_id(dlconfp->ld_linkid, zoneid);
865 890 if ((linkp == NULL) || (linkp->ll_class != dlconfp->ld_class) ||
866 891 (linkp->ll_media != dlconfp->ld_media) ||
867 892 (strcmp(linkp->ll_link, dlconfp->ld_link) != 0)) {
868 893 /*
869 894 * The link does not exist.
870 895 */
871 896 dlmgmt_table_unlock();
872 897 err = ENOENT;
873 898 goto done;
874 899 }
875 900
876 901 if (linkp->ll_gen != dlconfp->ld_gen) {
877 902 /*
878 903 * Something has changed the link configuration; try again.
879 904 */
880 905 dlmgmt_table_unlock();
881 906 err = EAGAIN;
882 907 goto done;
883 908 }
884 909
885 910 /*
886 911 * Delete the old attribute list.
887 912 */
888 913 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
889 914 next = attrp->lp_next;
890 915 free(attrp->lp_val);
891 916 free(attrp);
892 917 }
893 918 linkp->ll_head = NULL;
894 919
895 920 /*
896 921 * Set the new attribute.
897 922 */
898 923 for (attrp = dlconfp->ld_head; attrp != NULL; attrp = attrp->lp_next) {
899 924 if ((err = linkattr_set(&(linkp->ll_head), attrp->lp_name,
900 925 attrp->lp_val, attrp->lp_sz, attrp->lp_type)) != 0) {
901 926 dlmgmt_table_unlock();
902 927 goto done;
903 928 }
904 929 }
905 930
906 931 linkp->ll_gen++;
907 932 err = dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_PERSIST);
908 933 dlmgmt_table_unlock();
909 934 done:
910 935 dlmgmt_dlconf_table_unlock();
911 936 retvalp->lr_err = err;
912 937 }
913 938
914 939 /* ARGSUSED */
915 940 static void
916 941 dlmgmt_removeconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
917 942 ucred_t *cred)
918 943 {
919 944 dlmgmt_door_removeconf_t *removeconf = argp;
920 945 dlmgmt_removeconf_retval_t *retvalp = retp;
921 946 dlmgmt_link_t *linkp;
922 947 int err;
923 948
924 949 dlmgmt_table_lock(B_TRUE);
925 950 if ((linkp = link_by_id(removeconf->ld_linkid, zoneid)) == NULL) {
926 951 err = ENOENT;
927 952 goto done;
928 953 }
929 954 if (zoneid != GLOBAL_ZONEID && linkp->ll_onloan) {
930 955 /*
931 956 * A non-global zone cannot remove the persistent
932 957 * configuration of a link that is on loan from the global
933 958 * zone.
934 959 */
935 960 err = EACCES;
936 961 goto done;
937 962 }
938 963 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
939 964 goto done;
940 965
941 966 err = dlmgmt_delete_db_entry(linkp, DLMGMT_PERSIST);
942 967 done:
943 968 dlmgmt_table_unlock();
944 969 retvalp->lr_err = err;
945 970 }
946 971
947 972 /* ARGSUSED */
948 973 static void
949 974 dlmgmt_destroyconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
950 975 ucred_t *cred)
951 976 {
952 977 dlmgmt_door_destroyconf_t *destroyconf = argp;
953 978 dlmgmt_destroyconf_retval_t *retvalp = retp;
954 979 dlmgmt_dlconf_t dlconf, *dlconfp;
955 980 int err = 0;
956 981
957 982 /*
958 983 * Hold the writer lock to update the dlconf table.
959 984 */
960 985 dlmgmt_dlconf_table_lock(B_TRUE);
961 986
962 987 dlconf.ld_id = destroyconf->ld_confid;
963 988 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
964 989 if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
965 990 err = ENOENT;
966 991 goto done;
967 992 }
968 993
969 994 if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
970 995 goto done;
971 996
972 997 avl_remove(&dlmgmt_dlconf_avl, dlconfp);
973 998 dlconf_destroy(dlconfp);
974 999
975 1000 done:
976 1001 dlmgmt_dlconf_table_unlock();
977 1002 retvalp->lr_err = err;
978 1003 }
979 1004
980 1005 /*
981 1006 * dlmgmt_openconf() returns a handle of the current configuration, which
982 1007 * is then used to update the configuration by dlmgmt_writeconf(). Therefore,
983 1008 * it requires privileges.
984 1009 *
985 1010 * Further, please see the comments above dladm_write_conf() to see how
986 1011 * ld_gen is used to ensure atomicity across the {dlmgmt_openconf(),
987 1012 * dlmgmt_writeconf()} pair.
988 1013 */
989 1014 /* ARGSUSED */
990 1015 static void
991 1016 dlmgmt_openconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
992 1017 ucred_t *cred)
993 1018 {
994 1019 dlmgmt_door_openconf_t *openconf = argp;
995 1020 dlmgmt_openconf_retval_t *retvalp = retp;
996 1021 dlmgmt_link_t *linkp;
997 1022 datalink_id_t linkid = openconf->ld_linkid;
998 1023 dlmgmt_dlconf_t *dlconfp;
999 1024 dlmgmt_linkattr_t *attrp;
1000 1025 int err = 0;
1001 1026
1002 1027 /*
1003 1028 * Hold the writer lock to update the dlconf table.
1004 1029 */
1005 1030 dlmgmt_dlconf_table_lock(B_TRUE);
1006 1031
1007 1032 /*
1008 1033 * Hold the reader lock to access the link
1009 1034 */
1010 1035 dlmgmt_table_lock(B_FALSE);
1011 1036 linkp = link_by_id(linkid, zoneid);
1012 1037 if ((linkp == NULL) || !(linkp->ll_flags & DLMGMT_PERSIST)) {
1013 1038 /* The persistent link configuration does not exist. */
1014 1039 err = ENOENT;
1015 1040 goto done;
1016 1041 }
1017 1042 if (linkp->ll_onloan && zoneid != GLOBAL_ZONEID) {
1018 1043 /*
1019 1044 * The caller is in a non-global zone and the persistent
1020 1045 * configuration belongs to the global zone.
1021 1046 */
1022 1047 err = EACCES;
1023 1048 goto done;
1024 1049 }
1025 1050
1026 1051 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
1027 1052 goto done;
1028 1053
1029 1054 if ((err = dlconf_create(linkp->ll_link, linkp->ll_linkid,
1030 1055 linkp->ll_class, linkp->ll_media, zoneid, &dlconfp)) != 0)
1031 1056 goto done;
1032 1057
1033 1058 for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next) {
1034 1059 if ((err = linkattr_set(&(dlconfp->ld_head), attrp->lp_name,
1035 1060 attrp->lp_val, attrp->lp_sz, attrp->lp_type)) != 0) {
1036 1061 dlconf_destroy(dlconfp);
1037 1062 goto done;
1038 1063 }
1039 1064 }
1040 1065 dlconfp->ld_gen = linkp->ll_gen;
1041 1066 avl_add(&dlmgmt_dlconf_avl, dlconfp);
1042 1067 dlmgmt_advance_dlconfid(dlconfp);
1043 1068
1044 1069 retvalp->lr_confid = dlconfp->ld_id;
1045 1070 done:
1046 1071 dlmgmt_table_unlock();
1047 1072 dlmgmt_dlconf_table_unlock();
1048 1073 retvalp->lr_err = err;
1049 1074 }
1050 1075
1051 1076 /*
1052 1077 * dlmgmt_getconfsnapshot() returns a read-only snapshot of all the
1053 1078 * configuration, and requires no privileges.
1054 1079 *
1055 1080 * If the given size cannot hold all the configuration, set the size
1056 1081 * that is needed, and return ENOSPC.
1057 1082 */
1058 1083 /* ARGSUSED */
1059 1084 static void
1060 1085 dlmgmt_getconfsnapshot(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1061 1086 ucred_t *cred)
1062 1087 {
1063 1088 dlmgmt_door_getconfsnapshot_t *snapshot = argp;
1064 1089 dlmgmt_getconfsnapshot_retval_t *retvalp = retp;
1065 1090 dlmgmt_link_t *linkp;
1066 1091 datalink_id_t linkid = snapshot->ld_linkid;
1067 1092 dlmgmt_linkattr_t *attrp;
1068 1093 char *buf;
1069 1094 size_t nvlsz;
1070 1095 nvlist_t *nvl = NULL;
1071 1096 int err = 0;
1072 1097
1073 1098 assert(*sz >= sizeof (dlmgmt_getconfsnapshot_retval_t));
1074 1099
1075 1100 /*
1076 1101 * Hold the reader lock to access the link
1077 1102 */
1078 1103 dlmgmt_table_lock(B_FALSE);
1079 1104 linkp = link_by_id(linkid, zoneid);
1080 1105 if ((linkp == NULL) || !(linkp->ll_flags & DLMGMT_PERSIST)) {
1081 1106 /* The persistent link configuration does not exist. */
1082 1107 err = ENOENT;
1083 1108 goto done;
1084 1109 }
1085 1110 if (linkp->ll_onloan && zoneid != GLOBAL_ZONEID) {
1086 1111 /*
1087 1112 * The caller is in a non-global zone and the persistent
1088 1113 * configuration belongs to the global zone.
1089 1114 */
1090 1115 err = EACCES;
1091 1116 goto done;
1092 1117 }
1093 1118
1094 1119 err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0);
1095 1120 if (err != 0)
1096 1121 goto done;
1097 1122
1098 1123 for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next) {
1099 1124 if ((err = nvlist_add_byte_array(nvl, attrp->lp_name,
1100 1125 attrp->lp_val, attrp->lp_sz)) != 0) {
1101 1126 goto done;
1102 1127 }
1103 1128 }
1104 1129
1105 1130 if ((err = nvlist_size(nvl, &nvlsz, NV_ENCODE_NATIVE)) != 0)
1106 1131 goto done;
1107 1132
1108 1133 if (nvlsz + sizeof (dlmgmt_getconfsnapshot_retval_t) > *sz) {
1109 1134 *sz = nvlsz + sizeof (dlmgmt_getconfsnapshot_retval_t);
1110 1135 err = ENOSPC;
1111 1136 goto done;
1112 1137 }
1113 1138
1114 1139 /*
1115 1140 * pack the the nvlist into the return value.
1116 1141 */
1117 1142 *sz = nvlsz + sizeof (dlmgmt_getconfsnapshot_retval_t);
1118 1143 retvalp->lr_nvlsz = nvlsz;
1119 1144 buf = (char *)retvalp + sizeof (dlmgmt_getconfsnapshot_retval_t);
1120 1145 err = nvlist_pack(nvl, &buf, &nvlsz, NV_ENCODE_NATIVE, 0);
1121 1146
1122 1147 done:
1123 1148 dlmgmt_table_unlock();
1124 1149 nvlist_free(nvl);
1125 1150 retvalp->lr_err = err;
1126 1151 }
1127 1152
1128 1153 /* ARGSUSED */
1129 1154 static void
1130 1155 dlmgmt_getattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1131 1156 ucred_t *cred)
1132 1157 {
1133 1158 dlmgmt_door_getattr_t *getattr = argp;
1134 1159 dlmgmt_getattr_retval_t *retvalp = retp;
1135 1160 dlmgmt_dlconf_t dlconf, *dlconfp;
1136 1161 int err;
1137 1162
1138 1163 /*
1139 1164 * Hold the read lock to access the dlconf table.
1140 1165 */
1141 1166 dlmgmt_dlconf_table_lock(B_FALSE);
1142 1167
1143 1168 dlconf.ld_id = getattr->ld_confid;
1144 1169 if ((dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL)) == NULL ||
1145 1170 zoneid != dlconfp->ld_zoneid) {
1146 1171 retvalp->lr_err = ENOENT;
1147 1172 } else {
1148 1173 if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0) {
1149 1174 retvalp->lr_err = err;
1150 1175 } else {
1151 1176 retvalp->lr_err = dlmgmt_getattr_common(
1152 1177 &dlconfp->ld_head, getattr->ld_attr, retvalp);
1153 1178 }
1154 1179 }
1155 1180
1156 1181 dlmgmt_dlconf_table_unlock();
1157 1182 }
1158 1183
1159 1184 /* ARGSUSED */
1160 1185 static void
1161 1186 dlmgmt_upcall_linkprop_init(void *argp, void *retp, size_t *sz,
1162 1187 zoneid_t zoneid, ucred_t *cred)
1163 1188 {
1164 1189 dlmgmt_door_linkprop_init_t *lip = argp;
1165 1190 dlmgmt_linkprop_init_retval_t *retvalp = retp;
1166 1191 dlmgmt_link_t *linkp;
1167 1192 int err;
1168 1193
1169 1194 dlmgmt_table_lock(B_FALSE);
1170 1195 if ((linkp = link_by_id(lip->ld_linkid, zoneid)) == NULL)
1171 1196 err = ENOENT;
1172 1197 else
1173 1198 err = dlmgmt_checkprivs(linkp->ll_class, cred);
1174 1199 dlmgmt_table_unlock();
1175 1200
1176 1201 if (err == 0) {
1177 1202 dladm_status_t s;
1178 1203 char buf[DLADM_STRSIZE];
1179 1204
1180 1205 s = dladm_init_linkprop(dld_handle, lip->ld_linkid, B_TRUE);
1181 1206 if (s != DLADM_STATUS_OK) {
1182 1207 dlmgmt_log(LOG_WARNING,
1183 1208 "linkprop initialization failed on link %d: %s",
1184 1209 lip->ld_linkid, dladm_status2str(s, buf));
1185 1210 err = EINVAL;
1186 1211 }
1187 1212 }
1188 1213 retvalp->lr_err = err;
1189 1214 }
1190 1215
1191 1216 /* ARGSUSED */
1192 1217 static void
1193 1218 dlmgmt_setzoneid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1194 1219 ucred_t *cred)
1195 1220 {
1196 1221 dlmgmt_door_setzoneid_t *setzoneid = argp;
1197 1222 dlmgmt_setzoneid_retval_t *retvalp = retp;
1198 1223 dlmgmt_link_t *linkp;
1199 1224 datalink_id_t linkid = setzoneid->ld_linkid;
1200 1225 zoneid_t oldzoneid, newzoneid;
1201 1226 int err = 0;
1202 1227
1203 1228 dlmgmt_table_lock(B_TRUE);
1204 1229
1205 1230 /* We currently only allow changing zoneid's from the global zone. */
1206 1231 if (zoneid != GLOBAL_ZONEID) {
1207 1232 err = EACCES;
1208 1233 goto done;
|
↓ open down ↓ |
487 lines elided |
↑ open up ↑ |
1209 1234 }
1210 1235
1211 1236 if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
1212 1237 err = ENOENT;
1213 1238 goto done;
1214 1239 }
1215 1240
1216 1241 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
1217 1242 goto done;
1218 1243
1244 + if (linkp->ll_tomb == B_TRUE) {
1245 + err = EBUSY;
1246 + goto done;
1247 + }
1248 +
1219 1249 /* We can only assign an active link to a zone. */
1220 1250 if (!(linkp->ll_flags & DLMGMT_ACTIVE)) {
1221 1251 err = EINVAL;
1222 1252 goto done;
1223 1253 }
1224 1254
1225 1255 oldzoneid = linkp->ll_zoneid;
1226 1256 newzoneid = setzoneid->ld_zoneid;
1227 1257
1228 1258 if (oldzoneid == newzoneid)
1229 1259 goto done;
1230 1260
1231 1261 /*
1232 1262 * Before we remove the link from its current zone, make sure that
1233 1263 * there isn't a link with the same name in the destination zone.
1234 1264 */
1235 1265 if (zoneid != GLOBAL_ZONEID &&
1236 1266 link_by_name(linkp->ll_link, newzoneid) != NULL) {
1237 1267 err = EEXIST;
|
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
1238 1268 goto done;
1239 1269 }
1240 1270
1241 1271 if (oldzoneid != GLOBAL_ZONEID) {
1242 1272 if (zone_remove_datalink(oldzoneid, linkid) != 0) {
1243 1273 err = errno;
1244 1274 dlmgmt_log(LOG_WARNING, "unable to remove link %d from "
1245 1275 "zone %d: %s", linkid, oldzoneid, strerror(err));
1246 1276 goto done;
1247 1277 }
1248 - avl_remove(&dlmgmt_loan_avl, linkp);
1278 +
1279 + if (newzoneid == GLOBAL_ZONEID && linkp->ll_onloan) {
1280 + /*
1281 + * We can only reassign a loaned VNIC back to the
1282 + * global zone when the zone is shutting down, since
1283 + * otherwise the VNIC is in use by the zone and will be
1284 + * busy. Leave the VNIC assigned to the zone so we can
1285 + * still see it and delete it when dlmgmt_zonehalt()
1286 + * runs.
1287 + */
1288 + goto done;
1289 + }
1290 +
1249 1291 linkp->ll_onloan = B_FALSE;
1250 1292 }
1251 1293 if (newzoneid != GLOBAL_ZONEID) {
1252 1294 if (zone_add_datalink(newzoneid, linkid) != 0) {
1253 1295 err = errno;
1254 1296 dlmgmt_log(LOG_WARNING, "unable to add link %d to zone "
1255 1297 "%d: %s", linkid, newzoneid, strerror(err));
1256 1298 (void) zone_add_datalink(oldzoneid, linkid);
1257 1299 goto done;
1258 1300 }
1259 - avl_add(&dlmgmt_loan_avl, linkp);
1260 1301 linkp->ll_onloan = B_TRUE;
1261 1302 }
1262 1303
1263 1304 avl_remove(&dlmgmt_name_avl, linkp);
1264 1305 linkp->ll_zoneid = newzoneid;
1265 1306 avl_add(&dlmgmt_name_avl, linkp);
1266 1307
1267 1308 done:
1268 1309 dlmgmt_table_unlock();
1269 1310 retvalp->lr_err = err;
1270 1311 }
1271 1312
1272 1313 /* ARGSUSED */
1273 1314 static void
1274 1315 dlmgmt_zoneboot(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1275 1316 ucred_t *cred)
1276 1317 {
1277 1318 int err;
1278 1319 dlmgmt_door_zoneboot_t *zoneboot = argp;
1279 1320 dlmgmt_zoneboot_retval_t *retvalp = retp;
1280 1321
1281 1322 dlmgmt_table_lock(B_TRUE);
1282 1323
1283 1324 if ((err = dlmgmt_checkprivs(0, cred)) != 0)
1284 1325 goto done;
1285 1326
1286 1327 if (zoneid != GLOBAL_ZONEID) {
1287 1328 err = EACCES;
1288 1329 goto done;
1289 1330 }
1290 1331 if (zoneboot->ld_zoneid == GLOBAL_ZONEID) {
1291 1332 err = EINVAL;
1292 1333 goto done;
1293 1334 }
1294 1335
1295 1336 if ((err = dlmgmt_elevate_privileges()) == 0) {
1296 1337 err = dlmgmt_zone_init(zoneboot->ld_zoneid);
1297 1338 (void) dlmgmt_drop_privileges();
1298 1339 }
1299 1340 done:
1300 1341 dlmgmt_table_unlock();
1301 1342 retvalp->lr_err = err;
|
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
1302 1343 }
1303 1344
1304 1345 /* ARGSUSED */
1305 1346 static void
1306 1347 dlmgmt_zonehalt(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1307 1348 ucred_t *cred)
1308 1349 {
1309 1350 int err = 0;
1310 1351 dlmgmt_door_zonehalt_t *zonehalt = argp;
1311 1352 dlmgmt_zonehalt_retval_t *retvalp = retp;
1353 + static char my_pid[10];
1312 1354
1355 + if (my_pid[0] == NULL)
1356 + (void) snprintf(my_pid, sizeof (my_pid), "%d\n", getpid());
1357 +
1313 1358 if ((err = dlmgmt_checkprivs(0, cred)) == 0) {
1314 1359 if (zoneid != GLOBAL_ZONEID) {
1315 1360 err = EACCES;
1316 1361 } else if (zonehalt->ld_zoneid == GLOBAL_ZONEID) {
1317 1362 err = EINVAL;
1318 1363 } else {
1364 + /*
1365 + * dls and mac don't honor the locking rules defined in
1366 + * mac. In order to try and make that case less likely
1367 + * to happen, we try to serialize some of the zone
1368 + * activity here between dlmgmtd and the brands on
1369 + * /etc/dladm/zone.lck
1370 + */
1371 + int fd;
1372 +
1373 + while ((fd = open(ZONE_LOCK, O_WRONLY |
1374 + O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
1375 + (void) sleep(1);
1376 + (void) write(fd, my_pid, sizeof (my_pid));
1377 + (void) close(fd);
1378 +
1319 1379 dlmgmt_table_lock(B_TRUE);
1320 1380 dlmgmt_db_fini(zonehalt->ld_zoneid);
1321 1381 dlmgmt_table_unlock();
1382 +
1383 + (void) unlink(ZONE_LOCK);
1322 1384 }
1323 1385 }
1324 1386 retvalp->lr_err = err;
1325 1387 }
1326 1388
1327 1389 static dlmgmt_door_info_t i_dlmgmt_door_info_tbl[] = {
1328 1390 { DLMGMT_CMD_DLS_CREATE, sizeof (dlmgmt_upcall_arg_create_t),
1329 1391 sizeof (dlmgmt_create_retval_t), dlmgmt_upcall_create },
1330 1392 { DLMGMT_CMD_DLS_GETATTR, sizeof (dlmgmt_upcall_arg_getattr_t),
1331 1393 sizeof (dlmgmt_getattr_retval_t), dlmgmt_upcall_getattr },
1332 1394 { DLMGMT_CMD_DLS_DESTROY, sizeof (dlmgmt_upcall_arg_destroy_t),
1333 1395 sizeof (dlmgmt_destroy_retval_t), dlmgmt_upcall_destroy },
1334 1396 { DLMGMT_CMD_GETNAME, sizeof (dlmgmt_door_getname_t),
1335 1397 sizeof (dlmgmt_getname_retval_t), dlmgmt_getname },
1336 1398 { DLMGMT_CMD_GETLINKID, sizeof (dlmgmt_door_getlinkid_t),
1337 1399 sizeof (dlmgmt_getlinkid_retval_t), dlmgmt_getlinkid },
1338 1400 { DLMGMT_CMD_GETNEXT, sizeof (dlmgmt_door_getnext_t),
1339 1401 sizeof (dlmgmt_getnext_retval_t), dlmgmt_getnext },
1340 1402 { DLMGMT_CMD_DLS_UPDATE, sizeof (dlmgmt_upcall_arg_update_t),
1341 1403 sizeof (dlmgmt_update_retval_t), dlmgmt_upcall_update },
1342 1404 { DLMGMT_CMD_CREATE_LINKID, sizeof (dlmgmt_door_createid_t),
1343 1405 sizeof (dlmgmt_createid_retval_t), dlmgmt_createid },
1344 1406 { DLMGMT_CMD_DESTROY_LINKID, sizeof (dlmgmt_door_destroyid_t),
1345 1407 sizeof (dlmgmt_destroyid_retval_t), dlmgmt_destroyid },
1346 1408 { DLMGMT_CMD_REMAP_LINKID, sizeof (dlmgmt_door_remapid_t),
1347 1409 sizeof (dlmgmt_remapid_retval_t), dlmgmt_remapid },
1348 1410 { DLMGMT_CMD_CREATECONF, sizeof (dlmgmt_door_createconf_t),
1349 1411 sizeof (dlmgmt_createconf_retval_t), dlmgmt_createconf },
1350 1412 { DLMGMT_CMD_OPENCONF, sizeof (dlmgmt_door_openconf_t),
1351 1413 sizeof (dlmgmt_openconf_retval_t), dlmgmt_openconf },
1352 1414 { DLMGMT_CMD_WRITECONF, sizeof (dlmgmt_door_writeconf_t),
1353 1415 sizeof (dlmgmt_writeconf_retval_t), dlmgmt_writeconf },
1354 1416 { DLMGMT_CMD_UP_LINKID, sizeof (dlmgmt_door_upid_t),
1355 1417 sizeof (dlmgmt_upid_retval_t), dlmgmt_upid },
1356 1418 { DLMGMT_CMD_SETATTR, sizeof (dlmgmt_door_setattr_t),
1357 1419 sizeof (dlmgmt_setattr_retval_t), dlmgmt_setattr },
1358 1420 { DLMGMT_CMD_UNSETATTR, sizeof (dlmgmt_door_unsetattr_t),
1359 1421 sizeof (dlmgmt_unsetattr_retval_t), dlmgmt_unsetconfattr },
1360 1422 { DLMGMT_CMD_REMOVECONF, sizeof (dlmgmt_door_removeconf_t),
1361 1423 sizeof (dlmgmt_removeconf_retval_t), dlmgmt_removeconf },
1362 1424 { DLMGMT_CMD_DESTROYCONF, sizeof (dlmgmt_door_destroyconf_t),
1363 1425 sizeof (dlmgmt_destroyconf_retval_t), dlmgmt_destroyconf },
1364 1426 { DLMGMT_CMD_GETATTR, sizeof (dlmgmt_door_getattr_t),
1365 1427 sizeof (dlmgmt_getattr_retval_t), dlmgmt_getattr },
1366 1428 { DLMGMT_CMD_GETCONFSNAPSHOT, sizeof (dlmgmt_door_getconfsnapshot_t),
1367 1429 sizeof (dlmgmt_getconfsnapshot_retval_t), dlmgmt_getconfsnapshot },
1368 1430 { DLMGMT_CMD_LINKPROP_INIT, sizeof (dlmgmt_door_linkprop_init_t),
1369 1431 sizeof (dlmgmt_linkprop_init_retval_t),
1370 1432 dlmgmt_upcall_linkprop_init },
1371 1433 { DLMGMT_CMD_SETZONEID, sizeof (dlmgmt_door_setzoneid_t),
1372 1434 sizeof (dlmgmt_setzoneid_retval_t), dlmgmt_setzoneid },
1373 1435 { DLMGMT_CMD_ZONEBOOT, sizeof (dlmgmt_door_zoneboot_t),
1374 1436 sizeof (dlmgmt_zoneboot_retval_t), dlmgmt_zoneboot },
1375 1437 { DLMGMT_CMD_ZONEHALT, sizeof (dlmgmt_door_zonehalt_t),
1376 1438 sizeof (dlmgmt_zonehalt_retval_t), dlmgmt_zonehalt },
1377 1439 { 0, 0, 0, NULL }
1378 1440 };
1379 1441
1380 1442 static dlmgmt_door_info_t *
1381 1443 dlmgmt_getcmdinfo(int cmd)
1382 1444 {
1383 1445 dlmgmt_door_info_t *infop = i_dlmgmt_door_info_tbl;
1384 1446
1385 1447 while (infop->di_handler != NULL) {
1386 1448 if (infop->di_cmd == cmd)
1387 1449 break;
1388 1450 infop++;
1389 1451 }
1390 1452 return (infop);
1391 1453 }
1392 1454
1393 1455 /* ARGSUSED */
1394 1456 void
1395 1457 dlmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
1396 1458 uint_t n_desc)
1397 1459 {
1398 1460 dlmgmt_door_arg_t *door_arg = (dlmgmt_door_arg_t *)(void *)argp;
1399 1461 dlmgmt_door_info_t *infop = NULL;
1400 1462 dlmgmt_retval_t retval;
1401 1463 ucred_t *cred = NULL;
1402 1464 zoneid_t zoneid;
1403 1465 void *retvalp = NULL;
1404 1466 size_t sz, acksz;
1405 1467 int err = 0;
1406 1468
1407 1469 infop = dlmgmt_getcmdinfo(door_arg->ld_cmd);
1408 1470 if (infop == NULL || argsz != infop->di_reqsz) {
1409 1471 err = EINVAL;
1410 1472 goto done;
1411 1473 }
1412 1474
1413 1475 if (door_ucred(&cred) != 0 || (zoneid = ucred_getzoneid(cred)) == -1) {
1414 1476 err = errno;
1415 1477 goto done;
1416 1478 }
1417 1479
1418 1480 /*
1419 1481 * Note that malloc() cannot be used here because door_return
1420 1482 * never returns, and memory allocated by malloc() would get leaked.
1421 1483 * Use alloca() instead.
1422 1484 */
1423 1485 acksz = infop->di_acksz;
1424 1486
1425 1487 again:
1426 1488 retvalp = alloca(acksz);
1427 1489 sz = acksz;
1428 1490 infop->di_handler(argp, retvalp, &acksz, zoneid, cred);
1429 1491 if (acksz > sz) {
1430 1492 /*
1431 1493 * If the specified buffer size is not big enough to hold the
1432 1494 * return value, reallocate the buffer and try to get the
1433 1495 * result one more time.
1434 1496 */
1435 1497 assert(((dlmgmt_retval_t *)retvalp)->lr_err == ENOSPC);
1436 1498 goto again;
1437 1499 }
1438 1500
1439 1501 done:
1440 1502 if (cred != NULL)
1441 1503 ucred_free(cred);
1442 1504 if (err == 0) {
1443 1505 (void) door_return(retvalp, acksz, NULL, 0);
1444 1506 } else {
1445 1507 retval.lr_err = err;
1446 1508 (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
1447 1509 }
1448 1510 }
|
↓ open down ↓ |
117 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX