Print this page
OS-1885 deadlock between vnic destroy and kstat read
OS-676 debug kernel blew assertion in dls_devnet_stat_create()
OS-428 add link zonename kstat
OS-406
OS-327
OS-276 global zone duplicate kstat when two zones have same vnic name
OS-249

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/dls/dls_mgmt.c
          +++ new/usr/src/uts/common/io/dls/dls_mgmt.c
↓ 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   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + * Copyright (c) 2013 Joyent, Inc.  All rights reserved.
  24   25   */
  25   26  
  26   27  /*
  27   28   * Datalink management routines.
  28   29   */
  29   30  
  30   31  #include <sys/types.h>
  31   32  #include <sys/door.h>
  32   33  #include <sys/zone.h>
  33   34  #include <sys/modctl.h>
↓ open down ↓ 64 lines elided ↑ open up ↑
  98   99          kstat_t         *dd_zone_ksp;   /* in dd_zid if != owner_zid */
  99  100          uint32_t        dd_ref;
 100  101          kmutex_t        dd_mutex;
 101  102          kcondvar_t      dd_cv;
 102  103          uint32_t        dd_tref;
 103  104          uint_t          dd_flags;
 104  105          zoneid_t        dd_owner_zid;   /* zone where node was created */
 105  106          zoneid_t        dd_zid;         /* current zone */
 106  107          boolean_t       dd_prop_loaded;
 107  108          taskqid_t       dd_prop_taskid;
      109 +        boolean_t       dd_transient;   /* link goes away when zone does */
 108  110  } dls_devnet_t;
 109  111  
 110  112  static int i_dls_devnet_create_iptun(const char *, const char *,
 111  113      datalink_id_t *);
 112  114  static int i_dls_devnet_destroy_iptun(datalink_id_t);
 113      -static int i_dls_devnet_setzid(dls_devnet_t *, zoneid_t, boolean_t);
      115 +static int i_dls_devnet_setzid(dls_devnet_t *, zoneid_t, boolean_t, boolean_t);
 114  116  static int dls_devnet_unset(const char *, datalink_id_t *, boolean_t);
 115  117  
 116  118  /*ARGSUSED*/
 117  119  static int
 118  120  i_dls_devnet_constructor(void *buf, void *arg, int kmflag)
 119  121  {
 120  122          dls_devnet_t    *ddp = buf;
 121  123  
 122  124          bzero(buf, sizeof (dls_devnet_t));
 123  125          mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL);
↓ open down ↓ 14 lines elided ↑ open up ↑
 138  140          cv_destroy(&ddp->dd_cv);
 139  141  }
 140  142  
 141  143  /* ARGSUSED */
 142  144  static int
 143  145  dls_zone_remove(datalink_id_t linkid, void *arg)
 144  146  {
 145  147          dls_devnet_t *ddp;
 146  148  
 147  149          if (dls_devnet_hold_tmp(linkid, &ddp) == 0) {
 148      -                (void) dls_devnet_setzid(ddp, GLOBAL_ZONEID);
      150 +                /*
      151 +                 * Don't bother moving transient links back to the global zone
      152 +                 * since we will simply delete them in dls_devnet_unset.
      153 +                 */
      154 +                if (!ddp->dd_transient)
      155 +                        (void) dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE);
 149  156                  dls_devnet_rele_tmp(ddp);
 150  157          }
 151  158          return (0);
 152  159  }
 153  160  
 154  161  /* ARGSUSED */
 155  162  static void *
 156  163  dls_stack_init(netstackid_t stackid, netstack_t *ns)
 157  164  {
 158  165          dls_stack_t *dlss;
↓ open down ↓ 360 lines elided ↑ open up ↑
 519  526   */
 520  527  int
 521  528  dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid)
 522  529  {
 523  530          dlmgmt_door_getlinkid_t         getlinkid;
 524  531          dlmgmt_getlinkid_retval_t       retval;
 525  532          int                             err;
 526  533  
 527  534          getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
 528  535          (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
      536 +        getlinkid.ld_zoneid = getzoneid();
 529  537  
 530  538          if ((err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval,
 531  539              sizeof (retval))) == 0) {
 532  540                  *linkid = retval.lr_linkid;
 533  541          }
 534  542          return (err);
 535  543  }
 536  544  
 537  545  datalink_id_t
 538  546  dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class,
↓ open down ↓ 194 lines elided ↑ open up ↑
 733  741          err = dls_stat_update(ksp, dlp, rw);
 734  742  
 735  743          dls_devnet_rele_tmp(ddp);
 736  744          return (err);
 737  745  }
 738  746  
 739  747  /*
 740  748   * Create the "link" kstats.
 741  749   */
 742  750  static void
 743      -dls_devnet_stat_create(dls_devnet_t *ddp, zoneid_t zoneid)
      751 +dls_devnet_stat_create(dls_devnet_t *ddp, zoneid_t zoneid, zoneid_t newzoneid)
 744  752  {
 745  753          kstat_t *ksp;
      754 +        char    *nm;
      755 +        char    kname[MAXLINKNAMELEN];
 746  756  
 747      -        if (dls_stat_create("link", 0, ddp->dd_linkname, zoneid,
 748      -            dls_devnet_stat_update, ddp, &ksp) == 0) {
      757 +        if (zoneid != newzoneid) {
      758 +                ASSERT(zoneid == GLOBAL_ZONEID);
      759 +                (void) snprintf(kname, sizeof (kname), "z%d_%s", newzoneid,
      760 +                    ddp->dd_linkname);
      761 +                nm = kname;
      762 +        } else {
      763 +                nm = ddp->dd_linkname;
      764 +        }
      765 +
      766 +        if (dls_stat_create("link", 0, nm, zoneid,
      767 +            dls_devnet_stat_update, ddp, &ksp, newzoneid) == 0) {
 749  768                  ASSERT(ksp != NULL);
 750  769                  if (zoneid == ddp->dd_owner_zid) {
 751  770                          ASSERT(ddp->dd_ksp == NULL);
 752  771                          ddp->dd_ksp = ksp;
 753  772                  } else {
 754  773                          ASSERT(ddp->dd_zone_ksp == NULL);
 755  774                          ddp->dd_zone_ksp = ksp;
 756  775                  }
 757  776          }
 758  777  }
 759  778  
 760  779  /*
 761  780   * Destroy the "link" kstats.
 762  781   */
 763  782  static void
 764  783  dls_devnet_stat_destroy(dls_devnet_t *ddp, zoneid_t zoneid)
 765  784  {
 766  785          if (zoneid == ddp->dd_owner_zid) {
 767  786                  if (ddp->dd_ksp != NULL) {
 768      -                        kstat_delete(ddp->dd_ksp);
      787 +                        dls_stat_delete(ddp->dd_ksp);
 769  788                          ddp->dd_ksp = NULL;
 770  789                  }
 771  790          } else {
 772  791                  if (ddp->dd_zone_ksp != NULL) {
 773      -                        kstat_delete(ddp->dd_zone_ksp);
      792 +                        dls_stat_delete(ddp->dd_zone_ksp);
 774  793                          ddp->dd_zone_ksp = NULL;
 775  794                  }
 776  795          }
 777  796  }
 778  797  
 779  798  /*
 780  799   * The link has been renamed. Destroy the old non-legacy kstats ("link kstats")
 781  800   * and create the new set using the new name.
 782  801   */
 783  802  static void
 784      -dls_devnet_stat_rename(dls_devnet_t *ddp)
      803 +dls_devnet_stat_rename(dls_devnet_t *ddp, boolean_t zoneinit)
 785  804  {
 786  805          if (ddp->dd_ksp != NULL) {
 787      -                kstat_delete(ddp->dd_ksp);
      806 +                dls_stat_delete(ddp->dd_ksp);
 788  807                  ddp->dd_ksp = NULL;
 789  808          }
 790      -        /* We can't rename a link while it's assigned to a non-global zone. */
      809 +        if (zoneinit && ddp->dd_zone_ksp != NULL) {
      810 +                dls_stat_delete(ddp->dd_zone_ksp);
      811 +                ddp->dd_zone_ksp = NULL;
      812 +        }
      813 +        /*
      814 +         * We can't rename a link while it's assigned to a non-global zone
      815 +         * unless we're first initializing the zone while readying it.
      816 +         */
 791  817          ASSERT(ddp->dd_zone_ksp == NULL);
 792      -        dls_devnet_stat_create(ddp, ddp->dd_owner_zid);
      818 +        dls_devnet_stat_create(ddp, ddp->dd_owner_zid,
      819 +            (zoneinit ? ddp->dd_zid : ddp->dd_owner_zid));
      820 +        if (zoneinit)
      821 +                dls_devnet_stat_create(ddp, ddp->dd_zid, ddp->dd_zid);
 793  822  }
 794  823  
 795  824  /*
 796  825   * Associate a linkid with a given link (identified by macname)
 797  826   */
 798  827  static int
 799  828  dls_devnet_set(const char *macname, datalink_id_t linkid, zoneid_t zoneid,
 800  829      dls_devnet_t **ddpp)
 801  830  {
 802  831          dls_devnet_t            *ddp = NULL;
↓ open down ↓ 68 lines elided ↑ open up ↑
 871  900          /*
 872  901           * It is safe to drop the i_dls_devnet_lock at this point. In the case
 873  902           * of physical devices, the softmac framework will fail the device
 874  903           * detach based on the smac_state or smac_hold_cnt. Other cases like
 875  904           * vnic and aggr use their own scheme to serialize creates and deletes
 876  905           * and ensure that *ddp is valid.
 877  906           */
 878  907          rw_exit(&i_dls_devnet_lock);
 879  908          if (err == 0) {
 880  909                  if (zoneid != GLOBAL_ZONEID &&
 881      -                    (err = i_dls_devnet_setzid(ddp, zoneid, B_FALSE)) != 0)
      910 +                    (err = i_dls_devnet_setzid(ddp, zoneid, B_FALSE,
      911 +                    B_FALSE)) != 0)
 882  912                          (void) dls_devnet_unset(macname, &linkid, B_TRUE);
 883  913                  /*
 884  914                   * The kstat subsystem holds its own locks (rather perimeter)
 885  915                   * before calling the ks_update (dls_devnet_stat_update) entry
 886  916                   * point which in turn grabs the i_dls_devnet_lock. So the
 887  917                   * lock hierarchy is kstat locks -> i_dls_devnet_lock.
 888  918                   */
 889  919                  if (stat_create)
 890      -                        dls_devnet_stat_create(ddp, zoneid);
      920 +                        dls_devnet_stat_create(ddp, zoneid, zoneid);
 891  921                  if (ddpp != NULL)
 892  922                          *ddpp = ddp;
 893  923          }
 894  924          return (err);
 895  925  }
 896  926  
 897  927  /*
 898  928   * Disassociate a linkid with a given link (identified by macname)
 899  929   * This waits until temporary references to the dls_devnet_t are gone.
 900  930   */
↓ open down ↓ 16 lines elided ↑ open up ↑
 917  947  
 918  948          /*
 919  949           * Make sure downcalls into softmac_create or softmac_destroy from
 920  950           * devfs don't cv_wait on any devfs related condition for fear of
 921  951           * deadlock. Return EBUSY if the asynchronous thread started for
 922  952           * property loading as part of the post attach hasn't yet completed.
 923  953           */
 924  954          ASSERT(ddp->dd_ref != 0);
 925  955          if ((ddp->dd_ref != 1) || (!wait &&
 926  956              (ddp->dd_tref != 0 || ddp->dd_prop_taskid != NULL))) {
 927      -                mutex_exit(&ddp->dd_mutex);
 928      -                rw_exit(&i_dls_devnet_lock);
 929      -                return (EBUSY);
      957 +                int zstatus = 0;
      958 +
      959 +                /*
      960 +                 * There are a couple of alternatives that might be going on
      961 +                 * here; a) the zone is shutting down and it has a transient
      962 +                 * link assigned, in which case we want to clean it up instead
      963 +                 * of moving it back to the global zone, or b) its possible
      964 +                 * that we're trying to clean up an orphaned vnic that was
      965 +                 * delegated to a zone and which wasn't cleaned up properly
      966 +                 * when the zone went away.  Check for either of these cases
      967 +                 * before we simply return EBUSY.
      968 +                 *
      969 +                 * zstatus indicates which situation we are dealing with:
      970 +                 *       0 - means return EBUSY
      971 +                 *       1 - means case (a), cleanup transient link
      972 +                 *      -1 - means case (b), orphained VNIC
      973 +                 */
      974 +                if (ddp->dd_ref > 1 && ddp->dd_zid != GLOBAL_ZONEID) {
      975 +                        zone_t  *zp;
      976 +
      977 +                        if ((zp = zone_find_by_id(ddp->dd_zid)) == NULL) {
      978 +                                zstatus = -1;
      979 +                        } else {
      980 +                                if (ddp->dd_transient) {
      981 +                                        zone_status_t s = zone_status_get(zp);
      982 +
      983 +                                        if (s >= ZONE_IS_SHUTTING_DOWN)
      984 +                                                zstatus = 1;
      985 +                                }
      986 +                                zone_rele(zp);
      987 +                        }
      988 +                }
      989 +
      990 +                if (zstatus == 0) {
      991 +                        mutex_exit(&ddp->dd_mutex);
      992 +                        rw_exit(&i_dls_devnet_lock);
      993 +                        return (EBUSY);
      994 +                }
      995 +
      996 +                /*
      997 +                 * We want to delete the link, reset ref to 1;
      998 +                 */
      999 +                if (zstatus == -1)
     1000 +                        /* Log a warning, but continue in this case */
     1001 +                        cmn_err(CE_WARN, "clear orphaned datalink: %s\n",
     1002 +                            ddp->dd_linkname);
     1003 +                ddp->dd_ref = 1;
 930 1004          }
 931 1005  
 932 1006          ddp->dd_flags |= DD_CONDEMNED;
 933 1007          ddp->dd_ref--;
 934 1008          *id = ddp->dd_linkid;
 935 1009  
 936      -        if (ddp->dd_zid != GLOBAL_ZONEID)
 937      -                (void) i_dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE);
     1010 +        if (ddp->dd_zid != GLOBAL_ZONEID) {
     1011 +                /*
     1012 +                 * We need to release the dd_mutex before we try and destroy the
     1013 +                 * stat. When we destroy it, we'll need to grab the lock for the
     1014 +                 * kstat but if there's a concurrent reader of the kstat, we'll
     1015 +                 * be blocked on it. This will lead to deadlock because these
     1016 +                 * kstats employ a ks_update function (dls_devnet_stat_update)
     1017 +                 * which needs the dd_mutex that we currently hold.
     1018 +                 *
     1019 +                 * Because we've already flagged the dls_devnet_t as
     1020 +                 * DD_CONDEMNED and we still have a write lock on
     1021 +                 * i_dls_devnet_lock, we should be able to release the dd_mutex.
     1022 +                 */
     1023 +                mutex_exit(&ddp->dd_mutex);
     1024 +                dls_devnet_stat_destroy(ddp, ddp->dd_zid);
     1025 +                mutex_enter(&ddp->dd_mutex);
     1026 +                (void) i_dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE,
     1027 +                    B_FALSE);
     1028 +        }
 938 1029  
 939 1030          /*
 940 1031           * Remove this dls_devnet_t from the hash table.
 941 1032           */
 942 1033          VERIFY(mod_hash_remove(i_dls_devnet_hash,
 943 1034              (mod_hash_key_t)ddp->dd_mac, &val) == 0);
 944 1035  
 945 1036          if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
 946 1037                  VERIFY(mod_hash_remove(i_dls_devnet_id_hash,
 947 1038                      (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, &val) == 0);
↓ open down ↓ 5 lines elided ↑ open up ↑
 953 1044          if (wait) {
 954 1045                  /*
 955 1046                   * Wait until all temporary references are released.
 956 1047                   */
 957 1048                  while ((ddp->dd_tref != 0) || (ddp->dd_prop_taskid != NULL))
 958 1049                          cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
 959 1050          } else {
 960 1051                  ASSERT(ddp->dd_tref == 0 && ddp->dd_prop_taskid == NULL);
 961 1052          }
 962 1053  
 963      -        if (ddp->dd_linkid != DATALINK_INVALID_LINKID)
     1054 +        if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
     1055 +                /*
     1056 +                 * See the earlier call in this function for an explanation.
     1057 +                 */
     1058 +                mutex_exit(&ddp->dd_mutex);
 964 1059                  dls_devnet_stat_destroy(ddp, ddp->dd_owner_zid);
     1060 +                mutex_enter(&ddp->dd_mutex);
     1061 +        }
 965 1062  
     1063 +
 966 1064          ddp->dd_prop_loaded = B_FALSE;
 967 1065          ddp->dd_linkid = DATALINK_INVALID_LINKID;
 968 1066          ddp->dd_flags = 0;
 969 1067          mutex_exit(&ddp->dd_mutex);
 970 1068          kmem_cache_free(i_dls_devnet_cachep, ddp);
 971 1069  
 972 1070          return (0);
 973 1071  }
 974 1072  
 975 1073  static int
↓ open down ↓ 278 lines elided ↑ open up ↑
1254 1352   *    id1 is held by any applications.
1255 1353   *
1256 1354   *    In this case, the link's kstats need to be updated using the given name.
1257 1355   *
1258 1356   * 2. Request to rename a valid link (id1) to the name of a REMOVED
1259 1357   *    physical link (id2). In this case, check that id1 and its associated
1260 1358   *    mac is not held by any application, and update the link's linkid to id2.
1261 1359   *
1262 1360   *    This case does not change the <link name, linkid> mapping, so the link's
1263 1361   *    kstats need to be updated with using name associated the given id2.
     1362 + *
     1363 + * The zonename parameter is used to allow us to create a VNIC in the global
     1364 + * zone which is assigned to a non-global zone.  Since there is a race condition
     1365 + * in the create process if two VNICs have the same name, we need to rename it
     1366 + * after it has been assigned to the zone.
1264 1367   */
1265 1368  int
1266      -dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link)
     1369 +dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link,
     1370 +    boolean_t zoneinit)
1267 1371  {
1268 1372          dls_dev_handle_t        ddh = NULL;
1269 1373          int                     err = 0;
1270 1374          dev_t                   phydev = 0;
1271 1375          dls_devnet_t            *ddp;
1272 1376          mac_perim_handle_t      mph = NULL;
1273 1377          mac_handle_t            mh;
1274 1378          mod_hash_val_t          val;
1275 1379          boolean_t               clear_dd_flag = B_FALSE;
1276 1380  
↓ open down ↓ 29 lines elided ↑ open up ↑
1306 1410                  ASSERT(err == MH_ERR_NOTFOUND);
1307 1411                  err = ENOENT;
1308 1412                  goto done;
1309 1413          }
1310 1414  
1311 1415          /*
1312 1416           * Return EBUSY if any applications have this link open, if any thread
1313 1417           * is currently accessing the link kstats, or if the link is on-loan
1314 1418           * to a non-global zone. Then set the DD_KSTAT_CHANGING flag to
1315 1419           * prevent any access to the kstats while we delete and recreate
1316      -         * kstats below.
     1420 +         * kstats below.  However, we skip this check if we're renaming the
     1421 +         * vnic as part of bringing it up for a zone.
1317 1422           */
1318 1423          mutex_enter(&ddp->dd_mutex);
1319      -        if (ddp->dd_ref > 1) {
1320      -                mutex_exit(&ddp->dd_mutex);
1321      -                err = EBUSY;
1322      -                goto done;
     1424 +        if (!zoneinit) {
     1425 +                if (ddp->dd_ref > 1) {
     1426 +                        mutex_exit(&ddp->dd_mutex);
     1427 +                        err = EBUSY;
     1428 +                        goto done;
     1429 +                }
1323 1430          }
1324 1431  
1325 1432          ddp->dd_flags |= DD_KSTAT_CHANGING;
1326 1433          clear_dd_flag = B_TRUE;
1327 1434          mutex_exit(&ddp->dd_mutex);
1328 1435  
1329 1436          if (id2 == DATALINK_INVALID_LINKID) {
1330 1437                  (void) strlcpy(ddp->dd_linkname, link,
1331 1438                      sizeof (ddp->dd_linkname));
1332 1439  
1333 1440                  /* rename mac client name and its flow if exists */
1334 1441                  if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1335 1442                          goto done;
1336      -                (void) mac_rename_primary(mh, link);
     1443 +                if (zoneinit) {
     1444 +                        char tname[MAXLINKNAMELEN];
     1445 +
     1446 +                        (void) snprintf(tname, sizeof (tname), "z%d_%s",
     1447 +                            ddp->dd_zid, link);
     1448 +                        (void) mac_rename_primary(mh, tname);
     1449 +                } else {
     1450 +                        (void) mac_rename_primary(mh, link);
     1451 +                }
1337 1452                  mac_close(mh);
1338 1453                  goto done;
1339 1454          }
1340 1455  
1341 1456          /*
1342 1457           * The second case, check whether the MAC is used by any MAC
1343 1458           * user.  This must be a physical link so ddh must not be NULL.
1344 1459           */
1345 1460          if (ddh == NULL) {
1346 1461                  err = EINVAL;
↓ open down ↓ 52 lines elided ↑ open up ↑
1399 1514  done:
1400 1515          /*
1401 1516           * Change the name of the kstat based on the new link name.
1402 1517           * We can't hold the i_dls_devnet_lock across calls to the kstat
1403 1518           * subsystem. Instead the DD_KSTAT_CHANGING flag set above in this
1404 1519           * function prevents any access to the dd_ksp while we delete and
1405 1520           * recreate it below.
1406 1521           */
1407 1522          rw_exit(&i_dls_devnet_lock);
1408 1523          if (err == 0)
1409      -                dls_devnet_stat_rename(ddp);
     1524 +                dls_devnet_stat_rename(ddp, zoneinit);
1410 1525  
1411 1526          if (clear_dd_flag) {
1412 1527                  mutex_enter(&ddp->dd_mutex);
1413 1528                  ddp->dd_flags &= ~DD_KSTAT_CHANGING;
1414 1529                  mutex_exit(&ddp->dd_mutex);
1415 1530          }
1416 1531  
1417 1532          if (mph != NULL)
1418 1533                  mac_perim_exit(mph);
1419 1534          softmac_rele_device(ddh);
1420 1535          return (err);
1421 1536  }
1422 1537  
1423 1538  static int
1424      -i_dls_devnet_setzid(dls_devnet_t *ddp, zoneid_t new_zoneid, boolean_t setprop)
     1539 +i_dls_devnet_setzid(dls_devnet_t *ddp, zoneid_t new_zoneid, boolean_t setprop,
     1540 +    boolean_t transient)
1425 1541  {
1426 1542          int                     err;
1427 1543          mac_perim_handle_t      mph;
1428 1544          boolean_t               upcall_done = B_FALSE;
1429 1545          datalink_id_t           linkid = ddp->dd_linkid;
1430 1546          zoneid_t                old_zoneid = ddp->dd_zid;
1431 1547          dlmgmt_door_setzoneid_t setzid;
1432 1548          dlmgmt_setzoneid_retval_t retval;
1433 1549  
1434 1550          if (old_zoneid == new_zoneid)
↓ open down ↓ 12 lines elided ↑ open up ↑
1447 1563                  setzid.ld_linkid = linkid;
1448 1564                  setzid.ld_zoneid = new_zoneid;
1449 1565                  err = i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1450 1566                      sizeof (retval));
1451 1567                  if (err != 0)
1452 1568                          goto done;
1453 1569                  upcall_done = B_TRUE;
1454 1570          }
1455 1571          if ((err = dls_link_setzid(ddp->dd_mac, new_zoneid)) == 0) {
1456 1572                  ddp->dd_zid = new_zoneid;
     1573 +                ddp->dd_transient = transient;
1457 1574                  devnet_need_rebuild = B_TRUE;
1458 1575          }
1459 1576  
1460 1577  done:
1461 1578          if (err != 0 && upcall_done) {
1462 1579                  setzid.ld_zoneid = old_zoneid;
1463 1580                  (void) i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1464 1581                      sizeof (retval));
1465 1582          }
1466 1583          mac_perim_exit(mph);
1467 1584          return (err);
1468 1585  }
1469 1586  
1470 1587  int
1471      -dls_devnet_setzid(dls_dl_handle_t ddh, zoneid_t new_zid)
     1588 +dls_devnet_setzid(dls_dl_handle_t ddh, zoneid_t new_zid, boolean_t transient)
1472 1589  {
1473 1590          dls_devnet_t    *ddp;
1474 1591          int             err;
1475 1592          zoneid_t        old_zid;
1476 1593          boolean_t       refheld = B_FALSE;
1477 1594  
1478 1595          old_zid = ddh->dd_zid;
1479 1596  
1480 1597          if (old_zid == new_zid)
1481 1598                  return (0);
↓ open down ↓ 1 lines elided ↑ open up ↑
1483 1600          /*
1484 1601           * Acquire an additional reference to the link if it is being assigned
1485 1602           * to a non-global zone from the global zone.
1486 1603           */
1487 1604          if (old_zid == GLOBAL_ZONEID && new_zid != GLOBAL_ZONEID) {
1488 1605                  if ((err = dls_devnet_hold(ddh->dd_linkid, &ddp)) != 0)
1489 1606                          return (err);
1490 1607                  refheld = B_TRUE;
1491 1608          }
1492 1609  
1493      -        if ((err = i_dls_devnet_setzid(ddh, new_zid, B_TRUE)) != 0) {
     1610 +        if ((err = i_dls_devnet_setzid(ddh, new_zid, B_TRUE, transient)) != 0) {
1494 1611                  if (refheld)
1495 1612                          dls_devnet_rele(ddp);
1496 1613                  return (err);
1497 1614          }
1498 1615  
1499 1616          /*
1500 1617           * Release the additional reference if the link is returning to the
1501 1618           * global zone from a non-global zone.
1502 1619           */
1503 1620          if (old_zid != GLOBAL_ZONEID && new_zid == GLOBAL_ZONEID)
1504 1621                  dls_devnet_rele(ddh);
1505 1622  
1506 1623          /* Re-create kstats in the appropriate zones. */
1507 1624          if (old_zid != GLOBAL_ZONEID)
1508 1625                  dls_devnet_stat_destroy(ddh, old_zid);
1509 1626          if (new_zid != GLOBAL_ZONEID)
1510      -                dls_devnet_stat_create(ddh, new_zid);
     1627 +                dls_devnet_stat_create(ddh, new_zid, new_zid);
1511 1628  
1512 1629          return (0);
1513 1630  }
1514 1631  
1515 1632  zoneid_t
1516 1633  dls_devnet_getzid(dls_dl_handle_t ddh)
1517 1634  {
1518 1635          return (((dls_devnet_t *)ddh)->dd_zid);
1519 1636  }
1520 1637  
↓ open down ↓ 257 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX