Print this page
701 UNMAP support for COMSTAR
Contributed by: Sumit Gupta <sumit.gupta@nexenta.com>
Reviewed by: Garrett D'Amore <garrett@nexenta.com>
Rich Lowe's comments

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c
          +++ new/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
       23 + *
       24 + * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  23   25   */
  24   26  
  25   27  #include <sys/conf.h>
  26   28  #include <sys/file.h>
  27   29  #include <sys/ddi.h>
  28   30  #include <sys/sunddi.h>
  29   31  #include <sys/modctl.h>
  30   32  #include <sys/scsi/scsi.h>
  31   33  #include <sys/scsi/impl/scsi_reset_notify.h>
  32   34  #include <sys/disp.h>
↓ open down ↓ 43 lines elided ↑ open up ↑
  76   78      int no_register, sbd_lu_t **slr);
  77   79  int sbd_import_active_lu(sbd_import_lu_t *ilu, sbd_lu_t *sl, uint32_t *err_ret);
  78   80  int sbd_delete_lu(sbd_delete_lu_t *dlu, int struct_sz, uint32_t *err_ret);
  79   81  int sbd_modify_lu(sbd_modify_lu_t *mlu, int struct_sz, uint32_t *err_ret);
  80   82  int sbd_set_global_props(sbd_global_props_t *mlu, int struct_sz,
  81   83      uint32_t *err_ret);
  82   84  int sbd_get_global_props(sbd_global_props_t *oslp, uint32_t oslp_sz,
  83   85      uint32_t *err_ret);
  84   86  int sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
  85   87      sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret);
  86      -char *sbd_get_zvol_name(sbd_lu_t *sl);
       88 +static int sbd_get_unmap_props(sbd_unmap_props_t *sup, sbd_unmap_props_t *osup,
       89 +    uint32_t *err_ret);
  87   90  sbd_status_t sbd_create_zfs_meta_object(sbd_lu_t *sl);
  88   91  sbd_status_t sbd_open_zfs_meta(sbd_lu_t *sl);
  89   92  sbd_status_t sbd_read_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
  90   93      uint64_t off);
  91   94  sbd_status_t sbd_write_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
  92   95      uint64_t off);
  93   96  sbd_status_t sbd_update_zfs_prop(sbd_lu_t *sl);
  94   97  int sbd_is_zvol(char *path);
  95   98  int sbd_zvolget(char *zvol_name, char **comstarprop);
  96   99  int sbd_zvolset(char *zvol_name, char *comstarprop);
  97  100  char sbd_ctoi(char c);
  98  101  void sbd_close_lu(sbd_lu_t *sl);
      102 +static nvlist_t *sbd_zvol_get_props(char *zvol_name);
      103 +static int sbd_zvol_set_props(char *zvol_name, nvlist_t *nv);
  99  104  
 100  105  static ldi_ident_t      sbd_zfs_ident;
 101  106  static stmf_lu_provider_t *sbd_lp;
 102  107  static sbd_lu_t         *sbd_lu_list = NULL;
 103  108  static kmutex_t         sbd_lock;
 104  109  static dev_info_t       *sbd_dip;
 105  110  static uint32_t         sbd_lu_count = 0;
 106  111  
 107  112  /* Global property settings for the logical unit */
 108  113  char sbd_vendor_id[]    = "SUN     ";
