Print this page
701 UNMAP support for COMSTAR
Contributed by: Sumit Gupta <sumit.gupta@nexenta.com>
Reviewed by: Garrett D'Amore <garrett@nexenta.com>
Reviewed by: Eric Schrock <eric.schrock@delphix.com>
Reviewed by: George Wilson <gwilson@zfsmail.com>
*** 18,27 ****
--- 18,29 ----
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/ddi.h>
*** 81,91 ****
uint32_t *err_ret);
int sbd_get_global_props(sbd_global_props_t *oslp, uint32_t oslp_sz,
uint32_t *err_ret);
int sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret);
! char *sbd_get_zvol_name(sbd_lu_t *sl);
sbd_status_t sbd_create_zfs_meta_object(sbd_lu_t *sl);
sbd_status_t sbd_open_zfs_meta(sbd_lu_t *sl);
sbd_status_t sbd_read_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
uint64_t off);
sbd_status_t sbd_write_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
--- 83,95 ----
uint32_t *err_ret);
int sbd_get_global_props(sbd_global_props_t *oslp, uint32_t oslp_sz,
uint32_t *err_ret);
int sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret);
! static char *sbd_get_zvol_name(sbd_lu_t *);
! static int sbd_get_unmap_props(sbd_unmap_props_t *sup, sbd_unmap_props_t *osup,
! uint32_t *err_ret);
sbd_status_t sbd_create_zfs_meta_object(sbd_lu_t *sl);
sbd_status_t sbd_open_zfs_meta(sbd_lu_t *sl);
sbd_status_t sbd_read_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
uint64_t off);
sbd_status_t sbd_write_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
*** 446,455 ****
--- 450,471 ----
}
mutex_exit(&sbd_lock);
ret = 0;
iocd->stmf_error = 0;
break;
+ case SBD_IOCTL_GET_UNMAP_PROPS:
+ if (iocd->stmf_ibuf_size < sizeof (sbd_unmap_props_t)) {
+ ret = EFAULT;
+ break;
+ }
+ if (iocd->stmf_obuf_size < sizeof (sbd_unmap_props_t)) {
+ ret = EINVAL;
+ break;
+ }
+ ret = sbd_get_unmap_props((sbd_unmap_props_t *)ibuf,
+ (sbd_unmap_props_t *)obuf, &iocd->stmf_error);
+ break;
default:
ret = ENOTTY;
}
if (ret == 0) {
*** 1370,1385 ****
--- 1386,1417 ----
ret = sbd_write_meta_section(sl, (sm_section_hdr_t *)sli);
kmem_free(sli, sizeof (*sli) + s);
return (ret);
}
+ /*
+ * Will scribble SL_UNMAP_ENABLED into sl_flags if we succeed.
+ */
+ static void
+ do_unmap_setup(sbd_lu_t *sl)
+ {
+ ASSERT((sl->sl_flags & SL_UNMAP_ENABLED) == 0);
+
+ if ((sl->sl_flags & SL_ZFS_META) == 0)
+ return; /* No UNMAP for you. */
+
+ sl->sl_flags |= SL_UNMAP_ENABLED;
+ }
+
int
sbd_populate_and_register_lu(sbd_lu_t *sl, uint32_t *err_ret)
{
stmf_lu_t *lu = sl->sl_lu;
stmf_status_t ret;
+ do_unmap_setup(sl);
+
lu->lu_id = (scsi_devid_desc_t *)sl->sl_device_id;
if (sl->sl_alias) {
lu->lu_alias = sl->sl_alias;
} else {
lu->lu_alias = sl->sl_name;
*** 3130,3139 ****
--- 3162,3211 ----
rw_exit(&sbd_global_prop_lock);
return (0);
}
+ static int
+ sbd_get_unmap_props(sbd_unmap_props_t *sup,
+ sbd_unmap_props_t *osup, uint32_t *err_ret)
+ {
+ sbd_status_t sret;
+ sbd_lu_t *sl = NULL;
+
+ if (sup->sup_guid_valid) {
+ sret = sbd_find_and_lock_lu(sup->sup_guid,
+ NULL, SL_OP_LU_PROPS, &sl);
+ } else {
+ sret = sbd_find_and_lock_lu(NULL,
+ (uint8_t *)sup->sup_zvol_path, SL_OP_LU_PROPS,
+ &sl);
+ }
+ if (sret != SBD_SUCCESS) {
+ if (sret == SBD_BUSY) {
+ *err_ret = SBD_RET_LU_BUSY;
+ return (EBUSY);
+ } else if (sret == SBD_NOT_FOUND) {
+ *err_ret = SBD_RET_NOT_FOUND;
+ return (ENOENT);
+ }
+ return (EIO);
+ }
+
+ sup->sup_found_lu = 1;
+ sup->sup_guid_valid = 1;
+ bcopy(sl->sl_device_id + 4, sup->sup_guid, 16);
+ if (sl->sl_flags & SL_UNMAP_ENABLED)
+ sup->sup_unmap_enabled = 1;
+ else
+ sup->sup_unmap_enabled = 0;
+
+ *osup = *sup;
+ sl->sl_trans_op = SL_OP_NONE;
+
+ return (0);
+ }
+
int
sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret)
{
sbd_status_t sret;
*** 3270,3280 ****
rw_exit(&sbd_global_prop_lock);
return (0);
}
! char *
sbd_get_zvol_name(sbd_lu_t *sl)
{
char *src;
char *p;
--- 3342,3355 ----
rw_exit(&sbd_global_prop_lock);
return (0);
}
! /*
! * Returns an allocated string with the "<pool>/..." form of the zvol name.
! */
! static char *
sbd_get_zvol_name(sbd_lu_t *sl)
{
char *src;
char *p;
*** 3284,3296 ****
src = sl->sl_meta_filename;
/* There has to be a better way */
if (SBD_IS_ZVOL(src) != 0) {
ASSERT(0);
}
! src += 14;
if (*src == '/')
! src++;
p = (char *)kmem_alloc(strlen(src) + 1, KM_SLEEP);
(void) strcpy(p, src);
return (p);
}
--- 3359,3371 ----
src = sl->sl_meta_filename;
/* There has to be a better way */
if (SBD_IS_ZVOL(src) != 0) {
ASSERT(0);
}
! src += 14; /* Past /dev/zvol/dsk/ */
if (*src == '/')
! src++; /* or /dev/zvol/rdsk/ */
p = (char *)kmem_alloc(strlen(src) + 1, KM_SLEEP);
(void) strcpy(p, src);
return (p);
}
*** 3620,3625 ****
--- 3695,3730 ----
kmem_free(packed, len);
out:
nvlist_free(nv);
(void) ldi_close(zfs_lh, FREAD|FWRITE, kcred);
return (rc);
+ }
+
+ /*
+ * Unmap a region in a volume. Currently only supported for zvols.
+ */
+ int
+ sbd_unmap(sbd_lu_t *sl, uint64_t offset, uint64_t length)
+ {
+ vnode_t *vp;
+ int unused;
+ dkioc_free_t df;
+
+ /* Right now, we only support UNMAP on zvols. */
+ if (!(sl->sl_flags & SL_ZFS_META))
+ return (EIO);
+
+ df.df_flags = (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) ?
+ DF_WAIT_SYNC : 0;
+ df.df_start = offset;
+ df.df_length = length;
+
+ /* Use the data vnode we have to send a fop_ioctl(). */
+ vp = sl->sl_data_vp;
+ if (vp == NULL) {
+ cmn_err(CE_WARN, "Cannot unmap - no vnode pointer.");
+ return (EIO);
+ }
+
+ return (VOP_IOCTL(vp, DKIOCFREE, (intptr_t)(&df), FKIOCTL, kcred,
+ &unused, NULL));
}