summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/cam/ctl/ctl.c102
-rw-r--r--sys/cam/ctl/ctl.h1
-rw-r--r--sys/cam/ctl/ctl_backend_block.c192
-rw-r--r--sys/cam/ctl/ctl_backend_ramdisk.c31
-rw-r--r--sys/cam/ctl/ctl_cmd_table.c15
-rw-r--r--sys/cam/ctl/ctl_private.h1
-rw-r--r--sys/cam/scsi/scsi_all.h26
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c13
8 files changed, 366 insertions, 15 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 4cbc14f..126c95b85 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -5174,6 +5174,40 @@ ctl_config_write_done(union ctl_io *io)
free(buf, M_CTL);
}
+void
+ctl_config_read_done(union ctl_io *io)
+{
+ uint8_t *buf;
+
+ /*
+ * If there is some error -- we are done, skip data transfer.
+ */
+ if ((io->io_hdr.flags & CTL_FLAG_ABORT) != 0 ||
+ ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE &&
+ (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) {
+ if (io->io_hdr.flags & CTL_FLAG_ALLOCATED)
+ buf = io->scsiio.kern_data_ptr;
+ else
+ buf = NULL;
+ ctl_done(io);
+ if (buf)
+ free(buf, M_CTL);
+ return;
+ }
+
+ /*
+ * If the IO_CONT flag is set, we need to call the supplied
+ * function to continue processing the I/O, instead of completing
+ * the I/O just yet.
+ */
+ if (io->io_hdr.flags & CTL_FLAG_IO_CONT) {
+ io->scsiio.io_cont(io);
+ return;
+ }
+
+ ctl_datamove(io);
+}
+
/*
* SCSI release command.
*/
@@ -7175,6 +7209,66 @@ ctl_read_capacity_16(struct ctl_scsiio *ctsio)
}
int
+ctl_get_lba_status(struct ctl_scsiio *ctsio)
+{
+ struct scsi_get_lba_status *cdb;
+ struct scsi_get_lba_status_data *data;
+ struct ctl_lun *lun;
+ struct ctl_lba_len_flags *lbalen;
+ uint64_t lba;
+ uint32_t alloc_len, total_len;
+ int retval;
+
+ CTL_DEBUG_PRINT(("ctl_get_lba_status\n"));
+
+ lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+ cdb = (struct scsi_get_lba_status *)ctsio->cdb;
+ lba = scsi_8btou64(cdb->addr);
+ alloc_len = scsi_4btoul(cdb->alloc_len);
+
+ if (lba > lun->be_lun->maxlba) {
+ ctl_set_lba_out_of_range(ctsio);
+ ctl_done((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+ }
+
+ total_len = sizeof(*data) + sizeof(data->descr[0]);
+ ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
+ data = (struct scsi_get_lba_status_data *)ctsio->kern_data_ptr;
+
+ if (total_len < alloc_len) {
+ ctsio->residual = alloc_len - total_len;
+ ctsio->kern_data_len = total_len;
+ ctsio->kern_total_len = total_len;
+ } else {
+ ctsio->residual = 0;
+ ctsio->kern_data_len = alloc_len;
+ ctsio->kern_total_len = alloc_len;
+ }
+ ctsio->kern_data_resid = 0;
+ ctsio->kern_rel_offset = 0;
+ ctsio->kern_sg_entries = 0;
+
+ /* Fill dummy data in case backend can't tell anything. */
+ scsi_ulto4b(4 + sizeof(data->descr[0]), data->length);
+ scsi_u64to8b(lba, data->descr[0].addr);
+ scsi_ulto4b(MIN(UINT32_MAX, lun->be_lun->maxlba + 1 - lba),
+ data->descr[0].length);
+ data->descr[0].status = 0; /* Mapped or unknown. */
+
+ ctl_set_success(ctsio);
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
+ ctsio->be_move_done = ctl_config_move_done;
+
+ lbalen = (struct ctl_lba_len_flags *)&ctsio->io_hdr.ctl_private[CTL_PRIV_LBA_LEN];
+ lbalen->lba = lba;
+ lbalen->len = total_len;
+ lbalen->flags = 0;
+ retval = lun->backend->config_read((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+}
+
+int
ctl_read_defect(struct ctl_scsiio *ctsio)
{
struct scsi_read_defect_data_10 *ccb10;
@@ -10644,6 +10738,14 @@ ctl_get_lba_len(union ctl_io *io, uint64_t *lba, uint64_t *len)
*len = UINT64_MAX;
break;
}
+ case SERVICE_ACTION_IN: { /* GET LBA STATUS */
+ struct scsi_get_lba_status *cdb;
+
+ cdb = (struct scsi_get_lba_status *)io->scsiio.cdb;
+ *lba = scsi_8btou64(cdb->addr);
+ *len = UINT32_MAX;
+ break;
+ }
default:
return (1);
break; /* NOTREACHED */
diff --git a/sys/cam/ctl/ctl.h b/sys/cam/ctl/ctl.h
index 9856dcc..1ec0586 100644
--- a/sys/cam/ctl/ctl.h
+++ b/sys/cam/ctl/ctl.h
@@ -186,6 +186,7 @@ int ctl_config_move_done(union ctl_io *io);
void ctl_datamove(union ctl_io *io);
void ctl_done(union ctl_io *io);
void ctl_data_submit_done(union ctl_io *io);
+void ctl_config_read_done(union ctl_io *io);
void ctl_config_write_done(union ctl_io *io);
void ctl_portDB_changed(int portnum);
void ctl_init_isc_msg(void);
diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c
index 6f6b51a..3e33084 100644
--- a/sys/cam/ctl/ctl_backend_block.c
+++ b/sys/cam/ctl/ctl_backend_block.c
@@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include <sys/disk.h>
#include <sys/fcntl.h>
#include <sys/filedesc.h>
+#include <sys/filio.h>
#include <sys/proc.h>
#include <sys/pcpu.h>
#include <sys/module.h>
@@ -165,6 +166,7 @@ struct ctl_be_block_lun {
cbb_dispatch_t dispatch;
cbb_dispatch_t lun_flush;
cbb_dispatch_t unmap;
+ cbb_dispatch_t get_lba_status;
cbb_getattr_t getattr;
uma_zone_t lun_zone;
uint64_t size_blocks;
@@ -182,6 +184,7 @@ struct ctl_be_block_lun {
struct task io_task;
int num_threads;
STAILQ_HEAD(, ctl_io_hdr) input_queue;
+ STAILQ_HEAD(, ctl_io_hdr) config_read_queue;
STAILQ_HEAD(, ctl_io_hdr) config_write_queue;
STAILQ_HEAD(, ctl_io_hdr) datamove_queue;
struct mtx_padalign io_lock;
@@ -240,6 +243,8 @@ static void ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
static void ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
+static void ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun,
+ struct ctl_be_block_io *beio);
static void ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
static void ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun,
@@ -248,6 +253,8 @@ static void ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
static uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun,
const char *attrname);
+static void ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun,
+ union ctl_io *io);
static void ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun,
union ctl_io *io);
static void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun,
@@ -756,6 +763,46 @@ ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun,
}
static void
+ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun,
+ struct ctl_be_block_io *beio)
+{
+ union ctl_io *io = beio->io;
+ struct ctl_lba_len_flags *lbalen = ARGS(io);
+ struct scsi_get_lba_status_data *data;
+ off_t roff, off;
+ int error, status;
+
+ DPRINTF("entered\n");
+
+ off = roff = ((off_t)lbalen->lba) << be_lun->blocksize_shift;
+ vn_lock(be_lun->vn, LK_SHARED | LK_RETRY);
+ error = VOP_IOCTL(be_lun->vn, FIOSEEKHOLE, &off,
+ 0, curthread->td_ucred, curthread);
+ if (error == 0 && off > roff)
+ status = 0; /* mapped up to off */
+ else {
+ error = VOP_IOCTL(be_lun->vn, FIOSEEKDATA, &off,
+ 0, curthread->td_ucred, curthread);
+ if (error == 0 && off > roff)
+ status = 1; /* deallocated up to off */
+ else {
+ status = 0; /* unknown up to the end */
+ off = be_lun->size_bytes;
+ }
+ }
+ VOP_UNLOCK(be_lun->vn, 0);
+
+ off >>= be_lun->blocksize_shift;
+ data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr;
+ scsi_u64to8b(lbalen->lba, data->descr[0].addr);
+ scsi_ulto4b(MIN(UINT32_MAX, off - lbalen->lba),
+ data->descr[0].length);
+ data->descr[0].status = status;
+
+ ctl_complete_beio(beio);
+}
+
+static void
ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio)
{
@@ -848,6 +895,45 @@ ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun,
}
static void
+ctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun,
+ struct ctl_be_block_io *beio)
+{
+ struct ctl_be_block_devdata *dev_data = &be_lun->backend.dev;
+ union ctl_io *io = beio->io;
+ struct ctl_lba_len_flags *lbalen = ARGS(io);
+ struct scsi_get_lba_status_data *data;
+ off_t roff, off;
+ int error, status;
+
+ DPRINTF("entered\n");
+
+ off = roff = ((off_t)lbalen->lba) << be_lun->blocksize_shift;
+ error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKHOLE,
+ (caddr_t)&off, FREAD, curthread);
+ if (error == 0 && off > roff)
+ status = 0; /* mapped up to off */
+ else {
+ error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKDATA,
+ (caddr_t)&off, FREAD, curthread);
+ if (error == 0 && off > roff)
+ status = 1; /* deallocated up to off */
+ else {
+ status = 0; /* unknown up to the end */
+ off = be_lun->size_bytes;
+ }
+ }
+
+ off >>= be_lun->blocksize_shift;
+ data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr;
+ scsi_u64to8b(lbalen->lba, data->descr[0].addr);
+ scsi_ulto4b(MIN(UINT32_MAX, off - lbalen->lba),
+ data->descr[0].length);
+ data->descr[0].status = status;
+
+ ctl_complete_beio(beio);
+}
+
+static void
ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio)
{
@@ -1220,6 +1306,49 @@ ctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun,
}
static void
+ctl_be_block_cr_done(struct ctl_be_block_io *beio)
+{
+ union ctl_io *io;
+
+ io = beio->io;
+ ctl_free_beio(beio);
+ ctl_config_read_done(io);
+}
+
+static void
+ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun,
+ union ctl_io *io)
+{
+ struct ctl_be_block_io *beio;
+ struct ctl_be_block_softc *softc;
+
+ DPRINTF("entered\n");
+
+ softc = be_lun->softc;
+ beio = ctl_alloc_beio(softc);
+ beio->io = io;
+ beio->lun = be_lun;
+ beio->beio_cont = ctl_be_block_cr_done;
+ PRIV(io)->ptr = (void *)beio;
+
+ switch (io->scsiio.cdb[0]) {
+ case SERVICE_ACTION_IN: /* GET LBA STATUS */
+ beio->bio_cmd = -1;
+ beio->ds_trans_type = DEVSTAT_NO_DATA;
+ beio->ds_tag_type = DEVSTAT_TAG_ORDERED;
+ beio->io_len = 0;
+ if (be_lun->get_lba_status)
+ be_lun->get_lba_status(be_lun, beio);
+ else
+ ctl_be_block_cr_done(beio);
+ break;
+ default:
+ panic("Unhandled CDB type %#x", io->scsiio.cdb[0]);
+ break;
+ }
+}
+
+static void
ctl_be_block_cw_done(struct ctl_be_block_io *beio)
{
union ctl_io *io;
@@ -1454,16 +1583,21 @@ ctl_be_block_worker(void *context, int pending)
}
io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue);
if (io != NULL) {
-
DPRINTF("config write queue\n");
-
STAILQ_REMOVE(&be_lun->config_write_queue, &io->io_hdr,
ctl_io_hdr, links);
-
mtx_unlock(&be_lun->queue_lock);
-
ctl_be_block_cw_dispatch(be_lun, io);
-
+ mtx_lock(&be_lun->queue_lock);
+ continue;
+ }
+ io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue);
+ if (io != NULL) {
+ DPRINTF("config read queue\n");
+ STAILQ_REMOVE(&be_lun->config_read_queue, &io->io_hdr,
+ ctl_io_hdr, links);
+ mtx_unlock(&be_lun->queue_lock);
+ ctl_be_block_cr_dispatch(be_lun, io);
mtx_lock(&be_lun->queue_lock);
continue;
}
@@ -1592,6 +1726,7 @@ ctl_be_block_open_file(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
be_lun->dev_type = CTL_BE_BLOCK_FILE;
be_lun->dispatch = ctl_be_block_dispatch_file;
be_lun->lun_flush = ctl_be_block_flush_file;
+ be_lun->get_lba_status = ctl_be_block_gls_file;
error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred);
if (error != 0) {
@@ -1678,9 +1813,10 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
&be_lun->backend.dev.dev_ref);
if (be_lun->backend.dev.csw == NULL)
panic("Unable to retrieve device switch");
- if (strcmp(be_lun->backend.dev.csw->d_name, "zvol") == 0)
+ if (strcmp(be_lun->backend.dev.csw->d_name, "zvol") == 0) {
be_lun->dispatch = ctl_be_block_dispatch_zvol;
- else
+ be_lun->get_lba_status = ctl_be_block_gls_zvol;
+ } else
be_lun->dispatch = ctl_be_block_dispatch_dev;
be_lun->lun_flush = ctl_be_block_flush_dev;
be_lun->unmap = ctl_be_block_unmap_dev;
@@ -1955,6 +2091,7 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
be_lun->params = req->reqdata.create;
be_lun->softc = softc;
STAILQ_INIT(&be_lun->input_queue);
+ STAILQ_INIT(&be_lun->config_read_queue);
STAILQ_INIT(&be_lun->config_write_queue);
STAILQ_INIT(&be_lun->datamove_queue);
sprintf(be_lun->lunname, "cblk%d", softc->num_luns);
@@ -2585,13 +2722,50 @@ ctl_be_block_config_write(union ctl_io *io)
}
return (retval);
-
}
static int
ctl_be_block_config_read(union ctl_io *io)
{
- return (0);
+ struct ctl_be_block_lun *be_lun;
+ struct ctl_be_lun *ctl_be_lun;
+ int retval = 0;
+
+ DPRINTF("entered\n");
+
+ ctl_be_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[
+ CTL_PRIV_BACKEND_LUN].ptr;
+ be_lun = (struct ctl_be_block_lun *)ctl_be_lun->be_lun;
+
+ switch (io->scsiio.cdb[0]) {
+ case SERVICE_ACTION_IN:
+ if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) {
+ mtx_lock(&be_lun->queue_lock);
+ STAILQ_INSERT_TAIL(&be_lun->config_read_queue,
+ &io->io_hdr, links);
+ mtx_unlock(&be_lun->queue_lock);
+ taskqueue_enqueue(be_lun->io_taskqueue,
+ &be_lun->io_task);
+ retval = CTL_RETVAL_QUEUED;
+ break;
+ }
+ ctl_set_invalid_field(&io->scsiio,
+ /*sks_valid*/ 1,
+ /*command*/ 1,
+ /*field*/ 1,
+ /*bit_valid*/ 1,
+ /*bit*/ 4);
+ ctl_config_read_done(io);
+ retval = CTL_RETVAL_COMPLETE;
+ break;
+ default:
+ ctl_set_invalid_opcode(&io->scsiio);
+ ctl_config_read_done(io);
+ retval = CTL_RETVAL_COMPLETE;
+ break;
+ }
+
+ return (retval);
}
static int
diff --git a/sys/cam/ctl/ctl_backend_ramdisk.c b/sys/cam/ctl/ctl_backend_ramdisk.c
index 9b3b14a..adace4f 100644
--- a/sys/cam/ctl/ctl_backend_ramdisk.c
+++ b/sys/cam/ctl/ctl_backend_ramdisk.c
@@ -967,8 +967,31 @@ ctl_backend_ramdisk_config_write(union ctl_io *io)
static int
ctl_backend_ramdisk_config_read(union ctl_io *io)
{
- /*
- * XXX KDM need to implement!!
- */
- return (0);
+ int retval = 0;
+
+ switch (io->scsiio.cdb[0]) {
+ case SERVICE_ACTION_IN:
+ if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) {
+ /* We have nothing to tell, leave default data. */
+ ctl_config_read_done(io);
+ retval = CTL_RETVAL_COMPLETE;
+ break;
+ }
+ ctl_set_invalid_field(&io->scsiio,
+ /*sks_valid*/ 1,
+ /*command*/ 1,
+ /*field*/ 1,
+ /*bit_valid*/ 1,
+ /*bit*/ 4);
+ ctl_config_read_done(io);
+ retval = CTL_RETVAL_COMPLETE;
+ break;
+ default:
+ ctl_set_invalid_opcode(&io->scsiio);
+ ctl_config_read_done(io);
+ retval = CTL_RETVAL_COMPLETE;
+ break;
+ }
+
+ return (retval);
}
diff --git a/sys/cam/ctl/ctl_cmd_table.c b/sys/cam/ctl/ctl_cmd_table.c
index 5ae5057..24c0091 100644
--- a/sys/cam/ctl/ctl_cmd_table.c
+++ b/sys/cam/ctl/ctl_cmd_table.c
@@ -433,7 +433,7 @@ const struct ctl_cmd_entry ctl_cmd_table_9e[32] =
/* 0F */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
-/* 10 */
+/* 10 READ CAPACITY(16) */
{ctl_read_capacity_16, CTL_SERIDX_RD_CAP, CTL_CMD_FLAG_OK_ON_SLUN |
CTL_CMD_FLAG_OK_ON_STOPPED |
CTL_CMD_FLAG_OK_ON_INOPERABLE |
@@ -443,7 +443,18 @@ const struct ctl_cmd_entry ctl_cmd_table_9e[32] =
CTL_LUN_PAT_READCAP,
16, {0x10, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
-/* 11-1f */
+/* 11 */
+{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+
+/* 12 GET LBA STATUS */
+{ctl_get_lba_status, CTL_SERIDX_READ, CTL_CMD_FLAG_OK_ON_SLUN |
+ CTL_FLAG_DATA_IN |
+ CTL_CMD_FLAG_ALLOW_ON_PR_WRESV,
+ CTL_LUN_PAT_READ | CTL_LUN_PAT_RANGE,
+ 16, {0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0, 0x07}},
+
+/* 13-1f */
};
/* A3 MAINTENANCE IN */
diff --git a/sys/cam/ctl/ctl_private.h b/sys/cam/ctl/ctl_private.h
index dac8123..351b7f8 100644
--- a/sys/cam/ctl/ctl_private.h
+++ b/sys/cam/ctl/ctl_private.h
@@ -516,6 +516,7 @@ int ctl_report_supported_opcodes(struct ctl_scsiio *ctsio);
int ctl_report_supported_tmf(struct ctl_scsiio *ctsio);
int ctl_report_timestamp(struct ctl_scsiio *ctsio);
int ctl_isc(struct ctl_scsiio *ctsio);
+int ctl_get_lba_status(struct ctl_scsiio *ctsio);
void ctl_tpc_init(struct ctl_softc *softc);
void ctl_tpc_shutdown(struct ctl_softc *softc);
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
index 6ee0370..d536a74 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -2518,6 +2518,32 @@ struct scsi_read_capacity_data_long
uint8_t reserved[16];
};
+struct scsi_get_lba_status
+{
+ uint8_t opcode;
+#define SGLS_SERVICE_ACTION 0x12
+ uint8_t service_action;
+ uint8_t addr[8];
+ uint8_t alloc_len[4];
+ uint8_t reserved;
+ uint8_t control;
+};
+
+struct scsi_get_lba_status_data_descr
+{
+ uint8_t addr[8];
+ uint8_t length[4];
+ uint8_t status;
+ uint8_t reserved[3];
+};
+
+struct scsi_get_lba_status_data
+{
+ uint8_t length[4];
+ uint8_t reserved[4];
+ struct scsi_get_lba_status_data_descr descr[];
+};
+
struct scsi_report_luns
{
uint8_t opcode;
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
index 0451c65..e483d33 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zvol.c
@@ -91,6 +91,7 @@
#include <sys/dmu_tx.h>
#include <sys/zfeature.h>
#include <sys/zio_checksum.h>
+#include <sys/filio.h>
#include <geom/geom.h>
@@ -2914,6 +2915,18 @@ zvol_d_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct threa
error = ENOIOCTL;
break;
}
+ case FIOSEEKHOLE:
+ case FIOSEEKDATA: {
+ off_t *off = (off_t *)data;
+ uint64_t noff;
+ boolean_t hole;
+
+ hole = (cmd == FIOSEEKHOLE);
+ noff = *off;
+ error = dmu_offset_next(zv->zv_objset, ZVOL_OBJ, hole, &noff);
+ *off = noff;
+ break;
+ }
default:
error = ENOIOCTL;
}
OpenPOWER on IntegriCloud