↓ open down ↓ 332 lines elided ↑ open up ↑
 441  446                      sbd_lu_count);
 442  447                  for (nsl = sbd_lu_list, i = 0; nsl &&
 443  448                      (i < iocd->stmf_obuf_nentries); i++, nsl = nsl->sl_next) {
 444  449                          bcopy(nsl->sl_device_id + 4,
 445  450                              &(((uint8_t *)obuf)[i << 4]), 16);
 446  451                  }
 447  452                  mutex_exit(&sbd_lock);
 448  453                  ret = 0;
 449  454                  iocd->stmf_error = 0;
 450  455                  break;
      456 +        case SBD_IOCTL_GET_UNMAP_PROPS:
      457 +                if (iocd->stmf_ibuf_size < sizeof (sbd_unmap_props_t)) {
      458 +                        ret = EFAULT;
      459 +                        break;
      460 +                }
      461 +                if (iocd->stmf_obuf_size < sizeof (sbd_unmap_props_t)) {
      462 +                        ret = EINVAL;
      463 +                        break;
      464 +                }
      465 +                ret = sbd_get_unmap_props((sbd_unmap_props_t *)ibuf,
      466 +                    (sbd_unmap_props_t *)obuf, &iocd->stmf_error);
      467 +                break;
 451  468          default:
 452  469                  ret = ENOTTY;
 453  470          }
 454  471  
 455  472          if (ret == 0) {
 456  473                  ret = stmf_copyout_iocdata(data, mode, iocd, obuf);
 457  474          } else if (iocd->stmf_error) {
 458  475                  (void) stmf_copyout_iocdata(data, mode, iocd, obuf);
 459  476          }
 460  477          if (obuf) {
↓ open down ↓ 904 lines elided ↑ open up ↑
1365 1382          sli->sli_sms_header.sms_size = sizeof (*sli) + s;
1366 1383          sli->sli_sms_header.sms_id = SMS_ID_LU_INFO_1_1;
1367 1384          sli->sli_sms_header.sms_data_order = SMS_DATA_ORDER;
1368 1385  
1369 1386          mutex_exit(&sl->sl_lock);
1370 1387          ret = sbd_write_meta_section(sl, (sm_section_hdr_t *)sli);
1371 1388          kmem_free(sli, sizeof (*sli) + s);
1372 1389          return (ret);
1373 1390  }
1374 1391  
     1392 +/*
     1393 + * Will scribble SL_UNMAP_ENABLED into sl_flags if we succeed.
     1394 + */
     1395 +static void
     1396 +do_unmap_setup(sbd_lu_t *sl)
     1397 +{
     1398 +        char *file = NULL;
     1399 +        nvlist_t *nv = NULL, *nv2 = NULL;
     1400 +        boolean_t already_compressing = B_FALSE;
     1401 +        uint64_t val;
     1402 +
     1403 +        ASSERT((sl->sl_flags & SL_UNMAP_ENABLED) == 0);
     1404 +
     1405 +        if ((sl->sl_flags & SL_ZFS_META) == 0)
     1406 +                return; /* No UNMAP for you. */
     1407 +
     1408 +        file = sbd_get_zvol_name(sl);
     1409 +        if (file == NULL) {
     1410 +                cmn_err(CE_WARN, "sbd has zfs meta but no zvol name");
     1411 +                return; /* No UNMAP for you. */
     1412 +        }
     1413 +        nv = sbd_zvol_get_props(file);
     1414 +        if (nv == NULL) {
     1415 +                cmn_err(CE_WARN, "unable to get zvol props");
     1416 +                kmem_free(file, strlen(file) + 1);
     1417 +                return; /* No UNMAP for you. */
     1418 +        }
     1419 +
     1420 +        /* See if compression is supported, but turned off on this dataset. */
     1421 +        if (nvlist_lookup_nvlist(nv, "compression", &nv2) == 0 &&
     1422 +            nvlist_lookup_uint64(nv2, ZPROP_VALUE, &val) == 0) {
     1423 +                already_compressing = (val != ZIO_COMPRESS_OFF);
     1424 +        } else {
     1425 +                cmn_err(CE_WARN, "prop lookup for compression failed");
     1426 +        }
     1427 +
     1428 +        /*
     1429 +         * Check refreservation because no refreservation means this is a
     1430 +         * sparse zvol and we can enable SCSI unmap.
     1431 +         */
     1432 +        if (nvlist_lookup_nvlist(nv, "refreservation", &nv2) != 0) {
     1433 +                cmn_err(CE_WARN, "lookup for refreservation nvlist failed");
     1434 +        } else if (nvlist_lookup_uint64(nv2, ZPROP_VALUE, &val) != 0) {
     1435 +                cmn_err(CE_WARN, "prop lookup for refreservation failed");
     1436 +        } else if (val == 0) {
     1437 +                sl->sl_flags |= SL_UNMAP_ENABLED;
     1438 +                if (!already_compressing) {
     1439 +                        nvlist_free(nv);
     1440 +                        nv = NULL;
     1441 +                        if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0 ||
     1442 +                            nvlist_add_uint64(nv, "compression",
     1443 +                            ZIO_COMPRESS_ZLE) != 0 ||
     1444 +                            sbd_zvol_set_props(file, nv)) {
     1445 +                                cmn_err(CE_WARN, "Setting zle compression "
     1446 +                                    "failed for zvol %s", file);
     1447 +                        }
     1448 +                }
     1449 +        }
     1450 +
     1451 +        nvlist_free(nv);
     1452 +        kmem_free(file, strlen(file) + 1);
     1453 +}
     1454 +
1375 1455  int
1376 1456  sbd_populate_and_register_lu(sbd_lu_t *sl, uint32_t *err_ret)
1377 1457  {
1378 1458          stmf_lu_t *lu = sl->sl_lu;
1379 1459          stmf_status_t ret;
1380 1460  
     1461 +        do_unmap_setup(sl);
     1462 +
1381 1463          lu->lu_id = (scsi_devid_desc_t *)sl->sl_device_id;
1382 1464          if (sl->sl_alias) {
1383 1465                  lu->lu_alias = sl->sl_alias;
1384 1466          } else {
1385 1467                  lu->lu_alias = sl->sl_name;
1386 1468          }
1387 1469          if (sl->sl_access_state == SBD_LU_STANDBY) {
1388 1470                  /* call set access state */
1389 1471                  ret = stmf_set_lu_access(lu, STMF_LU_STANDBY);
1390 1472                  if (ret != STMF_SUCCESS) {
↓ open down ↓ 1734 lines elided ↑ open up ↑
3125 3207                  oslp->mlu_mgmt_url_valid = 1;
3126 3208                  oslp->mlu_mgmt_url_off = off;
3127 3209                  (void) strcpy((char *)&oslp->mlu_buf[off], sbd_mgmt_url);
3128 3210                  off += strlen(sbd_mgmt_url) + 1;
3129 3211          }
3130 3212  
3131 3213          rw_exit(&sbd_global_prop_lock);
3132 3214          return (0);
3133 3215  }
3134 3216  
     3217 +static int
     3218 +sbd_get_unmap_props(sbd_unmap_props_t *sup,
     3219 +    sbd_unmap_props_t *osup, uint32_t *err_ret)
     3220 +{
     3221 +        sbd_status_t sret;
     3222 +        sbd_lu_t *sl = NULL;
     3223 +
     3224 +        if (sup->sup_guid_valid) {
     3225 +                sret = sbd_find_and_lock_lu(sup->sup_guid,
     3226 +                    NULL, SL_OP_LU_PROPS, &sl);
     3227 +        } else {
     3228 +                sret = sbd_find_and_lock_lu(NULL,
     3229 +                    (uint8_t *)sup->sup_zvol_path, SL_OP_LU_PROPS,
     3230 +                    &sl);
     3231 +        }
     3232 +        if (sret != SBD_SUCCESS) {
     3233 +                if (sret == SBD_BUSY) {
     3234 +                        *err_ret = SBD_RET_LU_BUSY;
     3235 +                        return (EBUSY);
     3236 +                } else if (sret == SBD_NOT_FOUND) {
     3237 +                        *err_ret = SBD_RET_NOT_FOUND;
     3238 +                        return (ENOENT);
     3239 +                }
     3240 +                return (EIO);
     3241 +        }
     3242 +
     3243 +        sup->sup_found_lu = 1;
     3244 +        sup->sup_guid_valid = 1;
     3245 +        bcopy(sl->sl_device_id + 4, sup->sup_guid, 16);
     3246 +        if (sl->sl_flags & SL_UNMAP_ENABLED)
     3247 +                sup->sup_unmap_enabled = 1;
     3248 +        else
     3249 +                sup->sup_unmap_enabled = 0;
     3250 +
     3251 +        *osup = *sup;
     3252 +        sl->sl_trans_op = SL_OP_NONE;
     3253 +
     3254 +        return (0);
     3255 +}
     3256 +
3135 3257  int
3136 3258  sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
3137 3259      sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret)
3138 3260  {
3139 3261          sbd_status_t sret;
3140 3262          sbd_lu_t *sl = NULL;
3141 3263          uint32_t sz;
3142 3264          uint16_t off;
3143 3265  
3144 3266          if (islp->slp_input_guid) {
↓ open down ↓ 470 lines elided ↑ open up ↑
3615 3737          if (rc != 0) {
3616 3738                  cmn_err(CE_NOTE, "ioctl failed %d", rc);
3617 3739          }
3618 3740          kmem_free(zc, sizeof (zfs_cmd_t));
3619 3741          if (packed)
3620 3742                  kmem_free(packed, len);
3621 3743  out:
3622 3744          nvlist_free(nv);
3623 3745          (void) ldi_close(zfs_lh, FREAD|FWRITE, kcred);
3624 3746          return (rc);
     3747 +}
     3748 +
     3749 +static nvlist_t *
     3750 +sbd_zvol_get_props(char *zvol_name)
     3751 +{
     3752 +        ldi_handle_t    zfs_lh;
     3753 +        nvlist_t        *nv = NULL;
     3754 +        zfs_cmd_t       *zc;
     3755 +        int size = 4096;
     3756 +        int unused;
     3757 +        int rc;
     3758 +
     3759 +        if ((rc = ldi_open_by_name("/dev/zfs", FREAD | FWRITE, kcred,
     3760 +            &zfs_lh, sbd_zfs_ident)) != 0) {
     3761 +                cmn_err(CE_WARN, "ldi_open %d", rc);
     3762 +                return (NULL);
     3763 +        }
     3764 +
     3765 +        zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
     3766 +        (void) strlcpy(zc->zc_name, zvol_name, sizeof (zc->zc_name));
     3767 +szg_again:
     3768 +        zc->zc_nvlist_dst = (uint64_t)(intptr_t)kmem_alloc(size,
     3769 +            KM_SLEEP);
     3770 +        zc->zc_nvlist_dst_size = size;
     3771 +        rc = ldi_ioctl(zfs_lh, ZFS_IOC_OBJSET_STATS, (intptr_t)zc,
     3772 +            FKIOCTL, kcred, &unused);
     3773 +        /*
     3774 +         * ENOMEM means the list is larger than what we've allocated
     3775 +         * ldi_ioctl will fail with ENOMEM only once
     3776 +         */
     3777 +        if (rc == ENOMEM) {
     3778 +                int newsize;
     3779 +                newsize = zc->zc_nvlist_dst_size;
     3780 +                kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, size);
     3781 +                size = newsize;
     3782 +                goto szg_again;
     3783 +        } else if (rc != 0) {
     3784 +                goto szg_out;
     3785 +        }
     3786 +        rc = nvlist_unpack((char *)(uintptr_t)zc->zc_nvlist_dst,
     3787 +            zc->zc_nvlist_dst_size, &nv, 0);
     3788 +        ASSERT(rc == 0);        /* nvlist_unpack should not fail */
     3789 +szg_out:
     3790 +        kmem_free((void *)(uintptr_t)zc->zc_nvlist_dst, size);
     3791 +        kmem_free(zc, sizeof (zfs_cmd_t));
     3792 +        (void) ldi_close(zfs_lh, FREAD|FWRITE, kcred);
     3793 +
     3794 +        return (nv);
     3795 +}
     3796 +
     3797 +static int
     3798 +sbd_zvol_set_props(char *zvol_name, nvlist_t *nv)
     3799 +{
     3800 +        ldi_handle_t    zfs_lh;
     3801 +        char            *packed = NULL;
     3802 +        size_t          len;
     3803 +        zfs_cmd_t       *zc;
     3804 +        int unused;
     3805 +        int rc;
     3806 +
     3807 +        if ((rc = ldi_open_by_name("/dev/zfs", FREAD | FWRITE, kcred,
     3808 +            &zfs_lh, sbd_zfs_ident)) != 0) {
     3809 +                cmn_err(CE_WARN, "ldi_open %d", rc);
     3810 +                return (ENXIO);
     3811 +        }
     3812 +        if ((rc = nvlist_pack(nv, &packed, &len, NV_ENCODE_NATIVE, KM_SLEEP))) {
     3813 +                goto szs_out;
     3814 +        }
     3815 +
     3816 +        zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
     3817 +        (void) strlcpy(zc->zc_name, zvol_name, sizeof (zc->zc_name));
     3818 +        zc->zc_nvlist_src = (uint64_t)(intptr_t)packed;
     3819 +        zc->zc_nvlist_src_size = len;
     3820 +        rc = ldi_ioctl(zfs_lh, ZFS_IOC_SET_PROP, (intptr_t)zc,
     3821 +            FKIOCTL, kcred, &unused);
     3822 +        if (rc != 0) {
     3823 +                cmn_err(CE_NOTE, "ioctl failed %d", rc);
     3824 +        }
     3825 +        kmem_free(zc, sizeof (zfs_cmd_t));
     3826 +        if (packed)
     3827 +                kmem_free(packed, len);
     3828 +szs_out:
     3829 +        (void) ldi_close(zfs_lh, FREAD|FWRITE, kcred);
     3830 +        return (rc);
3625 3831  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX