Print this page
Forgot to merge in unlink of ZONE_LOCK in dlmgmtd.
dlmgmt mismerge
Mismerge dlmgmt_door.c
OS-3342 dlmgmtd needs to be mindful of lock ordering
OS-2608 dlmgmtd needs to record zone identifiers
OS-3492 zone_free asserts to its destruction when dlmgmtd has fallen
OS-3494 zoneadmd tears down networking too soon when boot fails
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
| 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
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 24 */
25 25
26 26 /*
27 27 * Main door handler functions used by dlmgmtd to process the different door
28 28 * call requests. Door call requests can come from the user-land applications,
29 29 * or from the kernel.
30 30 *
31 31 * Note on zones handling:
32 32 *
33 33 * There are two zoneid's associated with a link. One is the zoneid of the
34 34 * zone in which the link was created (ll_zoneid in the dlmgmt_link_t), and
35 35 * the other is the zoneid of the zone where the link is currently assigned
36 36 * (the "zone" link property). The two can be different if a datalink is
37 37 * created in the global zone and subsequently assigned to a non-global zone
38 38 * via zonecfg or via explicitly setting the "zone" link property.
39 39 *
40 40 * Door clients can see links that were created in their zone, and links that
41 41 * are currently assigned to their zone. Door clients in a zone can only
42 42 * modify links that were created in their zone.
43 43 *
44 44 * The datalink ID space is global, while each zone has its own datalink name
45 45 * space. This allows each zone to have complete freedom over the names that
46 46 * they assign to links created within the zone.
47 47 */
48 48
49 49 #include <assert.h>
50 50 #include <alloca.h>
|
↓ open down ↓ |
50 lines elided |
↑ open up ↑ |
51 51 #include <errno.h>
52 52 #include <priv_utils.h>
53 53 #include <stdlib.h>
54 54 #include <strings.h>
55 55 #include <syslog.h>
56 56 #include <sys/sysevent/eventdefs.h>
57 57 #include <zone.h>
58 58 #include <libsysevent.h>
59 59 #include <libdlmgmt.h>
60 60 #include <librcm.h>
61 +#include <sys/types.h>
62 +#include <sys/stat.h>
63 +#include <fcntl.h>
64 +#include <unistd.h>
61 65 #include "dlmgmt_impl.h"
62 66
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 ↓ |
299 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
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
442 452 /*
443 453 * Hold the reader lock to access the link
444 454 */
445 455 dlmgmt_table_lock(B_FALSE);
446 456
447 457 if ((linkp = link_by_name(getlinkid->ld_link, zoneid)) == NULL) {
448 458 /*
449 459 * The link does not exist in this zone.
450 460 */
451 461 err = ENOENT;
452 462 goto done;
453 463 }
454 464
455 465 retvalp->lr_linkid = linkp->ll_linkid;
456 466 retvalp->lr_flags = linkp->ll_flags;
457 467 retvalp->lr_class = linkp->ll_class;
458 468 retvalp->lr_media = linkp->ll_media;
459 469
460 470 done:
461 471 dlmgmt_table_unlock();
462 472 retvalp->lr_err = err;
463 473 }
464 474
465 475 /* ARGSUSED */
466 476 static void
467 477 dlmgmt_getnext(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
468 478 ucred_t *cred)
469 479 {
470 480 dlmgmt_door_getnext_t *getnext = argp;
471 481 dlmgmt_getnext_retval_t *retvalp = retp;
472 482 dlmgmt_link_t link, *linkp;
473 483 avl_index_t where;
474 484 int err = 0;
475 485
476 486 /*
477 487 * Hold the reader lock to access the link
478 488 */
479 489 dlmgmt_table_lock(B_FALSE);
480 490
481 491 link.ll_linkid = (getnext->ld_linkid + 1);
482 492 if ((linkp = avl_find(&dlmgmt_id_avl, &link, &where)) == NULL)
483 493 linkp = avl_nearest(&dlmgmt_id_avl, where, AVL_AFTER);
484 494
485 495 for (; linkp != NULL; linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
486 496 if (!link_is_visible(linkp, zoneid))
487 497 continue;
488 498 if ((linkp->ll_class & getnext->ld_class) &&
489 499 (linkp->ll_flags & getnext->ld_flags) &&
490 500 DATALINK_MEDIA_ACCEPTED(getnext->ld_dmedia,
491 501 linkp->ll_media))
492 502 break;
493 503 }
494 504
495 505 if (linkp == NULL) {
496 506 err = ENOENT;
497 507 } else {
498 508 retvalp->lr_linkid = linkp->ll_linkid;
499 509 retvalp->lr_class = linkp->ll_class;
500 510 retvalp->lr_media = linkp->ll_media;
501 511 retvalp->lr_flags = linkp->ll_flags;
502 512 }
503 513
504 514 dlmgmt_table_unlock();
505 515 retvalp->lr_err = err;
506 516 }
507 517
508 518 /* ARGSUSED */
509 519 static void
510 520 dlmgmt_upcall_getattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
511 521 ucred_t *cred)
512 522 {
513 523 dlmgmt_upcall_arg_getattr_t *getattr = argp;
514 524 dlmgmt_getattr_retval_t *retvalp = retp;
515 525 dlmgmt_link_t *linkp;
516 526
517 527 /*
518 528 * Hold the reader lock to access the link
519 529 */
520 530 dlmgmt_table_lock(B_FALSE);
521 531 if ((linkp = link_by_id(getattr->ld_linkid, zoneid)) == NULL) {
522 532 retvalp->lr_err = ENOENT;
523 533 } else {
524 534 retvalp->lr_err = dlmgmt_getattr_common(&linkp->ll_head,
525 535 getattr->ld_attr, retvalp);
526 536 }
527 537 dlmgmt_table_unlock();
528 538 }
529 539
530 540 /* ARGSUSED */
531 541 static void
532 542 dlmgmt_createid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
533 543 ucred_t *cred)
534 544 {
535 545 dlmgmt_door_createid_t *createid = argp;
536 546 dlmgmt_createid_retval_t *retvalp = retp;
537 547 dlmgmt_link_t *linkp;
538 548 datalink_id_t linkid = DATALINK_INVALID_LINKID;
539 549 char link[MAXLINKNAMELEN];
540 550 int err;
541 551
542 552 /*
543 553 * Hold the writer lock to update the dlconf table.
544 554 */
545 555 dlmgmt_table_lock(B_TRUE);
546 556
547 557 if ((err = dlmgmt_checkprivs(createid->ld_class, cred)) != 0)
548 558 goto done;
549 559
550 560 if (createid->ld_prefix) {
551 561 err = dlmgmt_generate_name(createid->ld_link, link,
552 562 MAXLINKNAMELEN, zoneid);
553 563 if (err != 0)
554 564 goto done;
555 565
556 566 err = dlmgmt_create_common(link, createid->ld_class,
557 567 createid->ld_media, zoneid, createid->ld_flags, &linkp);
558 568 } else {
559 569 err = dlmgmt_create_common(createid->ld_link,
560 570 createid->ld_class, createid->ld_media, zoneid,
561 571 createid->ld_flags, &linkp);
562 572 }
563 573
564 574 if (err == 0) {
565 575 /*
566 576 * Keep the active mapping.
567 577 */
568 578 linkid = linkp->ll_linkid;
569 579 if (createid->ld_flags & DLMGMT_ACTIVE) {
570 580 (void) dlmgmt_write_db_entry(linkp->ll_link, linkp,
571 581 DLMGMT_ACTIVE);
572 582 }
573 583 }
574 584
575 585 done:
576 586 dlmgmt_table_unlock();
577 587 retvalp->lr_linkid = linkid;
578 588 retvalp->lr_err = err;
579 589 }
580 590
581 591 /* ARGSUSED */
582 592 static void
583 593 dlmgmt_destroyid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
584 594 ucred_t *cred)
585 595 {
586 596 dlmgmt_door_destroyid_t *destroyid = argp;
587 597 dlmgmt_destroyid_retval_t *retvalp = retp;
588 598 datalink_id_t linkid = destroyid->ld_linkid;
589 599 uint32_t flags = destroyid->ld_flags;
590 600 dlmgmt_link_t *linkp = NULL;
591 601 int err = 0;
592 602
593 603 /*
594 604 * Hold the writer lock to update the link table.
595 605 */
596 606 dlmgmt_table_lock(B_TRUE);
597 607 if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
598 608 err = ENOENT;
599 609 goto done;
600 610 }
601 611
602 612 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
603 613 goto done;
604 614
605 615 /*
606 616 * Delete the active mapping.
607 617 */
608 618 if (flags & DLMGMT_ACTIVE)
609 619 err = dlmgmt_delete_db_entry(linkp, DLMGMT_ACTIVE);
610 620 if (err == 0)
611 621 err = dlmgmt_destroy_common(linkp, flags);
612 622 done:
613 623 dlmgmt_table_unlock();
614 624 retvalp->lr_err = err;
615 625 }
616 626
617 627 /*
618 628 * Remap a linkid to a given link name, i.e., rename an existing link1
619 629 * (ld_linkid) to a non-existent link2 (ld_link): rename link1's name to
620 630 * the given link name.
621 631 */
622 632 /* ARGSUSED */
623 633 static void
624 634 dlmgmt_remapid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
625 635 ucred_t *cred)
626 636 {
627 637 dlmgmt_door_remapid_t *remapid = argp;
628 638 dlmgmt_remapid_retval_t *retvalp = retp;
629 639 dlmgmt_link_t *linkp;
630 640 char oldname[MAXLINKNAMELEN];
631 641 boolean_t renamed = B_FALSE;
632 642 int err = 0;
633 643
634 644 if (!dladm_valid_linkname(remapid->ld_link)) {
635 645 retvalp->lr_err = EINVAL;
636 646 return;
637 647 }
638 648
639 649 /*
640 650 * Hold the writer lock to update the link table.
|
↓ open down ↓ |
249 lines elided |
↑ open up ↑ |
641 651 */
642 652 dlmgmt_table_lock(B_TRUE);
643 653 if ((linkp = link_by_id(remapid->ld_linkid, zoneid)) == NULL) {
644 654 err = ENOENT;
645 655 goto done;
646 656 }
647 657
648 658 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
649 659 goto done;
650 660
661 + if (linkp->ll_tomb == B_TRUE) {
662 + err = EBUSY;
663 + goto done;
664 + }
665 +
666 +
651 667 if (link_by_name(remapid->ld_link, linkp->ll_zoneid) != NULL) {
652 668 err = EEXIST;
653 669 goto done;
654 670 }
655 671
656 672 (void) strlcpy(oldname, linkp->ll_link, MAXLINKNAMELEN);
657 673 avl_remove(&dlmgmt_name_avl, linkp);
658 674 (void) strlcpy(linkp->ll_link, remapid->ld_link, MAXLINKNAMELEN);
659 675 avl_add(&dlmgmt_name_avl, linkp);
660 676 renamed = B_TRUE;
661 677
662 678 if (linkp->ll_flags & DLMGMT_ACTIVE) {
663 679 err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_ACTIVE);
664 680 if (err != 0)
665 681 goto done;
666 682 }
667 683 if (linkp->ll_flags & DLMGMT_PERSIST) {
668 684 err = dlmgmt_write_db_entry(oldname, linkp, DLMGMT_PERSIST);
669 685 if (err != 0) {
670 686 if (linkp->ll_flags & DLMGMT_ACTIVE) {
671 687 (void) dlmgmt_write_db_entry(remapid->ld_link,
672 688 linkp, DLMGMT_ACTIVE);
673 689 }
674 690 goto done;
675 691 }
676 692 }
677 693
678 694 dlmgmt_advance(linkp);
679 695 linkp->ll_gen++;
680 696 done:
681 697 if (err != 0 && renamed) {
682 698 avl_remove(&dlmgmt_name_avl, linkp);
683 699 (void) strlcpy(linkp->ll_link, oldname, MAXLINKNAMELEN);
684 700 avl_add(&dlmgmt_name_avl, linkp);
685 701 }
686 702 dlmgmt_table_unlock();
687 703 retvalp->lr_err = err;
688 704 }
689 705
690 706 /* ARGSUSED */
691 707 static void
692 708 dlmgmt_upid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
693 709 ucred_t *cred)
694 710 {
695 711 dlmgmt_door_upid_t *upid = argp;
696 712 dlmgmt_upid_retval_t *retvalp = retp;
697 713 dlmgmt_link_t *linkp;
698 714 int err = 0;
699 715
700 716 /*
701 717 * Hold the writer lock to update the link table.
|
↓ open down ↓ |
41 lines elided |
↑ open up ↑ |
702 718 */
703 719 dlmgmt_table_lock(B_TRUE);
704 720 if ((linkp = link_by_id(upid->ld_linkid, zoneid)) == NULL) {
705 721 err = ENOENT;
706 722 goto done;
707 723 }
708 724
709 725 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
710 726 goto done;
711 727
728 + if (linkp->ll_tomb == B_TRUE) {
729 + err = EBUSY;
730 + goto done;
731 + }
732 +
712 733 if (linkp->ll_flags & DLMGMT_ACTIVE) {
713 734 err = EINVAL;
714 735 goto done;
715 736 }
716 737
717 738 if ((err = link_activate(linkp)) == 0) {
718 739 (void) dlmgmt_write_db_entry(linkp->ll_link, linkp,
719 740 DLMGMT_ACTIVE);
720 741 }
721 742 done:
722 743 dlmgmt_table_unlock();
723 744 retvalp->lr_err = err;
724 745 }
725 746
726 747 /* ARGSUSED */
727 748 static void
728 749 dlmgmt_createconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
729 750 ucred_t *cred)
730 751 {
731 752 dlmgmt_door_createconf_t *createconf = argp;
732 753 dlmgmt_createconf_retval_t *retvalp = retp;
733 754 dlmgmt_dlconf_t *dlconfp;
734 755 int err;
735 756
736 757 /*
737 758 * Hold the writer lock to update the dlconf table.
738 759 */
739 760 dlmgmt_dlconf_table_lock(B_TRUE);
740 761
741 762 if ((err = dlmgmt_checkprivs(createconf->ld_class, cred)) != 0)
742 763 goto done;
743 764
744 765 err = dlconf_create(createconf->ld_link, createconf->ld_linkid,
745 766 createconf->ld_class, createconf->ld_media, zoneid, &dlconfp);
746 767 if (err == 0) {
747 768 avl_add(&dlmgmt_dlconf_avl, dlconfp);
748 769 dlmgmt_advance_dlconfid(dlconfp);
749 770 retvalp->lr_confid = dlconfp->ld_id;
750 771 }
751 772 done:
752 773 dlmgmt_dlconf_table_unlock();
753 774 retvalp->lr_err = err;
754 775 }
755 776
756 777 /* ARGSUSED */
757 778 static void
758 779 dlmgmt_setattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
759 780 ucred_t *cred)
760 781 {
761 782 dlmgmt_door_setattr_t *setattr = argp;
762 783 dlmgmt_setattr_retval_t *retvalp = retp;
763 784 dlmgmt_dlconf_t dlconf, *dlconfp;
764 785 int err = 0;
765 786
766 787 /*
767 788 * Hold the writer lock to update the dlconf table.
768 789 */
769 790 dlmgmt_dlconf_table_lock(B_TRUE);
770 791
771 792 dlconf.ld_id = setattr->ld_confid;
772 793 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
773 794 if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
774 795 err = ENOENT;
775 796 goto done;
776 797 }
777 798
778 799 if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
779 800 goto done;
780 801
781 802 err = linkattr_set(&(dlconfp->ld_head), setattr->ld_attr,
782 803 &setattr->ld_attrval, setattr->ld_attrsz, setattr->ld_type);
783 804
784 805 done:
785 806 dlmgmt_dlconf_table_unlock();
786 807 retvalp->lr_err = err;
787 808 }
788 809
789 810 /* ARGSUSED */
790 811 static void
791 812 dlmgmt_unsetconfattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
792 813 ucred_t *cred)
793 814 {
794 815 dlmgmt_door_unsetattr_t *unsetattr = argp;
795 816 dlmgmt_unsetattr_retval_t *retvalp = retp;
796 817 dlmgmt_dlconf_t dlconf, *dlconfp;
797 818 int err = 0;
798 819
799 820 /*
800 821 * Hold the writer lock to update the dlconf table.
801 822 */
802 823 dlmgmt_dlconf_table_lock(B_TRUE);
803 824
804 825 dlconf.ld_id = unsetattr->ld_confid;
805 826 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
806 827 if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
807 828 err = ENOENT;
808 829 goto done;
809 830 }
810 831
811 832 if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
812 833 goto done;
813 834
814 835 linkattr_unset(&(dlconfp->ld_head), unsetattr->ld_attr);
815 836
816 837 done:
817 838 dlmgmt_dlconf_table_unlock();
818 839 retvalp->lr_err = err;
819 840 }
820 841
821 842 /*
822 843 * Note that dlmgmt_openconf() returns a conf ID of a conf AVL tree entry,
823 844 * which is managed by dlmgmtd. The ID is used to find the conf entry when
824 845 * dlmgmt_write_conf() is called. The conf entry contains an ld_gen value
825 846 * (which is the generation number - ll_gen) of the dlmgmt_link_t at the time
826 847 * of dlmgmt_openconf(), and ll_gen changes every time the dlmgmt_link_t
827 848 * changes its attributes. Therefore, dlmgmt_write_conf() can compare ld_gen
828 849 * in the conf entry against the latest dlmgmt_link_t ll_gen value to see if
829 850 * anything has changed between the dlmgmt_openconf() and dlmgmt_writeconf()
830 851 * calls. If so, EAGAIN is returned. This mechanism can ensures atomicity
831 852 * across the pair of dladm_read_conf() and dladm_write_conf() calls.
832 853 */
833 854 /* ARGSUSED */
834 855 static void
835 856 dlmgmt_writeconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
836 857 ucred_t *cred)
837 858 {
838 859 dlmgmt_door_writeconf_t *writeconf = argp;
839 860 dlmgmt_writeconf_retval_t *retvalp = retp;
840 861 dlmgmt_dlconf_t dlconf, *dlconfp;
841 862 dlmgmt_link_t *linkp;
842 863 dlmgmt_linkattr_t *attrp, *next;
843 864 int err = 0;
844 865
845 866 /*
846 867 * Hold the lock to access the dlconf table.
847 868 */
848 869 dlmgmt_dlconf_table_lock(B_TRUE);
849 870
850 871 dlconf.ld_id = writeconf->ld_confid;
851 872 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
852 873 if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
853 874 err = ENOENT;
854 875 goto done;
855 876 }
856 877
857 878 if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
858 879 goto done;
859 880
860 881 /*
861 882 * Hold the writer lock to update the link table.
862 883 */
863 884 dlmgmt_table_lock(B_TRUE);
864 885 linkp = link_by_id(dlconfp->ld_linkid, zoneid);
865 886 if ((linkp == NULL) || (linkp->ll_class != dlconfp->ld_class) ||
866 887 (linkp->ll_media != dlconfp->ld_media) ||
867 888 (strcmp(linkp->ll_link, dlconfp->ld_link) != 0)) {
868 889 /*
869 890 * The link does not exist.
870 891 */
871 892 dlmgmt_table_unlock();
872 893 err = ENOENT;
873 894 goto done;
874 895 }
875 896
876 897 if (linkp->ll_gen != dlconfp->ld_gen) {
877 898 /*
878 899 * Something has changed the link configuration; try again.
879 900 */
880 901 dlmgmt_table_unlock();
881 902 err = EAGAIN;
882 903 goto done;
883 904 }
884 905
885 906 /*
886 907 * Delete the old attribute list.
887 908 */
888 909 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
889 910 next = attrp->lp_next;
890 911 free(attrp->lp_val);
891 912 free(attrp);
892 913 }
893 914 linkp->ll_head = NULL;
894 915
895 916 /*
896 917 * Set the new attribute.
897 918 */
898 919 for (attrp = dlconfp->ld_head; attrp != NULL; attrp = attrp->lp_next) {
899 920 if ((err = linkattr_set(&(linkp->ll_head), attrp->lp_name,
900 921 attrp->lp_val, attrp->lp_sz, attrp->lp_type)) != 0) {
901 922 dlmgmt_table_unlock();
902 923 goto done;
903 924 }
904 925 }
905 926
906 927 linkp->ll_gen++;
907 928 err = dlmgmt_write_db_entry(linkp->ll_link, linkp, DLMGMT_PERSIST);
908 929 dlmgmt_table_unlock();
909 930 done:
910 931 dlmgmt_dlconf_table_unlock();
911 932 retvalp->lr_err = err;
912 933 }
913 934
914 935 /* ARGSUSED */
915 936 static void
916 937 dlmgmt_removeconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
917 938 ucred_t *cred)
918 939 {
919 940 dlmgmt_door_removeconf_t *removeconf = argp;
920 941 dlmgmt_removeconf_retval_t *retvalp = retp;
921 942 dlmgmt_link_t *linkp;
922 943 int err;
923 944
924 945 dlmgmt_table_lock(B_TRUE);
925 946 if ((linkp = link_by_id(removeconf->ld_linkid, zoneid)) == NULL) {
926 947 err = ENOENT;
927 948 goto done;
928 949 }
929 950 if (zoneid != GLOBAL_ZONEID && linkp->ll_onloan) {
930 951 /*
931 952 * A non-global zone cannot remove the persistent
932 953 * configuration of a link that is on loan from the global
933 954 * zone.
934 955 */
935 956 err = EACCES;
936 957 goto done;
937 958 }
938 959 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
939 960 goto done;
940 961
941 962 err = dlmgmt_delete_db_entry(linkp, DLMGMT_PERSIST);
942 963 done:
943 964 dlmgmt_table_unlock();
944 965 retvalp->lr_err = err;
945 966 }
946 967
947 968 /* ARGSUSED */
948 969 static void
949 970 dlmgmt_destroyconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
950 971 ucred_t *cred)
951 972 {
952 973 dlmgmt_door_destroyconf_t *destroyconf = argp;
953 974 dlmgmt_destroyconf_retval_t *retvalp = retp;
954 975 dlmgmt_dlconf_t dlconf, *dlconfp;
955 976 int err = 0;
956 977
957 978 /*
958 979 * Hold the writer lock to update the dlconf table.
959 980 */
960 981 dlmgmt_dlconf_table_lock(B_TRUE);
961 982
962 983 dlconf.ld_id = destroyconf->ld_confid;
963 984 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
964 985 if (dlconfp == NULL || zoneid != dlconfp->ld_zoneid) {
965 986 err = ENOENT;
966 987 goto done;
967 988 }
968 989
969 990 if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0)
970 991 goto done;
971 992
972 993 avl_remove(&dlmgmt_dlconf_avl, dlconfp);
973 994 dlconf_destroy(dlconfp);
974 995
975 996 done:
976 997 dlmgmt_dlconf_table_unlock();
977 998 retvalp->lr_err = err;
978 999 }
979 1000
980 1001 /*
981 1002 * dlmgmt_openconf() returns a handle of the current configuration, which
982 1003 * is then used to update the configuration by dlmgmt_writeconf(). Therefore,
983 1004 * it requires privileges.
984 1005 *
985 1006 * Further, please see the comments above dladm_write_conf() to see how
986 1007 * ld_gen is used to ensure atomicity across the {dlmgmt_openconf(),
987 1008 * dlmgmt_writeconf()} pair.
988 1009 */
989 1010 /* ARGSUSED */
990 1011 static void
991 1012 dlmgmt_openconf(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
992 1013 ucred_t *cred)
993 1014 {
994 1015 dlmgmt_door_openconf_t *openconf = argp;
995 1016 dlmgmt_openconf_retval_t *retvalp = retp;
996 1017 dlmgmt_link_t *linkp;
997 1018 datalink_id_t linkid = openconf->ld_linkid;
998 1019 dlmgmt_dlconf_t *dlconfp;
999 1020 dlmgmt_linkattr_t *attrp;
1000 1021 int err = 0;
1001 1022
1002 1023 /*
1003 1024 * Hold the writer lock to update the dlconf table.
1004 1025 */
1005 1026 dlmgmt_dlconf_table_lock(B_TRUE);
1006 1027
1007 1028 /*
1008 1029 * Hold the reader lock to access the link
1009 1030 */
1010 1031 dlmgmt_table_lock(B_FALSE);
1011 1032 linkp = link_by_id(linkid, zoneid);
1012 1033 if ((linkp == NULL) || !(linkp->ll_flags & DLMGMT_PERSIST)) {
1013 1034 /* The persistent link configuration does not exist. */
1014 1035 err = ENOENT;
1015 1036 goto done;
1016 1037 }
1017 1038 if (linkp->ll_onloan && zoneid != GLOBAL_ZONEID) {
1018 1039 /*
1019 1040 * The caller is in a non-global zone and the persistent
1020 1041 * configuration belongs to the global zone.
1021 1042 */
1022 1043 err = EACCES;
1023 1044 goto done;
1024 1045 }
1025 1046
1026 1047 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
1027 1048 goto done;
1028 1049
1029 1050 if ((err = dlconf_create(linkp->ll_link, linkp->ll_linkid,
1030 1051 linkp->ll_class, linkp->ll_media, zoneid, &dlconfp)) != 0)
1031 1052 goto done;
1032 1053
1033 1054 for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next) {
1034 1055 if ((err = linkattr_set(&(dlconfp->ld_head), attrp->lp_name,
1035 1056 attrp->lp_val, attrp->lp_sz, attrp->lp_type)) != 0) {
1036 1057 dlconf_destroy(dlconfp);
1037 1058 goto done;
1038 1059 }
1039 1060 }
1040 1061 dlconfp->ld_gen = linkp->ll_gen;
1041 1062 avl_add(&dlmgmt_dlconf_avl, dlconfp);
1042 1063 dlmgmt_advance_dlconfid(dlconfp);
1043 1064
1044 1065 retvalp->lr_confid = dlconfp->ld_id;
1045 1066 done:
1046 1067 dlmgmt_table_unlock();
1047 1068 dlmgmt_dlconf_table_unlock();
1048 1069 retvalp->lr_err = err;
1049 1070 }
1050 1071
1051 1072 /*
1052 1073 * dlmgmt_getconfsnapshot() returns a read-only snapshot of all the
1053 1074 * configuration, and requires no privileges.
1054 1075 *
1055 1076 * If the given size cannot hold all the configuration, set the size
1056 1077 * that is needed, and return ENOSPC.
1057 1078 */
1058 1079 /* ARGSUSED */
1059 1080 static void
1060 1081 dlmgmt_getconfsnapshot(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1061 1082 ucred_t *cred)
1062 1083 {
1063 1084 dlmgmt_door_getconfsnapshot_t *snapshot = argp;
1064 1085 dlmgmt_getconfsnapshot_retval_t *retvalp = retp;
1065 1086 dlmgmt_link_t *linkp;
1066 1087 datalink_id_t linkid = snapshot->ld_linkid;
1067 1088 dlmgmt_linkattr_t *attrp;
1068 1089 char *buf;
1069 1090 size_t nvlsz;
1070 1091 nvlist_t *nvl = NULL;
1071 1092 int err = 0;
1072 1093
1073 1094 assert(*sz >= sizeof (dlmgmt_getconfsnapshot_retval_t));
1074 1095
1075 1096 /*
1076 1097 * Hold the reader lock to access the link
1077 1098 */
1078 1099 dlmgmt_table_lock(B_FALSE);
1079 1100 linkp = link_by_id(linkid, zoneid);
1080 1101 if ((linkp == NULL) || !(linkp->ll_flags & DLMGMT_PERSIST)) {
1081 1102 /* The persistent link configuration does not exist. */
1082 1103 err = ENOENT;
1083 1104 goto done;
1084 1105 }
1085 1106 if (linkp->ll_onloan && zoneid != GLOBAL_ZONEID) {
1086 1107 /*
1087 1108 * The caller is in a non-global zone and the persistent
1088 1109 * configuration belongs to the global zone.
1089 1110 */
1090 1111 err = EACCES;
1091 1112 goto done;
1092 1113 }
1093 1114
1094 1115 err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0);
1095 1116 if (err != 0)
1096 1117 goto done;
1097 1118
1098 1119 for (attrp = linkp->ll_head; attrp != NULL; attrp = attrp->lp_next) {
1099 1120 if ((err = nvlist_add_byte_array(nvl, attrp->lp_name,
1100 1121 attrp->lp_val, attrp->lp_sz)) != 0) {
1101 1122 goto done;
1102 1123 }
1103 1124 }
1104 1125
1105 1126 if ((err = nvlist_size(nvl, &nvlsz, NV_ENCODE_NATIVE)) != 0)
1106 1127 goto done;
1107 1128
1108 1129 if (nvlsz + sizeof (dlmgmt_getconfsnapshot_retval_t) > *sz) {
1109 1130 *sz = nvlsz + sizeof (dlmgmt_getconfsnapshot_retval_t);
1110 1131 err = ENOSPC;
1111 1132 goto done;
1112 1133 }
1113 1134
1114 1135 /*
1115 1136 * pack the the nvlist into the return value.
1116 1137 */
1117 1138 *sz = nvlsz + sizeof (dlmgmt_getconfsnapshot_retval_t);
1118 1139 retvalp->lr_nvlsz = nvlsz;
1119 1140 buf = (char *)retvalp + sizeof (dlmgmt_getconfsnapshot_retval_t);
1120 1141 err = nvlist_pack(nvl, &buf, &nvlsz, NV_ENCODE_NATIVE, 0);
1121 1142
1122 1143 done:
1123 1144 dlmgmt_table_unlock();
1124 1145 nvlist_free(nvl);
1125 1146 retvalp->lr_err = err;
1126 1147 }
1127 1148
1128 1149 /* ARGSUSED */
1129 1150 static void
1130 1151 dlmgmt_getattr(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1131 1152 ucred_t *cred)
1132 1153 {
1133 1154 dlmgmt_door_getattr_t *getattr = argp;
1134 1155 dlmgmt_getattr_retval_t *retvalp = retp;
1135 1156 dlmgmt_dlconf_t dlconf, *dlconfp;
1136 1157 int err;
1137 1158
1138 1159 /*
1139 1160 * Hold the read lock to access the dlconf table.
1140 1161 */
1141 1162 dlmgmt_dlconf_table_lock(B_FALSE);
1142 1163
1143 1164 dlconf.ld_id = getattr->ld_confid;
1144 1165 if ((dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL)) == NULL ||
1145 1166 zoneid != dlconfp->ld_zoneid) {
1146 1167 retvalp->lr_err = ENOENT;
1147 1168 } else {
1148 1169 if ((err = dlmgmt_checkprivs(dlconfp->ld_class, cred)) != 0) {
1149 1170 retvalp->lr_err = err;
1150 1171 } else {
1151 1172 retvalp->lr_err = dlmgmt_getattr_common(
1152 1173 &dlconfp->ld_head, getattr->ld_attr, retvalp);
1153 1174 }
1154 1175 }
1155 1176
1156 1177 dlmgmt_dlconf_table_unlock();
1157 1178 }
1158 1179
1159 1180 /* ARGSUSED */
1160 1181 static void
1161 1182 dlmgmt_upcall_linkprop_init(void *argp, void *retp, size_t *sz,
1162 1183 zoneid_t zoneid, ucred_t *cred)
1163 1184 {
1164 1185 dlmgmt_door_linkprop_init_t *lip = argp;
1165 1186 dlmgmt_linkprop_init_retval_t *retvalp = retp;
1166 1187 dlmgmt_link_t *linkp;
1167 1188 int err;
1168 1189
1169 1190 dlmgmt_table_lock(B_FALSE);
1170 1191 if ((linkp = link_by_id(lip->ld_linkid, zoneid)) == NULL)
1171 1192 err = ENOENT;
1172 1193 else
1173 1194 err = dlmgmt_checkprivs(linkp->ll_class, cred);
1174 1195 dlmgmt_table_unlock();
1175 1196
1176 1197 if (err == 0) {
1177 1198 dladm_status_t s;
1178 1199 char buf[DLADM_STRSIZE];
1179 1200
1180 1201 s = dladm_init_linkprop(dld_handle, lip->ld_linkid, B_TRUE);
1181 1202 if (s != DLADM_STATUS_OK) {
1182 1203 dlmgmt_log(LOG_WARNING,
1183 1204 "linkprop initialization failed on link %d: %s",
1184 1205 lip->ld_linkid, dladm_status2str(s, buf));
1185 1206 err = EINVAL;
1186 1207 }
1187 1208 }
1188 1209 retvalp->lr_err = err;
1189 1210 }
1190 1211
1191 1212 /* ARGSUSED */
1192 1213 static void
1193 1214 dlmgmt_setzoneid(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1194 1215 ucred_t *cred)
1195 1216 {
1196 1217 dlmgmt_door_setzoneid_t *setzoneid = argp;
1197 1218 dlmgmt_setzoneid_retval_t *retvalp = retp;
1198 1219 dlmgmt_link_t *linkp;
1199 1220 datalink_id_t linkid = setzoneid->ld_linkid;
1200 1221 zoneid_t oldzoneid, newzoneid;
1201 1222 int err = 0;
1202 1223
1203 1224 dlmgmt_table_lock(B_TRUE);
1204 1225
1205 1226 /* We currently only allow changing zoneid's from the global zone. */
1206 1227 if (zoneid != GLOBAL_ZONEID) {
1207 1228 err = EACCES;
1208 1229 goto done;
|
↓ open down ↓ |
487 lines elided |
↑ open up ↑ |
1209 1230 }
1210 1231
1211 1232 if ((linkp = link_by_id(linkid, zoneid)) == NULL) {
1212 1233 err = ENOENT;
1213 1234 goto done;
1214 1235 }
1215 1236
1216 1237 if ((err = dlmgmt_checkprivs(linkp->ll_class, cred)) != 0)
1217 1238 goto done;
1218 1239
1240 + if (linkp->ll_tomb == B_TRUE) {
1241 + err = EBUSY;
1242 + goto done;
1243 + }
1244 +
1219 1245 /* We can only assign an active link to a zone. */
1220 1246 if (!(linkp->ll_flags & DLMGMT_ACTIVE)) {
1221 1247 err = EINVAL;
1222 1248 goto done;
1223 1249 }
1224 1250
1225 1251 oldzoneid = linkp->ll_zoneid;
1226 1252 newzoneid = setzoneid->ld_zoneid;
1227 1253
1228 1254 if (oldzoneid == newzoneid)
1229 1255 goto done;
1230 1256
1231 1257 /*
1232 1258 * Before we remove the link from its current zone, make sure that
1233 1259 * there isn't a link with the same name in the destination zone.
1234 1260 */
1235 1261 if (zoneid != GLOBAL_ZONEID &&
1236 1262 link_by_name(linkp->ll_link, newzoneid) != NULL) {
1237 1263 err = EEXIST;
1238 1264 goto done;
1239 1265 }
1240 1266
1241 1267 if (oldzoneid != GLOBAL_ZONEID) {
1242 1268 if (zone_remove_datalink(oldzoneid, linkid) != 0) {
1243 1269 err = errno;
1244 1270 dlmgmt_log(LOG_WARNING, "unable to remove link %d from "
1245 1271 "zone %d: %s", linkid, oldzoneid, strerror(err));
1246 1272 goto done;
1247 1273 }
1248 1274 avl_remove(&dlmgmt_loan_avl, linkp);
1249 1275 linkp->ll_onloan = B_FALSE;
1250 1276 }
1251 1277 if (newzoneid != GLOBAL_ZONEID) {
1252 1278 if (zone_add_datalink(newzoneid, linkid) != 0) {
1253 1279 err = errno;
1254 1280 dlmgmt_log(LOG_WARNING, "unable to add link %d to zone "
1255 1281 "%d: %s", linkid, newzoneid, strerror(err));
1256 1282 (void) zone_add_datalink(oldzoneid, linkid);
1257 1283 goto done;
1258 1284 }
1259 1285 avl_add(&dlmgmt_loan_avl, linkp);
1260 1286 linkp->ll_onloan = B_TRUE;
1261 1287 }
1262 1288
1263 1289 avl_remove(&dlmgmt_name_avl, linkp);
1264 1290 linkp->ll_zoneid = newzoneid;
1265 1291 avl_add(&dlmgmt_name_avl, linkp);
1266 1292
1267 1293 done:
1268 1294 dlmgmt_table_unlock();
1269 1295 retvalp->lr_err = err;
1270 1296 }
1271 1297
1272 1298 /* ARGSUSED */
1273 1299 static void
1274 1300 dlmgmt_zoneboot(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1275 1301 ucred_t *cred)
1276 1302 {
1277 1303 int err;
1278 1304 dlmgmt_door_zoneboot_t *zoneboot = argp;
1279 1305 dlmgmt_zoneboot_retval_t *retvalp = retp;
1280 1306
1281 1307 dlmgmt_table_lock(B_TRUE);
1282 1308
1283 1309 if ((err = dlmgmt_checkprivs(0, cred)) != 0)
1284 1310 goto done;
1285 1311
1286 1312 if (zoneid != GLOBAL_ZONEID) {
1287 1313 err = EACCES;
1288 1314 goto done;
1289 1315 }
1290 1316 if (zoneboot->ld_zoneid == GLOBAL_ZONEID) {
1291 1317 err = EINVAL;
1292 1318 goto done;
1293 1319 }
1294 1320
1295 1321 if ((err = dlmgmt_elevate_privileges()) == 0) {
1296 1322 err = dlmgmt_zone_init(zoneboot->ld_zoneid);
1297 1323 (void) dlmgmt_drop_privileges();
1298 1324 }
1299 1325 done:
1300 1326 dlmgmt_table_unlock();
1301 1327 retvalp->lr_err = err;
|
↓ open down ↓ |
73 lines elided |
↑ open up ↑ |
1302 1328 }
1303 1329
1304 1330 /* ARGSUSED */
1305 1331 static void
1306 1332 dlmgmt_zonehalt(void *argp, void *retp, size_t *sz, zoneid_t zoneid,
1307 1333 ucred_t *cred)
1308 1334 {
1309 1335 int err = 0;
1310 1336 dlmgmt_door_zonehalt_t *zonehalt = argp;
1311 1337 dlmgmt_zonehalt_retval_t *retvalp = retp;
1338 + static char my_pid[10];
1312 1339
1340 + if (my_pid[0] == NULL)
1341 + (void) snprintf(my_pid, sizeof (my_pid), "%d\n", getpid());
1342 +
1313 1343 if ((err = dlmgmt_checkprivs(0, cred)) == 0) {
1314 1344 if (zoneid != GLOBAL_ZONEID) {
1315 1345 err = EACCES;
1316 1346 } else if (zonehalt->ld_zoneid == GLOBAL_ZONEID) {
1317 1347 err = EINVAL;
1318 1348 } else {
1349 + /*
1350 + * dls and mac don't honor the locking rules defined in
1351 + * mac. In order to try and make that case less likely
1352 + * to happen, we try to serialize some of the zone
1353 + * activity here between dlmgmtd and the brands on
1354 + * /etc/dladm/zone.lck
1355 + */
1356 + int fd;
1357 +
1358 + while ((fd = open(ZONE_LOCK, O_WRONLY |
1359 + O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
1360 + (void) sleep(1);
1361 + (void) write(fd, my_pid, sizeof (my_pid));
1362 + (void) close(fd);
1363 +
1319 1364 dlmgmt_table_lock(B_TRUE);
1320 1365 dlmgmt_db_fini(zonehalt->ld_zoneid);
1321 1366 dlmgmt_table_unlock();
1367 +
1368 + (void) unlink(ZONE_LOCK);
1322 1369 }
1323 1370 }
1324 1371 retvalp->lr_err = err;
1325 1372 }
1326 1373
1327 1374 static dlmgmt_door_info_t i_dlmgmt_door_info_tbl[] = {
1328 1375 { DLMGMT_CMD_DLS_CREATE, sizeof (dlmgmt_upcall_arg_create_t),
1329 1376 sizeof (dlmgmt_create_retval_t), dlmgmt_upcall_create },
1330 1377 { DLMGMT_CMD_DLS_GETATTR, sizeof (dlmgmt_upcall_arg_getattr_t),
1331 1378 sizeof (dlmgmt_getattr_retval_t), dlmgmt_upcall_getattr },
1332 1379 { DLMGMT_CMD_DLS_DESTROY, sizeof (dlmgmt_upcall_arg_destroy_t),
1333 1380 sizeof (dlmgmt_destroy_retval_t), dlmgmt_upcall_destroy },
1334 1381 { DLMGMT_CMD_GETNAME, sizeof (dlmgmt_door_getname_t),
1335 1382 sizeof (dlmgmt_getname_retval_t), dlmgmt_getname },
1336 1383 { DLMGMT_CMD_GETLINKID, sizeof (dlmgmt_door_getlinkid_t),
1337 1384 sizeof (dlmgmt_getlinkid_retval_t), dlmgmt_getlinkid },
1338 1385 { DLMGMT_CMD_GETNEXT, sizeof (dlmgmt_door_getnext_t),
1339 1386 sizeof (dlmgmt_getnext_retval_t), dlmgmt_getnext },
1340 1387 { DLMGMT_CMD_DLS_UPDATE, sizeof (dlmgmt_upcall_arg_update_t),
1341 1388 sizeof (dlmgmt_update_retval_t), dlmgmt_upcall_update },
1342 1389 { DLMGMT_CMD_CREATE_LINKID, sizeof (dlmgmt_door_createid_t),
1343 1390 sizeof (dlmgmt_createid_retval_t), dlmgmt_createid },
1344 1391 { DLMGMT_CMD_DESTROY_LINKID, sizeof (dlmgmt_door_destroyid_t),
1345 1392 sizeof (dlmgmt_destroyid_retval_t), dlmgmt_destroyid },
1346 1393 { DLMGMT_CMD_REMAP_LINKID, sizeof (dlmgmt_door_remapid_t),
1347 1394 sizeof (dlmgmt_remapid_retval_t), dlmgmt_remapid },
1348 1395 { DLMGMT_CMD_CREATECONF, sizeof (dlmgmt_door_createconf_t),
1349 1396 sizeof (dlmgmt_createconf_retval_t), dlmgmt_createconf },
1350 1397 { DLMGMT_CMD_OPENCONF, sizeof (dlmgmt_door_openconf_t),
1351 1398 sizeof (dlmgmt_openconf_retval_t), dlmgmt_openconf },
1352 1399 { DLMGMT_CMD_WRITECONF, sizeof (dlmgmt_door_writeconf_t),
1353 1400 sizeof (dlmgmt_writeconf_retval_t), dlmgmt_writeconf },
1354 1401 { DLMGMT_CMD_UP_LINKID, sizeof (dlmgmt_door_upid_t),
1355 1402 sizeof (dlmgmt_upid_retval_t), dlmgmt_upid },
1356 1403 { DLMGMT_CMD_SETATTR, sizeof (dlmgmt_door_setattr_t),
1357 1404 sizeof (dlmgmt_setattr_retval_t), dlmgmt_setattr },
1358 1405 { DLMGMT_CMD_UNSETATTR, sizeof (dlmgmt_door_unsetattr_t),
1359 1406 sizeof (dlmgmt_unsetattr_retval_t), dlmgmt_unsetconfattr },
1360 1407 { DLMGMT_CMD_REMOVECONF, sizeof (dlmgmt_door_removeconf_t),
1361 1408 sizeof (dlmgmt_removeconf_retval_t), dlmgmt_removeconf },
1362 1409 { DLMGMT_CMD_DESTROYCONF, sizeof (dlmgmt_door_destroyconf_t),
1363 1410 sizeof (dlmgmt_destroyconf_retval_t), dlmgmt_destroyconf },
1364 1411 { DLMGMT_CMD_GETATTR, sizeof (dlmgmt_door_getattr_t),
1365 1412 sizeof (dlmgmt_getattr_retval_t), dlmgmt_getattr },
1366 1413 { DLMGMT_CMD_GETCONFSNAPSHOT, sizeof (dlmgmt_door_getconfsnapshot_t),
1367 1414 sizeof (dlmgmt_getconfsnapshot_retval_t), dlmgmt_getconfsnapshot },
1368 1415 { DLMGMT_CMD_LINKPROP_INIT, sizeof (dlmgmt_door_linkprop_init_t),
1369 1416 sizeof (dlmgmt_linkprop_init_retval_t),
1370 1417 dlmgmt_upcall_linkprop_init },
1371 1418 { DLMGMT_CMD_SETZONEID, sizeof (dlmgmt_door_setzoneid_t),
1372 1419 sizeof (dlmgmt_setzoneid_retval_t), dlmgmt_setzoneid },
1373 1420 { DLMGMT_CMD_ZONEBOOT, sizeof (dlmgmt_door_zoneboot_t),
1374 1421 sizeof (dlmgmt_zoneboot_retval_t), dlmgmt_zoneboot },
1375 1422 { DLMGMT_CMD_ZONEHALT, sizeof (dlmgmt_door_zonehalt_t),
1376 1423 sizeof (dlmgmt_zonehalt_retval_t), dlmgmt_zonehalt },
1377 1424 { 0, 0, 0, NULL }
1378 1425 };
1379 1426
1380 1427 static dlmgmt_door_info_t *
1381 1428 dlmgmt_getcmdinfo(int cmd)
1382 1429 {
1383 1430 dlmgmt_door_info_t *infop = i_dlmgmt_door_info_tbl;
1384 1431
1385 1432 while (infop->di_handler != NULL) {
1386 1433 if (infop->di_cmd == cmd)
1387 1434 break;
1388 1435 infop++;
1389 1436 }
1390 1437 return (infop);
1391 1438 }
1392 1439
1393 1440 /* ARGSUSED */
1394 1441 void
1395 1442 dlmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
1396 1443 uint_t n_desc)
1397 1444 {
1398 1445 dlmgmt_door_arg_t *door_arg = (dlmgmt_door_arg_t *)(void *)argp;
1399 1446 dlmgmt_door_info_t *infop = NULL;
1400 1447 dlmgmt_retval_t retval;
1401 1448 ucred_t *cred = NULL;
1402 1449 zoneid_t zoneid;
1403 1450 void *retvalp = NULL;
1404 1451 size_t sz, acksz;
1405 1452 int err = 0;
1406 1453
1407 1454 infop = dlmgmt_getcmdinfo(door_arg->ld_cmd);
1408 1455 if (infop == NULL || argsz != infop->di_reqsz) {
1409 1456 err = EINVAL;
1410 1457 goto done;
1411 1458 }
1412 1459
1413 1460 if (door_ucred(&cred) != 0 || (zoneid = ucred_getzoneid(cred)) == -1) {
1414 1461 err = errno;
1415 1462 goto done;
1416 1463 }
1417 1464
1418 1465 /*
1419 1466 * Note that malloc() cannot be used here because door_return
1420 1467 * never returns, and memory allocated by malloc() would get leaked.
1421 1468 * Use alloca() instead.
1422 1469 */
1423 1470 acksz = infop->di_acksz;
1424 1471
1425 1472 again:
1426 1473 retvalp = alloca(acksz);
1427 1474 sz = acksz;
1428 1475 infop->di_handler(argp, retvalp, &acksz, zoneid, cred);
1429 1476 if (acksz > sz) {
1430 1477 /*
1431 1478 * If the specified buffer size is not big enough to hold the
1432 1479 * return value, reallocate the buffer and try to get the
1433 1480 * result one more time.
1434 1481 */
1435 1482 assert(((dlmgmt_retval_t *)retvalp)->lr_err == ENOSPC);
1436 1483 goto again;
1437 1484 }
1438 1485
1439 1486 done:
1440 1487 if (cred != NULL)
1441 1488 ucred_free(cred);
1442 1489 if (err == 0) {
1443 1490 (void) door_return(retvalp, acksz, NULL, 0);
1444 1491 } else {
1445 1492 retval.lr_err = err;
1446 1493 (void) door_return((char *)&retval, sizeof (retval), NULL, 0);
1447 1494 }
1448 1495 }
|
↓ open down ↓ |
117 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX