summaryrefslogtreecommitdiff
path: root/sys/cam/ctl/ctl_backend_block.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cam/ctl/ctl_backend_block.c')
-rw-r--r--sys/cam/ctl/ctl_backend_block.c383
1 files changed, 223 insertions, 160 deletions
diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c
index 799f74273ace..c9d2a570a2bc 100644
--- a/sys/cam/ctl/ctl_backend_block.c
+++ b/sys/cam/ctl/ctl_backend_block.c
@@ -85,7 +85,9 @@ __FBSDID("$FreeBSD$");
#include <cam/ctl/ctl.h>
#include <cam/ctl/ctl_backend.h>
#include <cam/ctl/ctl_ioctl.h>
+#include <cam/ctl/ctl_ha.h>
#include <cam/ctl/ctl_scsi_all.h>
+#include <cam/ctl/ctl_private.h>
#include <cam/ctl/ctl_error.h>
/*
@@ -124,18 +126,11 @@ typedef enum {
CTL_BE_BLOCK_FILE
} ctl_be_block_type;
-struct ctl_be_block_devdata {
- struct cdev *cdev;
- struct cdevsw *csw;
- int dev_ref;
-};
-
struct ctl_be_block_filedata {
struct ucred *cred;
};
union ctl_be_block_bedata {
- struct ctl_be_block_devdata dev;
struct ctl_be_block_filedata file;
};
@@ -217,6 +212,8 @@ struct ctl_be_block_io {
void (*beio_cont)(struct ctl_be_block_io *beio); /* to continue processing */
};
+extern struct ctl_softc *control_softc;
+
static int cbb_num_threads = 14;
SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, block, CTLFLAG_RD, 0,
"CAM Target Layer Block Backend");
@@ -819,16 +816,15 @@ static void
ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio)
{
- struct ctl_be_block_devdata *dev_data;
union ctl_io *io;
+ struct cdevsw *csw;
+ struct cdev *dev;
struct uio xuio;
struct iovec *xiovec;
- int flags;
- int error, i;
+ int error, flags, i, ref;
DPRINTF("entered\n");
- dev_data = &be_lun->backend.dev;
io = beio->io;
flags = 0;
if (ARGS(io)->flags & CTL_LLF_DPO)
@@ -861,13 +857,20 @@ ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun,
devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0);
mtx_unlock(&be_lun->io_lock);
- if (beio->bio_cmd == BIO_READ) {
- error = (*dev_data->csw->d_read)(dev_data->cdev, &xuio, flags);
+ csw = devvn_refthread(be_lun->vn, &dev, &ref);
+ if (csw) {
+ if (beio->bio_cmd == BIO_READ)
+ error = csw->d_read(dev, &xuio, flags);
+ else
+ error = csw->d_write(dev, &xuio, flags);
+ dev_relthread(dev, ref);
+ } else
+ error = ENXIO;
+
+ if (beio->bio_cmd == BIO_READ)
SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0);
- } else {
- error = (*dev_data->csw->d_write)(dev_data->cdev, &xuio, flags);
+ else
SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0);
- }
mtx_lock(&be_lun->io_lock);
devstat_end_transaction(beio->lun->disk_stats, beio->io_len,
@@ -911,23 +914,30 @@ 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 cdevsw *csw;
+ struct cdev *dev;
struct ctl_lba_len_flags *lbalen = ARGS(io);
struct scsi_get_lba_status_data *data;
off_t roff, off;
- int error, status;
+ int error, ref, status;
DPRINTF("entered\n");
+ csw = devvn_refthread(be_lun->vn, &dev, &ref);
+ if (csw == NULL) {
+ status = 0; /* unknown up to the end */
+ off = be_lun->size_bytes;
+ goto done;
+ }
off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize;
- error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKHOLE,
- (caddr_t)&off, FREAD, curthread);
+ error = csw->d_ioctl(dev, 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);
+ error = csw->d_ioctl(dev, FIOSEEKDATA, (caddr_t)&off, FREAD,
+ curthread);
if (error == 0 && off > roff)
status = 1; /* deallocated up to off */
else {
@@ -935,7 +945,9 @@ ctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun,
off = be_lun->size_bytes;
}
}
+ dev_relthread(dev, ref);
+done:
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 / be_lun->cbe_lun.blocksize -
@@ -951,9 +963,10 @@ ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun,
{
struct bio *bio;
union ctl_io *io;
- struct ctl_be_block_devdata *dev_data;
+ struct cdevsw *csw;
+ struct cdev *dev;
+ int ref;
- dev_data = &be_lun->backend.dev;
io = beio->io;
DPRINTF("entered\n");
@@ -962,7 +975,6 @@ ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun,
bio = g_alloc_bio();
bio->bio_cmd = BIO_FLUSH;
- bio->bio_dev = dev_data->cdev;
bio->bio_offset = 0;
bio->bio_data = 0;
bio->bio_done = ctl_be_block_biodone;
@@ -982,7 +994,15 @@ ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun,
devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0);
mtx_unlock(&be_lun->io_lock);
- (*dev_data->csw->d_strategy)(bio);
+ csw = devvn_refthread(be_lun->vn, &dev, &ref);
+ if (csw) {
+ bio->bio_dev = dev;
+ csw->d_strategy(bio);
+ dev_relthread(dev, ref);
+ } else {
+ bio->bio_error = ENXIO;
+ ctl_be_block_biodone(bio);
+ }
}
static void
@@ -991,15 +1011,17 @@ ctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun,
uint64_t off, uint64_t len, int last)
{
struct bio *bio;
- struct ctl_be_block_devdata *dev_data;
uint64_t maxlen;
+ struct cdevsw *csw;
+ struct cdev *dev;
+ int ref;
- dev_data = &be_lun->backend.dev;
+ csw = devvn_refthread(be_lun->vn, &dev, &ref);
maxlen = LONG_MAX - (LONG_MAX % be_lun->cbe_lun.blocksize);
while (len > 0) {
bio = g_alloc_bio();
bio->bio_cmd = BIO_DELETE;
- bio->bio_dev = dev_data->cdev;
+ bio->bio_dev = dev;
bio->bio_offset = off;
bio->bio_length = MIN(len, maxlen);
bio->bio_data = 0;
@@ -1016,8 +1038,15 @@ ctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun,
beio->send_complete = 1;
mtx_unlock(&be_lun->io_lock);
- (*dev_data->csw->d_strategy)(bio);
+ if (csw) {
+ csw->d_strategy(bio);
+ } else {
+ bio->bio_error = ENXIO;
+ ctl_be_block_biodone(bio);
+ }
}
+ if (csw)
+ dev_relthread(dev, ref);
}
static void
@@ -1025,12 +1054,10 @@ ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio)
{
union ctl_io *io;
- struct ctl_be_block_devdata *dev_data;
struct ctl_ptr_len_flags *ptrlen;
struct scsi_unmap_desc *buf, *end;
uint64_t len;
- dev_data = &be_lun->backend.dev;
io = beio->io;
DPRINTF("entered\n");
@@ -1063,23 +1090,25 @@ ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio)
{
TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue);
- int i;
struct bio *bio;
- struct ctl_be_block_devdata *dev_data;
+ struct cdevsw *csw;
+ struct cdev *dev;
off_t cur_offset;
- int max_iosize;
+ int i, max_iosize, ref;
DPRINTF("entered\n");
-
- dev_data = &be_lun->backend.dev;
+ csw = devvn_refthread(be_lun->vn, &dev, &ref);
/*
* We have to limit our I/O size to the maximum supported by the
* backend device. Hopefully it is MAXPHYS. If the driver doesn't
* set it properly, use DFLTPHYS.
*/
- max_iosize = dev_data->cdev->si_iosize_max;
- if (max_iosize < PAGE_SIZE)
+ if (csw) {
+ max_iosize = dev->si_iosize_max;
+ if (max_iosize < PAGE_SIZE)
+ max_iosize = DFLTPHYS;
+ } else
max_iosize = DFLTPHYS;
cur_offset = beio->io_offset;
@@ -1097,7 +1126,7 @@ ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
KASSERT(bio != NULL, ("g_alloc_bio() failed!\n"));
bio->bio_cmd = beio->bio_cmd;
- bio->bio_dev = dev_data->cdev;
+ bio->bio_dev = dev;
bio->bio_caller1 = beio;
bio->bio_length = min(cur_size, max_iosize);
bio->bio_offset = cur_offset;
@@ -1124,23 +1153,36 @@ ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
*/
while ((bio = TAILQ_FIRST(&queue)) != NULL) {
TAILQ_REMOVE(&queue, bio, bio_queue);
- (*dev_data->csw->d_strategy)(bio);
+ if (csw)
+ csw->d_strategy(bio);
+ else {
+ bio->bio_error = ENXIO;
+ ctl_be_block_biodone(bio);
+ }
}
+ if (csw)
+ dev_relthread(dev, ref);
}
static uint64_t
ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname)
{
- struct ctl_be_block_devdata *dev_data = &be_lun->backend.dev;
struct diocgattr_arg arg;
- int error;
+ struct cdevsw *csw;
+ struct cdev *dev;
+ int error, ref;
- if (dev_data->csw == NULL || dev_data->csw->d_ioctl == NULL)
+ csw = devvn_refthread(be_lun->vn, &dev, &ref);
+ if (csw == NULL)
return (UINT64_MAX);
strlcpy(arg.name, attrname, sizeof(arg.name));
arg.len = sizeof(arg.value.off);
- error = dev_data->csw->d_ioctl(dev_data->cdev,
- DIOCGATTR, (caddr_t)&arg, FREAD, curthread);
+ if (csw->d_ioctl) {
+ error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD,
+ curthread);
+ } else
+ error = ENODEV;
+ dev_relthread(dev, ref);
if (error != 0)
return (UINT64_MAX);
return (arg.value.off);
@@ -1573,33 +1615,32 @@ ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun,
static void
ctl_be_block_worker(void *context, int pending)
{
- struct ctl_be_block_lun *be_lun;
- struct ctl_be_block_softc *softc;
+ struct ctl_be_block_lun *be_lun = (struct ctl_be_block_lun *)context;
+ struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
union ctl_io *io;
-
- be_lun = (struct ctl_be_block_lun *)context;
- softc = be_lun->softc;
+ struct ctl_be_block_io *beio;
DPRINTF("entered\n");
-
- mtx_lock(&be_lun->queue_lock);
+ /*
+ * Fetch and process I/Os from all queues. If we detect LUN
+ * CTL_LUN_FLAG_OFFLINE status here -- it is result of a race,
+ * so make response maximally opaque to not confuse initiator.
+ */
for (;;) {
+ mtx_lock(&be_lun->queue_lock);
io = (union ctl_io *)STAILQ_FIRST(&be_lun->datamove_queue);
if (io != NULL) {
- struct ctl_be_block_io *beio;
-
DPRINTF("datamove queue\n");
-
STAILQ_REMOVE(&be_lun->datamove_queue, &io->io_hdr,
ctl_io_hdr, links);
-
mtx_unlock(&be_lun->queue_lock);
-
beio = (struct ctl_be_block_io *)PRIV(io)->ptr;
-
+ if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) {
+ ctl_set_busy(&io->scsiio);
+ ctl_complete_beio(beio);
+ return;
+ }
be_lun->dispatch(be_lun, beio);
-
- mtx_lock(&be_lun->queue_lock);
continue;
}
io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue);
@@ -1608,8 +1649,12 @@ ctl_be_block_worker(void *context, int pending)
STAILQ_REMOVE(&be_lun->config_write_queue, &io->io_hdr,
ctl_io_hdr, links);
mtx_unlock(&be_lun->queue_lock);
+ if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) {
+ ctl_set_busy(&io->scsiio);
+ ctl_config_write_done(io);
+ return;
+ }
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);
@@ -1618,25 +1663,26 @@ ctl_be_block_worker(void *context, int pending)
STAILQ_REMOVE(&be_lun->config_read_queue, &io->io_hdr,
ctl_io_hdr, links);
mtx_unlock(&be_lun->queue_lock);
+ if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) {
+ ctl_set_busy(&io->scsiio);
+ ctl_config_read_done(io);
+ return;
+ }
ctl_be_block_cr_dispatch(be_lun, io);
- mtx_lock(&be_lun->queue_lock);
continue;
}
io = (union ctl_io *)STAILQ_FIRST(&be_lun->input_queue);
if (io != NULL) {
DPRINTF("input queue\n");
-
STAILQ_REMOVE(&be_lun->input_queue, &io->io_hdr,
ctl_io_hdr, links);
mtx_unlock(&be_lun->queue_lock);
-
- /*
- * We must drop the lock, since this routine and
- * its children may sleep.
- */
+ if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) {
+ ctl_set_busy(&io->scsiio);
+ ctl_data_submit_done(io);
+ return;
+ }
ctl_be_block_dispatch(be_lun, io);
-
- mtx_lock(&be_lun->queue_lock);
continue;
}
@@ -1644,9 +1690,9 @@ ctl_be_block_worker(void *context, int pending)
* If we get here, there is no work left in the queues, so
* just break out and let the task queue go to sleep.
*/
+ mtx_unlock(&be_lun->queue_lock);
break;
}
- mtx_unlock(&be_lun->queue_lock);
}
/*
@@ -1849,22 +1895,19 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
{
struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
struct ctl_lun_create_params *params;
- struct vattr vattr;
+ struct cdevsw *csw;
struct cdev *dev;
- struct cdevsw *devsw;
char *value;
- int error, atomic, maxio, unmap, tmp;
+ int error, atomic, maxio, ref, unmap, tmp;
off_t ps, pss, po, pos, us, uss, uo, uos, otmp;
params = &be_lun->params;
be_lun->dev_type = CTL_BE_BLOCK_DEV;
- be_lun->backend.dev.cdev = be_lun->vn->v_rdev;
- be_lun->backend.dev.csw = dev_refthread(be_lun->backend.dev.cdev,
- &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) {
+ csw = devvn_refthread(be_lun->vn, &dev, &ref);
+ if (csw == NULL)
+ return (ENXIO);
+ if (strcmp(csw->d_name, "zvol") == 0) {
be_lun->dispatch = ctl_be_block_dispatch_zvol;
be_lun->get_lba_status = ctl_be_block_gls_zvol;
atomic = maxio = CTLBLK_MAX_IO_SIZE;
@@ -1872,7 +1915,7 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
be_lun->dispatch = ctl_be_block_dispatch_dev;
be_lun->get_lba_status = NULL;
atomic = 0;
- maxio = be_lun->backend.dev.cdev->si_iosize_max;
+ maxio = dev->si_iosize_max;
if (maxio <= 0)
maxio = DFLTPHYS;
if (maxio > CTLBLK_MAX_IO_SIZE)
@@ -1882,26 +1925,17 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
be_lun->getattr = ctl_be_block_getattr_dev;
be_lun->unmap = ctl_be_block_unmap_dev;
- error = VOP_GETATTR(be_lun->vn, &vattr, NOCRED);
- if (error) {
- snprintf(req->error_str, sizeof(req->error_str),
- "error getting vnode attributes for device %s",
- be_lun->dev_path);
- return (error);
- }
-
- dev = be_lun->vn->v_rdev;
- devsw = dev->si_devsw;
- if (!devsw->d_ioctl) {
+ if (!csw->d_ioctl) {
+ dev_relthread(dev, ref);
snprintf(req->error_str, sizeof(req->error_str),
- "no d_ioctl for device %s!",
- be_lun->dev_path);
+ "no d_ioctl for device %s!", be_lun->dev_path);
return (ENODEV);
}
- error = devsw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD,
+ error = csw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD,
curthread);
if (error) {
+ dev_relthread(dev, ref);
snprintf(req->error_str, sizeof(req->error_str),
"error %d returned for DIOCGSECTORSIZE ioctl "
"on %s!", error, be_lun->dev_path);
@@ -1919,14 +1953,15 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
if (params->blocksize_bytes % tmp == 0) {
cbe_lun->blocksize = params->blocksize_bytes;
} else {
+ dev_relthread(dev, ref);
snprintf(req->error_str, sizeof(req->error_str),
"requested blocksize %u is not an even "
"multiple of backing device blocksize %u",
params->blocksize_bytes, tmp);
return (EINVAL);
-
}
} else if (params->blocksize_bytes != 0) {
+ dev_relthread(dev, ref);
snprintf(req->error_str, sizeof(req->error_str),
"requested blocksize %u < backing device "
"blocksize %u", params->blocksize_bytes, tmp);
@@ -1934,9 +1969,10 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
} else
cbe_lun->blocksize = tmp;
- error = devsw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD,
- curthread);
+ error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD,
+ curthread);
if (error) {
+ dev_relthread(dev, ref);
snprintf(req->error_str, sizeof(req->error_str),
"error %d returned for DIOCGMEDIASIZE "
" ioctl on %s!", error,
@@ -1946,6 +1982,7 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
if (params->lun_size_bytes != 0) {
if (params->lun_size_bytes > otmp) {
+ dev_relthread(dev, ref);
snprintf(req->error_str, sizeof(req->error_str),
"requested LUN size %ju > backing device "
"size %ju",
@@ -1961,13 +1998,13 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
cbe_lun->maxlba = (be_lun->size_blocks == 0) ?
0 : (be_lun->size_blocks - 1);
- error = devsw->d_ioctl(dev, DIOCGSTRIPESIZE,
- (caddr_t)&ps, FREAD, curthread);
+ error = csw->d_ioctl(dev, DIOCGSTRIPESIZE, (caddr_t)&ps, FREAD,
+ curthread);
if (error)
ps = po = 0;
else {
- error = devsw->d_ioctl(dev, DIOCGSTRIPEOFFSET,
- (caddr_t)&po, FREAD, curthread);
+ error = csw->d_ioctl(dev, DIOCGSTRIPEOFFSET, (caddr_t)&po,
+ FREAD, curthread);
if (error)
po = 0;
}
@@ -2012,8 +2049,8 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name));
arg.len = sizeof(arg.value.i);
- error = devsw->d_ioctl(dev, DIOCGATTR,
- (caddr_t)&arg, FREAD, curthread);
+ error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD,
+ curthread);
unmap = (error == 0) ? arg.value.i : 0;
}
value = ctl_get_opt(&cbe_lun->options, "unmap");
@@ -2024,6 +2061,7 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
else
cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP;
+ dev_relthread(dev, ref);
return (0);
}
@@ -2034,24 +2072,6 @@ ctl_be_block_close(struct ctl_be_block_lun *be_lun)
int flags;
if (be_lun->vn) {
- switch (be_lun->dev_type) {
- case CTL_BE_BLOCK_DEV:
- if (be_lun->backend.dev.csw) {
- dev_relthread(be_lun->backend.dev.cdev,
- be_lun->backend.dev.dev_ref);
- be_lun->backend.dev.csw = NULL;
- be_lun->backend.dev.cdev = NULL;
- }
- break;
- case CTL_BE_BLOCK_FILE:
- break;
- case CTL_BE_BLOCK_NONE:
- break;
- default:
- panic("Unexpected backend type.");
- break;
- }
-
flags = FREAD;
if ((cbe_lun->flags & CTL_LUN_FLAG_READONLY) == 0)
flags |= FWRITE;
@@ -2214,7 +2234,13 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
else
cbe_lun->lun_type = T_DIRECT;
be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED;
- cbe_lun->flags = CTL_LUN_FLAG_PRIMARY;
+ cbe_lun->flags = 0;
+ value = ctl_get_opt(&cbe_lun->options, "ha_role");
+ if (value != NULL) {
+ if (strcmp(value, "primary") == 0)
+ cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
+ } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF)
+ cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
if (cbe_lun->lun_type == T_DIRECT) {
be_lun->size_bytes = params->lun_size_bytes;
@@ -2226,10 +2252,13 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
cbe_lun->maxlba = (be_lun->size_blocks == 0) ?
0 : (be_lun->size_blocks - 1);
- retval = ctl_be_block_open(softc, be_lun, req);
- if (retval != 0) {
- retval = 0;
- req->status = CTL_LUN_WARNING;
+ if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) ||
+ control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) {
+ retval = ctl_be_block_open(softc, be_lun, req);
+ if (retval != 0) {
+ retval = 0;
+ req->status = CTL_LUN_WARNING;
+ }
}
num_threads = cbb_num_threads;
} else {
@@ -2418,6 +2447,7 @@ ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
{
struct ctl_lun_rm_params *params;
struct ctl_be_block_lun *be_lun;
+ struct ctl_be_lun *cbe_lun;
int retval;
params = &req->reqdata.rm;
@@ -2435,18 +2465,24 @@ ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
params->lun_id);
goto bailout_error;
}
+ cbe_lun = &be_lun->cbe_lun;
- retval = ctl_disable_lun(&be_lun->cbe_lun);
-
+ retval = ctl_disable_lun(cbe_lun);
if (retval != 0) {
snprintf(req->error_str, sizeof(req->error_str),
"error %d returned from ctl_disable_lun() for "
"LUN %d", retval, params->lun_id);
goto bailout_error;
+ }
+ if (be_lun->vn != NULL) {
+ cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE;
+ ctl_lun_offline(cbe_lun);
+ taskqueue_drain_all(be_lun->io_taskqueue);
+ ctl_be_block_close(be_lun);
}
- retval = ctl_invalidate_lun(&be_lun->cbe_lun);
+ retval = ctl_invalidate_lun(cbe_lun);
if (retval != 0) {
snprintf(req->error_str, sizeof(req->error_str),
"error %d returned from ctl_invalidate_lun() for "
@@ -2455,15 +2491,12 @@ ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
}
mtx_lock(&softc->lock);
-
be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING;
-
while ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) {
retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0);
if (retval == EINTR)
break;
}
-
be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING;
if ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) {
@@ -2478,18 +2511,15 @@ ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
softc->num_luns--;
mtx_unlock(&softc->lock);
- taskqueue_drain(be_lun->io_taskqueue, &be_lun->io_task);
-
+ taskqueue_drain_all(be_lun->io_taskqueue);
taskqueue_free(be_lun->io_taskqueue);
- ctl_be_block_close(be_lun);
-
if (be_lun->disk_stats != NULL)
devstat_remove_entry(be_lun->disk_stats);
uma_zdestroy(be_lun->lun_zone);
- ctl_free_opts(&be_lun->cbe_lun.options);
+ ctl_free_opts(&cbe_lun->options);
free(be_lun->dev_path, M_CTLBLK);
mtx_destroy(&be_lun->queue_lock);
mtx_destroy(&be_lun->io_lock);
@@ -2540,21 +2570,25 @@ ctl_be_block_modify_dev(struct ctl_be_block_lun *be_lun,
struct ctl_lun_req *req)
{
struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun;
- struct ctl_be_block_devdata *dev_data;
- int error;
struct ctl_lun_create_params *params = &be_lun->params;
+ struct cdevsw *csw;
+ struct cdev *dev;
uint64_t size_bytes;
+ int error, ref;
- dev_data = &be_lun->backend.dev;
- if (!dev_data->csw->d_ioctl) {
+ csw = devvn_refthread(be_lun->vn, &dev, &ref);
+ if (csw == NULL)
+ return (ENXIO);
+ if (csw->d_ioctl == NULL) {
+ dev_relthread(dev, ref);
snprintf(req->error_str, sizeof(req->error_str),
"no d_ioctl for device %s!", be_lun->dev_path);
return (ENODEV);
}
- error = dev_data->csw->d_ioctl(dev_data->cdev, DIOCGMEDIASIZE,
- (caddr_t)&size_bytes, FREAD,
- curthread);
+ error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&size_bytes, FREAD,
+ curthread);
+ dev_relthread(dev, ref);
if (error) {
snprintf(req->error_str, sizeof(req->error_str),
"error %d returned for DIOCGMEDIASIZE ioctl "
@@ -2587,8 +2621,9 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
struct ctl_lun_modify_params *params;
struct ctl_be_block_lun *be_lun;
struct ctl_be_lun *cbe_lun;
+ char *value;
uint64_t oldsize;
- int error;
+ int error, wasprim;
params = &req->reqdata.modify;
@@ -2611,23 +2646,51 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
be_lun->params.lun_size_bytes = params->lun_size_bytes;
ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args);
- oldsize = be_lun->size_blocks;
- if (be_lun->vn == NULL)
- error = ctl_be_block_open(softc, be_lun, req);
- else if (vn_isdisk(be_lun->vn, &error))
- error = ctl_be_block_modify_dev(be_lun, req);
- else if (be_lun->vn->v_type == VREG)
- error = ctl_be_block_modify_file(be_lun, req);
+ wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY);
+ value = ctl_get_opt(&cbe_lun->options, "ha_role");
+ if (value != NULL) {
+ if (strcmp(value, "primary") == 0)
+ cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
+ else
+ cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY;
+ } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF)
+ cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
else
- error = EINVAL;
+ cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY;
+ if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) {
+ if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)
+ ctl_lun_primary(cbe_lun);
+ else
+ ctl_lun_secondary(cbe_lun);
+ }
+ oldsize = be_lun->size_blocks;
+ if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) ||
+ control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) {
+ if (be_lun->vn == NULL)
+ error = ctl_be_block_open(softc, be_lun, req);
+ else if (vn_isdisk(be_lun->vn, &error))
+ error = ctl_be_block_modify_dev(be_lun, req);
+ else if (be_lun->vn->v_type == VREG)
+ error = ctl_be_block_modify_file(be_lun, req);
+ else
+ error = EINVAL;
+ if ((cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) &&
+ be_lun->vn != NULL) {
+ cbe_lun->flags &= ~CTL_LUN_FLAG_OFFLINE;
+ ctl_lun_online(cbe_lun);
+ }
+ } else {
+ if (be_lun->vn != NULL) {
+ cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE;
+ ctl_lun_offline(cbe_lun);
+ taskqueue_drain_all(be_lun->io_taskqueue);
+ error = ctl_be_block_close(be_lun);
+ } else
+ error = 0;
+ }
if (be_lun->size_blocks != oldsize)
ctl_lun_capacity_changed(cbe_lun);
- if ((cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) &&
- be_lun->vn != NULL) {
- cbe_lun->flags &= ~CTL_LUN_FLAG_OFFLINE;
- ctl_lun_online(cbe_lun);
- }
/* Tell the user the exact size we ended up using */
params->lun_size_bytes = be_lun->size_bytes;