53#include <sys/kernel.h>
55#include <sys/kthread.h>
58#include <sys/limits.h>
61#include <sys/condvar.h>
62#include <sys/malloc.h>
64#include <sys/ioccom.h>
67#include <sys/endian.h>
70#include <sys/taskqueue.h>
76#include <sys/filedesc.h>
80#include <sys/module.h>
82#include <sys/devicestat.h>
83#include <sys/sysctl.h>
87#include <sys/unistd.h>
108#define CTLBLK_MAX_SEGS 8
109#define CTLBLK_HALF_SEGS (CTLBLK_MAX_SEGS / 2)
110#define CTLBLK_MIN_SEG (128 * 1024)
111#define CTLBLK_MAX_SEG MIN(1024 * 1024, MAX(CTLBLK_MIN_SEG, maxphys))
112#define CTLBLK_MAX_IO_SIZE (CTLBLK_MAX_SEG * CTLBLK_MAX_SEGS)
115#define DPRINTF(fmt, args...) \
116 printf("cbb(%s:%d): " fmt, __FUNCTION__, __LINE__, ##args)
118#define DPRINTF(fmt, args...) do {} while(0)
122 ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND])
124 ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN])
153 const char *attrname);
177 struct taskqueue *io_taskqueue;
184 struct mtx_padalign io_lock;
185 struct mtx_padalign queue_lock;
196 uma_zone_t beio_zone;
197 uma_zone_t bufmin_zone;
198 uma_zone_t bufmax_zone;
233SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, block, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
234 "CAM Target Layer Block Backend");
235SYSCTL_INT(_kern_cam_ctl_block, OID_AUTO, num_threads, CTLFLAG_RWTUN,
250 const char *attrname);
260 const char *attrname);
270 int flag,
struct thread *td);
315 sg->
addr = uma_zalloc(softc->bufmin_zone, M_WAITOK);
319 sg->
addr = uma_zalloc(softc->bufmax_zone, M_WAITOK);
329 uma_zfree(softc->bufmin_zone, sg->
addr);
333 uma_zfree(softc->bufmax_zone, sg->
addr);
342 beio = uma_zalloc(
softc->beio_zone, M_WAITOK | M_ZERO);
354 for (i = 0; i < beio->
num_segs; i++) {
364 uma_zfree(softc->beio_zone, beio);
372 if (atomic_fetchadd_int(&beio->
refcnt, diff) + diff == 0)
397cmp(uint8_t *a, uint8_t *b,
size_t size)
401 for (i = 0; i < size; i++) {
418 for (i = 0; i < beio->
num_segs; i++) {
423 if (res < beio->
sg_segs[i].len)
467 if ((beio->
bio_cmd == BIO_READ)
487 mtx_lock(&be_lun->queue_lock);
488 STAILQ_INSERT_TAIL(&be_lun->datamove_queue, &io->
io_hdr, links);
489 mtx_unlock(&be_lun->queue_lock);
490 taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task);
508 error = bio->bio_error;
509 mtx_lock(&be_lun->io_lock);
531 mtx_unlock(&be_lun->io_lock);
542 mtx_unlock(&be_lun->io_lock);
550 if (error == EOPNOTSUPP) {
552 }
else if (error == ENOSPC || error == EDQUOT) {
554 }
else if (error == EROFS || error == EACCES) {
556 }
else if (beio->
bio_cmd == BIO_FLUSH) {
573 if ((beio->
bio_cmd == BIO_WRITE)
574 || (beio->
bio_cmd == BIO_FLUSH)
575 || (beio->
bio_cmd == BIO_DELETE)
595 struct mount *mountpoint;
600 binuptime(&beio->
ds_t0);
603 (void) vn_start_write(be_lun->
vn, &mountpoint, V_WAIT);
605 vn_lock(be_lun->
vn, vn_lktype_write(mountpoint, be_lun->
vn) |
607 error = VOP_FSYNC(be_lun->
vn, beio->
io_arg ? MNT_NOWAIT : MNT_WAIT,
609 VOP_UNLOCK(be_lun->
vn);
611 vn_finished_write(mountpoint);
613 mtx_lock(&be_lun->io_lock);
617 mtx_unlock(&be_lun->io_lock);
644 struct iovec *xiovec;
658 bzero(&xuio,
sizeof(xuio));
659 if (beio->
bio_cmd == BIO_READ) {
660 SDT_PROBE0(cbb, , read, file_start);
661 xuio.uio_rw = UIO_READ;
663 SDT_PROBE0(cbb, , write, file_start);
664 xuio.uio_rw = UIO_WRITE;
667 xuio.uio_resid = beio->
io_len;
668 xuio.uio_segflg = UIO_SYSSPACE;
671 xuio.uio_td = curthread;
673 for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) {
678 binuptime(&beio->
ds_t0);
681 if (beio->
bio_cmd == BIO_READ) {
682 vn_lock(be_lun->
vn, LK_SHARED | LK_RETRY);
704 error = VOP_READ(be_lun->
vn, &xuio, flags, file_data->
cred);
706 VOP_UNLOCK(be_lun->
vn);
707 SDT_PROBE0(cbb, , read, file_done);
708 if (error == 0 && xuio.uio_resid > 0) {
713 s = beio->
io_len - xuio.uio_resid;
714 for (i = 0; i < beio->
num_segs; i++) {
725 struct mount *mountpoint;
727 (void)vn_start_write(be_lun->
vn, &mountpoint, V_WAIT);
728 vn_lock(be_lun->
vn, vn_lktype_write(mountpoint,
729 be_lun->
vn) | LK_RETRY);
746 error = VOP_WRITE(be_lun->
vn, &xuio, flags, file_data->
cred);
747 VOP_UNLOCK(be_lun->
vn);
749 vn_finished_write(mountpoint);
750 SDT_PROBE0(cbb, , write, file_done);
753 mtx_lock(&be_lun->io_lock);
757 mtx_unlock(&be_lun->io_lock);
764 if (error == ENOSPC || error == EDQUOT) {
766 }
else if (error == EROFS || error == EACCES) {
780 if ((beio->
bio_cmd == BIO_WRITE) ||
808 vn_lock(be_lun->
vn, LK_SHARED | LK_RETRY);
809 error = VOP_IOCTL(be_lun->
vn, FIOSEEKHOLE, &off,
810 0, curthread->td_ucred, curthread);
811 if (error == 0 && off > roff)
814 error = VOP_IOCTL(be_lun->
vn, FIOSEEKDATA, &off,
815 0, curthread->td_ucred, curthread);
816 if (error == 0 && off > roff)
823 VOP_UNLOCK(be_lun->
vn);
838 struct statfs statfs;
843 if (be_lun->
vn == NULL)
845 vn_lock(be_lun->
vn, LK_SHARED | LK_RETRY);
846 if (strcmp(attrname,
"blocksused") == 0) {
847 error = VOP_GETATTR(be_lun->
vn, &vattr, curthread->td_ucred);
851 if (strcmp(attrname,
"blocksavail") == 0 &&
852 !VN_IS_DOOMED(be_lun->
vn)) {
853 error = VFS_STATFS(be_lun->
vn->v_mount, &statfs);
855 val = statfs.f_bavail * statfs.f_bsize /
858 VOP_UNLOCK(be_lun->
vn);
879 binuptime(&beio->
ds_t0);
882 (void)vn_start_write(be_lun->
vn, &mp, V_WAIT);
883 vn_lock(be_lun->
vn, vn_lktype_write(mp, be_lun->
vn) | LK_RETRY);
889 end = buf + ptrlen->
len /
sizeof(*buf);
890 for (; buf < end; buf++) {
896 error = vn_deallocate(be_lun->
vn, &off, &
len,
897 0, IO_NOMACCHECK | IO_NODELOCKED, file_data->
cred,
906 error = vn_deallocate(be_lun->
vn, &off, &
len, 0,
907 IO_NOMACCHECK | IO_NODELOCKED, file_data->
cred, NOCRED);
909 VOP_UNLOCK(be_lun->
vn);
910 vn_finished_write(mp);
912 mtx_lock(&be_lun->io_lock);
916 mtx_unlock(&be_lun->io_lock);
949 struct iovec *xiovec;
950 int error, flags, i, ref;
961 bzero(&xuio,
sizeof(xuio));
962 if (beio->
bio_cmd == BIO_READ) {
963 SDT_PROBE0(cbb, , read, file_start);
964 xuio.uio_rw = UIO_READ;
966 SDT_PROBE0(cbb, , write, file_start);
967 xuio.uio_rw = UIO_WRITE;
970 xuio.uio_resid = beio->
io_len;
971 xuio.uio_segflg = UIO_SYSSPACE;
974 xuio.uio_td = curthread;
976 for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) {
981 binuptime(&beio->
ds_t0);
984 csw = devvn_refthread(be_lun->
vn, &dev, &ref);
986 if (beio->
bio_cmd == BIO_READ) {
990 error = csw->d_read(dev, &xuio, flags);
992 error = csw->d_write(dev, &xuio, flags);
993 dev_relthread(dev, ref);
998 SDT_PROBE0(cbb, , read, file_done);
1000 SDT_PROBE0(cbb, , write, file_done);
1002 mtx_lock(&be_lun->io_lock);
1005 NULL, &beio->
ds_t0);
1006 mtx_unlock(&be_lun->io_lock);
1013 if (error == ENOSPC || error == EDQUOT) {
1015 }
else if (error == EROFS || error == EACCES) {
1029 if ((beio->
bio_cmd == BIO_WRITE) ||
1054 int error, ref, status;
1058 csw = devvn_refthread(be_lun->
vn, &dev, &ref);
1065 error = csw->d_ioctl(dev, FIOSEEKHOLE, (caddr_t)&off, FREAD,
1067 if (error == 0 && off > roff)
1070 error = csw->d_ioctl(dev, FIOSEEKDATA, (caddr_t)&off, FREAD,
1072 if (error == 0 && off > roff)
1079 dev_relthread(dev, ref);
1103 bio = g_alloc_bio();
1105 bio->bio_cmd = BIO_FLUSH;
1106 bio->bio_offset = 0;
1109 bio->bio_caller1 = beio;
1110 bio->bio_pblkno = 0;
1120 binuptime(&beio->
ds_t0);
1123 csw = devvn_refthread(be_lun->
vn, &dev, &ref);
1126 csw->d_strategy(bio);
1127 dev_relthread(dev, ref);
1129 bio->bio_error = ENXIO;
1137 uint64_t off, uint64_t len,
int last)
1145 csw = devvn_refthread(be_lun->
vn, &dev, &ref);
1148 bio = g_alloc_bio();
1149 bio->bio_cmd = BIO_DELETE;
1151 bio->bio_offset = off;
1152 bio->bio_length = MIN(len, maxlen);
1155 bio->bio_caller1 = beio;
1158 off += bio->bio_length;
1159 len -= bio->bio_length;
1161 mtx_lock(&be_lun->io_lock);
1163 if (last && len == 0)
1165 mtx_unlock(&be_lun->io_lock);
1168 csw->d_strategy(bio);
1170 bio->bio_error = ENXIO;
1175 dev_relthread(dev, ref);
1191 binuptime(&beio->
ds_t0);
1198 end = buf + ptrlen->
len /
sizeof(*buf);
1199 for (; buf < end; buf++) {
1205 len, (end - buf < 2) ? TRUE : FALSE);
1216 TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue);
1221 int i, max_iosize, ref;
1224 csw = devvn_refthread(be_lun->
vn, &dev, &ref);
1231 max_iosize = dev->si_iosize_max;
1232 if (max_iosize <= 0)
1233 max_iosize = DFLTPHYS;
1235 max_iosize = maxphys;
1238 for (i = 0; i < beio->
num_segs; i++) {
1245 while (cur_size > 0) {
1247 bio = g_alloc_bio();
1249 KASSERT(bio != NULL, (
"g_alloc_bio() failed!\n"));
1253 bio->bio_caller1 = beio;
1254 bio->bio_length = min(cur_size, max_iosize);
1255 bio->bio_offset = cur_offset;
1256 bio->bio_data = cur_ptr;
1260 cur_offset += bio->bio_length;
1261 cur_ptr += bio->bio_length;
1262 cur_size -= bio->bio_length;
1264 TAILQ_INSERT_TAIL(&queue, bio, bio_queue);
1269 binuptime(&beio->
ds_t0);
1275 while ((bio = TAILQ_FIRST(&queue)) != NULL) {
1276 TAILQ_REMOVE(&queue, bio, bio_queue);
1278 csw->d_strategy(bio);
1280 bio->bio_error = ENXIO;
1285 dev_relthread(dev, ref);
1291 struct diocgattr_arg arg;
1296 csw = devvn_refthread(be_lun->
vn, &dev, &ref);
1298 return (UINT64_MAX);
1299 strlcpy(arg.name, attrname,
sizeof(arg.name));
1300 arg.len =
sizeof(arg.value.off);
1302 error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD,
1306 dev_relthread(dev, ref);
1308 return (UINT64_MAX);
1309 return (arg.value.off);
1358 uint64_t len_left,
lba;
1359 uint32_t pb, pbo, adj;
1387 be_lun->
unmap(be_lun, beio);
1394 DPRINTF(
"WRITE SAME at LBA %jx len %u\n",
1395 (uintmax_t)lbalen->
lba, lbalen->
len);
1403 for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) {
1419 DPRINTF(
"segment %d addr %p len %zd\n", i,
1427 for (; buf < end; buf += cbe_lun->
blocksize) {
1482 be_lun->
unmap(be_lun, beio);
1504 softc = be_lun->
softc;
1509 PRIV(io)->ptr = (
void *)beio;
1523 panic(
"Unhandled CDB type %#x", io->
scsiio.
cdb[0]);
1547 softc = be_lun->
softc;
1566 PRIV(io)->ptr = (
void *)beio;
1581 panic(
"Unhandled CDB type %#x", io->
scsiio.
cdb[0]);
1610 mtx_lock(&be_lun->queue_lock);
1611 STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->
io_hdr, links);
1612 mtx_unlock(&be_lun->queue_lock);
1613 taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task);
1625 uint64_t len_left, lbas;
1628 softc = be_lun->
softc;
1634 SDT_PROBE0(cbb, , write, start);
1636 SDT_PROBE0(cbb, , read, start);
1643 bptrlen->
ptr = (
void *)beio;
1668 DPRINTF(
"%s at LBA %jx len %u @%ju\n",
1669 (beio->
bio_cmd == BIO_READ) ?
"READ" :
"WRITE",
1670 (uintmax_t)lbalen->
lba, lbalen->
len, bptrlen->
len);
1679 bptrlen->
len += lbas;
1681 for (i = 0, len_left = beio->
io_len; len_left > 0; i++) {
1691 DPRINTF(
"segment %d addr %p len %zd\n", i,
1704 if (bptrlen->
len < lbalen->
len)
1723 if (beio->
bio_cmd == BIO_READ) {
1724 SDT_PROBE0(cbb, , read, alloc_done);
1727 SDT_PROBE0(cbb, , write, alloc_done);
1747 mtx_lock(&be_lun->queue_lock);
1748 io = (
union ctl_io *)STAILQ_FIRST(&be_lun->datamove_queue);
1751 STAILQ_REMOVE_HEAD(&be_lun->datamove_queue, links);
1752 mtx_unlock(&be_lun->queue_lock);
1762 io = (
union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue);
1764 DPRINTF(
"config write queue\n");
1765 STAILQ_REMOVE_HEAD(&be_lun->config_write_queue, links);
1766 mtx_unlock(&be_lun->queue_lock);
1775 io = (
union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue);
1777 DPRINTF(
"config read queue\n");
1778 STAILQ_REMOVE_HEAD(&be_lun->config_read_queue, links);
1779 mtx_unlock(&be_lun->queue_lock);
1788 io = (
union ctl_io *)STAILQ_FIRST(&be_lun->input_queue);
1791 STAILQ_REMOVE_HEAD(&be_lun->input_queue, links);
1792 mtx_unlock(&be_lun->queue_lock);
1806 mtx_unlock(&be_lun->queue_lock);
1826 (
"%s: unexpected I/O type %x", __func__, io->
io_hdr.
io_type));
1830 mtx_lock(&be_lun->queue_lock);
1831 STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->
io_hdr, links);
1832 mtx_unlock(&be_lun->queue_lock);
1833 taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task);
1840 int flag,
struct thread *td)
1865 "invalid LUN request type %d",
1887 off_t ps, pss, po, pos, us, uss, uo, uos;
1893 params = &be_lun->
params;
1901 cbe_lun->
flags &= ~CTL_LUN_FLAG_UNMAP;
1903 error = VOP_GETATTR(be_lun->
vn, &vattr, curthread->td_ucred);
1906 "error calling VOP_GETATTR() for file %s",
1911 error = VOP_PATHCONF(be_lun->
vn, _PC_DEALLOC_PRESENT, &pconf);
1914 "error calling VOP_PATHCONF() for file %s",
1921 file_data->
cred = crhold(curthread->td_ucred);
1943 us = ps = vattr.va_blocksize;
1946 value = dnvlist_get_string(cbe_lun->
options,
"pblocksize", NULL);
1949 value = dnvlist_get_string(cbe_lun->
options,
"pblockoffset", NULL);
1954 if ((pss > 0) && (pss * cbe_lun->
blocksize == ps) && (pss >= pos) &&
1955 ((pss & (pss - 1)) == 0) && (pos * cbe_lun->
blocksize == po)) {
1960 value = dnvlist_get_string(cbe_lun->
options,
"ublocksize", NULL);
1963 value = dnvlist_get_string(cbe_lun->
options,
"ublockoffset", NULL);
1968 if ((uss > 0) && (uss * cbe_lun->
blocksize == us) && (uss >= uos) &&
1969 ((uss & (uss - 1)) == 0) && (uos * cbe_lun->
blocksize == uo)) {
1981 "file %s size %ju < block size %u", be_lun->
dev_path,
1997 int error, atomic, maxio, ref, unmap, tmp;
1998 off_t ps, pss, po, pos, us, uss, uo, uos, otmp;
2000 params = &be_lun->
params;
2003 csw = devvn_refthread(be_lun->
vn, &dev, &ref);
2006 if (strcmp(csw->d_name,
"zvol") == 0) {
2014 maxio = dev->si_iosize_max;
2024 if (!csw->d_ioctl) {
2025 dev_relthread(dev, ref);
2027 "no d_ioctl for device %s!", be_lun->
dev_path);
2031 error = csw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD,
2034 dev_relthread(dev, ref);
2036 "error %d returned for DIOCGSECTORSIZE ioctl "
2037 "on %s!", error, be_lun->
dev_path);
2052 dev_relthread(dev, ref);
2054 "requested blocksize %u is not an even "
2055 "multiple of backing device blocksize %u",
2060 dev_relthread(dev, ref);
2062 "requested blocksize %u < backing device "
2070 error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD,
2073 dev_relthread(dev, ref);
2075 "error %d returned for DIOCGMEDIASIZE "
2076 " ioctl on %s!", error,
2083 dev_relthread(dev, ref);
2085 "requested LUN size %ju > backing device "
2099 error = csw->d_ioctl(dev, DIOCGSTRIPESIZE, (caddr_t)&ps, FREAD,
2104 error = csw->d_ioctl(dev, DIOCGSTRIPEOFFSET, (caddr_t)&po,
2112 value = dnvlist_get_string(cbe_lun->
options,
"pblocksize", NULL);
2115 value = dnvlist_get_string(cbe_lun->
options,
"pblockoffset", NULL);
2120 if ((pss > 0) && (pss * cbe_lun->
blocksize == ps) && (pss >= pos) &&
2121 ((pss & (pss - 1)) == 0) && (pos * cbe_lun->
blocksize == po)) {
2126 value = dnvlist_get_string(cbe_lun->
options,
"ublocksize", NULL);
2129 value = dnvlist_get_string(cbe_lun->
options,
"ublockoffset", NULL);
2134 if ((uss > 0) && (uss * cbe_lun->
blocksize == us) && (uss >= uos) &&
2135 ((uss & (uss - 1)) == 0) && (uos * cbe_lun->
blocksize == uo)) {
2146 struct diocgattr_arg arg;
2148 strlcpy(arg.name,
"GEOM::candelete",
sizeof(arg.name));
2149 arg.len =
sizeof(arg.value.i);
2150 error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD,
2152 unmap = (error == 0) ? arg.value.i : 0;
2154 value = dnvlist_get_string(cbe_lun->
options,
"unmap", NULL);
2156 unmap = (strcmp(value,
"on") == 0);
2160 cbe_lun->
flags &= ~CTL_LUN_FLAG_UNMAP;
2162 dev_relthread(dev, ref);
2176 (void)vn_close(be_lun->
vn,
flags, NOCRED, curthread);
2191 panic(
"Unexpected backend type %d", be_lun->
dev_type);
2203 struct nameidata nd;
2208 if (rootvnode == NULL) {
2210 "Root filesystem is not mounted");
2215 value = dnvlist_get_string(cbe_lun->
options,
"file", NULL);
2216 if (value == NULL) {
2218 "no file argument specified");
2222 be_lun->
dev_path = strdup(value, M_CTLBLK);
2225 value = dnvlist_get_string(cbe_lun->
options,
"readonly", NULL);
2226 if (value != NULL) {
2227 if (strcmp(value,
"on") != 0)
2233 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, be_lun->
dev_path);
2234 error = vn_open(&nd, &flags, 0, NULL);
2235 if ((error == EROFS || error == EACCES) && (flags & FWRITE)) {
2249 asprintf(&dev_name, M_CTLBLK,
"/dev/%s",
2256 "error opening %s: %d", be_lun->
dev_path, error);
2260 cbe_lun->
flags &= ~CTL_LUN_FLAG_READONLY;
2264 NDFREE(&nd, NDF_ONLY_PNBUF);
2265 be_lun->
vn = nd.ni_vp;
2268 if (vn_isdisk_error(be_lun->
vn, &error)) {
2270 }
else if (be_lun->
vn->v_type == VREG) {
2275 "%s is not a disk or plain file", be_lun->
dev_path);
2277 VOP_UNLOCK(be_lun->
vn);
2284 value = dnvlist_get_string(cbe_lun->
options,
"serseq", NULL);
2285 if (value != NULL && strcmp(value,
"on") == 0)
2287 else if (value != NULL && strcmp(value,
"read") == 0)
2289 else if (value != NULL && strcmp(value,
"soft") == 0)
2291 else if (value != NULL && strcmp(value,
"off") == 0)
2302 char num_thread_str[16];
2305 int retval, num_threads;
2306 int tmp_num_threads;
2312 be_lun = malloc(
sizeof(*be_lun), M_CTLBLK, M_ZERO | M_WAITOK);
2315 be_lun->
softc = softc;
2316 STAILQ_INIT(&be_lun->input_queue);
2317 STAILQ_INIT(&be_lun->config_read_queue);
2318 STAILQ_INIT(&be_lun->config_write_queue);
2319 STAILQ_INIT(&be_lun->datamove_queue);
2320 mtx_init(&be_lun->io_lock,
"ctlblock io", NULL, MTX_DEF);
2321 mtx_init(&be_lun->queue_lock,
"ctlblock queue", NULL, MTX_DEF);
2330 value = dnvlist_get_string(cbe_lun->
options,
"ha_role", NULL);
2331 if (value != NULL) {
2332 if (strcmp(value,
"primary") == 0)
2363 value = dnvlist_get_string(cbe_lun->
options,
"num_threads", NULL);
2364 if (value != NULL) {
2365 tmp_num_threads = strtol(value, NULL, 0);
2372 if (tmp_num_threads < 1) {
2374 "invalid number of threads %s",
2378 num_threads = tmp_num_threads;
2381 if (be_lun->
vn == NULL)
2396 snprintf(tmpstr,
sizeof(tmpstr),
"MYSERIAL%04d",
2399 MIN(
sizeof(cbe_lun->
serial_num),
sizeof(tmpstr)));
2403 MIN(
sizeof(params->
serial_num),
sizeof(tmpstr)));
2410 snprintf(tmpstr,
sizeof(tmpstr),
"MYDEVID%04d", softc->
num_luns);
2411 strncpy((
char *)cbe_lun->
device_id, tmpstr,
2412 MIN(
sizeof(cbe_lun->
device_id),
sizeof(tmpstr)));
2415 strncpy((
char *)params->
device_id, tmpstr,
2416 MIN(
sizeof(params->
device_id),
sizeof(tmpstr)));
2425 be_lun->io_taskqueue = taskqueue_create(
"ctlblocktq", M_WAITOK,
2426 taskqueue_thread_enqueue, &be_lun->io_taskqueue);
2428 if (be_lun->io_taskqueue == NULL) {
2430 "unable to create taskqueue");
2448 retval = taskqueue_start_threads_in_proc(&be_lun->io_taskqueue,
2457 be_lun->num_threads = num_threads;
2462 "ctl_add_lun() returned error %d, see dmesg for "
2470 DEVSTAT_ALL_SUPPORTED,
2472 | DEVSTAT_TYPE_IF_OTHER,
2473 DEVSTAT_PRIORITY_OTHER);
2475 mtx_lock(&softc->
lock);
2477 SLIST_INSERT_HEAD(&softc->lun_list, be_lun, links);
2478 mtx_unlock(&softc->
lock);
2487 if (be_lun->io_taskqueue != NULL)
2488 taskqueue_free(be_lun->io_taskqueue);
2492 nvlist_destroy(cbe_lun->
options);
2493 mtx_destroy(&be_lun->queue_lock);
2494 mtx_destroy(&be_lun->io_lock);
2495 free(be_lun, M_CTLBLK);
2511 mtx_lock(&softc->
lock);
2512 SLIST_FOREACH(be_lun, &softc->lun_list, links) {
2514 SLIST_REMOVE(&softc->lun_list, be_lun,
2520 mtx_unlock(&softc->
lock);
2522 if (be_lun == NULL) {
2524 "LUN %u is not managed by the block backend",
2530 if (be_lun->
vn != NULL) {
2533 taskqueue_drain_all(be_lun->io_taskqueue);
2537 mtx_lock(&softc->
lock);
2539 mtx_unlock(&softc->
lock);
2544 "error %d returned from ctl_remove_lun() for "
2545 "LUN %d", retval, params->
lun_id);
2546 mtx_lock(&softc->
lock);
2547 be_lun->
flags &= ~CTL_BE_BLOCK_LUN_WAITING;
2548 mtx_unlock(&softc->
lock);
2552 mtx_lock(&softc->
lock);
2554 retval = msleep(be_lun, &softc->
lock, PCATCH,
"ctlblockrm", 0);
2555 if (retval == EINTR)
2558 be_lun->
flags &= ~CTL_BE_BLOCK_LUN_WAITING;
2560 mtx_unlock(&softc->
lock);
2561 free(be_lun, M_CTLBLK);
2563 mtx_unlock(&softc->
lock);
2588 mtx_lock(&softc->
lock);
2589 SLIST_FOREACH(be_lun, &softc->lun_list, links) {
2593 mtx_unlock(&softc->
lock);
2594 if (be_lun == NULL) {
2596 "LUN %u is not managed by the block backend",
2606 nvlist_destroy(cbe_lun->
options);
2611 value = dnvlist_get_string(cbe_lun->
options,
"ha_role", NULL);
2612 if (value != NULL) {
2613 if (strcmp(value,
"primary") == 0)
2616 cbe_lun->
flags &= ~CTL_LUN_FLAG_PRIMARY;
2620 cbe_lun->
flags &= ~CTL_LUN_FLAG_PRIMARY;
2631 if (be_lun->
vn == NULL)
2633 else if (vn_isdisk_error(be_lun->
vn, &error))
2635 else if (be_lun->
vn->v_type == VREG) {
2636 vn_lock(be_lun->
vn, LK_SHARED | LK_RETRY);
2638 VOP_UNLOCK(be_lun->
vn);
2642 be_lun->
vn != NULL) {
2643 cbe_lun->
flags &= ~CTL_LUN_FLAG_NO_MEDIA;
2646 be_lun->
vn == NULL) {
2650 cbe_lun->
flags &= ~CTL_LUN_FLAG_EJECTED;
2652 if (be_lun->
vn != NULL) {
2655 taskqueue_drain_all(be_lun->io_taskqueue);
2682 taskqueue_drain_all(be_lun->io_taskqueue);
2683 taskqueue_free(be_lun->io_taskqueue);
2688 mtx_destroy(&be_lun->queue_lock);
2689 mtx_destroy(&be_lun->io_lock);
2691 mtx_lock(&softc->
lock);
2696 free(be_lun, M_CTLBLK);
2697 mtx_unlock(&softc->
lock);
2727 mtx_lock(&be_lun->queue_lock);
2728 STAILQ_INSERT_TAIL(&be_lun->config_write_queue, &io->
io_hdr,
2730 mtx_unlock(&be_lun->queue_lock);
2731 taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task);
2746 cbe_lun->
flags &= ~CTL_LUN_FLAG_EJECTED;
2748 cbe_lun->
flags &= ~CTL_LUN_FLAG_NO_MEDIA;
2762 if (be_lun->
vn != NULL)
2798 mtx_lock(&be_lun->queue_lock);
2799 STAILQ_INSERT_TAIL(&be_lun->config_read_queue,
2801 mtx_unlock(&be_lun->queue_lock);
2802 taskqueue_enqueue(be_lun->io_taskqueue,
2832 retval = sbuf_printf(sb,
"\t<num_threads>");
2835 retval = sbuf_printf(sb,
"%d", lun->num_threads);
2838 retval = sbuf_printf(sb,
"</num_threads>\n");
2850 return (UINT64_MAX);
2851 return (lun->
getattr(lun, attrname));
2860 mtx_init(&softc->
lock,
"ctlblock", NULL, MTX_DEF);
2861 softc->beio_zone = uma_zcreate(
"beio",
sizeof(
struct ctl_be_block_io),
2862 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
2864 NULL, NULL, NULL, NULL, 0, 0);
2867 NULL, NULL, NULL, NULL, 0, 0);
2868 SLIST_INIT(&softc->lun_list);
2879 while ((lun = SLIST_FIRST(&
softc->lun_list)) != NULL) {
2880 SLIST_REMOVE_HEAD(&
softc->lun_list, links);
2892 uma_zdestroy(
softc->bufmin_zone);
2894 uma_zdestroy(
softc->bufmax_zone);
2895 uma_zdestroy(
softc->beio_zone);
TAILQ_HEAD(ccb_hdr_tailq, ccb_hdr)
SLIST_HEAD(ccb_hdr_slist, ccb_hdr)
int ctl_add_lun(struct ctl_be_lun *be_lun)
int ctl_start_lun(struct ctl_be_lun *be_lun)
void ctl_serseq_done(union ctl_io *io)
int ctl_lun_no_media(struct ctl_be_lun *be_lun)
void ctl_datamove(union ctl_io *io)
int ctl_expand_number(const char *buf, uint64_t *num)
int ctl_lun_ejected(struct ctl_be_lun *be_lun)
int ctl_remove_lun(struct ctl_be_lun *be_lun)
int ctl_lun_has_media(struct ctl_be_lun *be_lun)
void ctl_config_write_done(union ctl_io *io)
int ctl_lun_primary(struct ctl_be_lun *be_lun)
int ctl_stop_lun(struct ctl_be_lun *be_lun)
int ctl_lun_secondary(struct ctl_be_lun *be_lun)
void ctl_lun_capacity_changed(struct ctl_be_lun *be_lun)
void ctl_config_read_done(union ctl_io *io)
void ctl_data_submit_done(union ctl_io *io)
#define CTL_RETVAL_COMPLETE
#define CTL_RETVAL_QUEUED
static void ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio)
static void ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, union ctl_io *io)
static size_t cmp(uint8_t *a, uint8_t *b, size_t size)
static int ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
static void ctl_be_block_cw_done_ws(struct ctl_be_block_io *beio)
MALLOC_DEFINE(M_CTLBLK, "ctlblock", "Memory used for CTL block backend")
SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, block, CTLFLAG_RD|CTLFLAG_MPSAFE, 0, "CAM Target Layer Block Backend")
static void ctl_real_free_beio(struct ctl_be_block_io *beio)
static int ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
SYSCTL_INT(_kern_cam_ctl_block, OID_AUTO, num_threads, CTLFLAG_RWTUN, &cbb_num_threads, 0, "Number of threads per backing file")
static struct ctl_be_block_softc backend_block_softc
static int ctl_be_block_move_done(union ctl_io *io, bool samethr)
static void ctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun, union ctl_io *io)
struct ctl_softc * control_softc
static void ctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio)
static int ctl_be_block_open(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
static void ctl_be_block_worker(void *context, int pending)
static int ctl_be_block_open_file(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
static void ctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio, uint64_t off, uint64_t len, int last)
static void ctl_be_block_cr_done(struct ctl_be_block_io *beio)
static struct ctl_backend_driver ctl_be_block_driver
static void ctl_be_block_dispatch_zvol(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 int ctl_be_block_config_write(union ctl_io *io)
static uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname)
static int ctl_be_block_shutdown(void)
static int ctl_be_block_lun_info(struct ctl_be_lun *cbe_lun, struct sbuf *sb)
static void ctl_be_block_compare(union ctl_io *io)
static int ctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
static uint64_t ctl_be_block_getattr_file(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_free_seg(struct ctl_be_block_softc *softc, struct ctl_sg_entry *sg)
SDT_PROBE_DEFINE1(cbb,, read, file_start, "uint64_t")
static int ctl_be_block_close(struct ctl_be_block_lun *be_lun)
static void ctl_free_beio(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 int ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
static int cbb_num_threads
static void ctl_refcnt_beio(void *arg, int diff)
static int ctl_be_block_config_read(union ctl_io *io)
void(* cbb_dispatch_t)(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio)
static void ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio)
CTL_BACKEND_DECLARE(cbb, ctl_be_block_driver)
static void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, union ctl_io *io)
static int ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
static void ctl_be_block_cw_dispatch_sync(struct ctl_be_block_lun *be_lun, union ctl_io *io)
static void ctl_be_block_lun_shutdown(struct ctl_be_lun *cbe_lun)
static void ctl_be_block_next(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_cw_dispatch_ws(struct ctl_be_block_lun *be_lun, union ctl_io *io)
static uint64_t ctl_be_block_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname)
static void ctl_be_block_unmap_file(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio)
static void ctl_be_block_cw_done(struct ctl_be_block_io *beio)
static struct ctl_be_block_io * ctl_alloc_beio(struct ctl_be_block_softc *softc)
#define CTLBLK_MAX_IO_SIZE
static void ctl_be_block_biodone(struct bio *bio)
static int ctl_be_block_submit(union ctl_io *io)
static void ctl_alloc_seg(struct ctl_be_block_softc *softc, struct ctl_sg_entry *sg, size_t len)
@ CTL_BE_BLOCK_LUN_WAITING
@ CTL_BE_BLOCK_LUN_UNCONFIGURED
static int ctl_be_block_init(void)
uint64_t(* cbb_getattr_t)(struct ctl_be_block_lun *be_lun, const char *attrname)
static void ctl_complete_beio(struct ctl_be_block_io *beio)
#define DPRINTF(fmt, args...)
static void ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, struct ctl_be_block_io *beio)
void ctl_set_hw_write_protected(struct ctl_scsiio *ctsio)
void ctl_set_space_alloc_fail(struct ctl_scsiio *ctsio)
void ctl_set_invalid_field(struct ctl_scsiio *ctsio, int sks_valid, int command, int field, int bit_valid, int bit)
void ctl_set_success(struct ctl_scsiio *ctsio)
void ctl_set_medium_error(struct ctl_scsiio *ctsio, int read)
void ctl_set_internal_failure(struct ctl_scsiio *ctsio, int sks_valid, uint16_t retry_count)
void ctl_set_invalid_opcode(struct ctl_scsiio *ctsio)
void ctl_set_busy(struct ctl_scsiio *ctsio)
void ctl_set_sense(struct ctl_scsiio *ctsio, int current_error, int sense_key, int asc, int ascq,...)
#define CTL_BACKEND_LUN(io)
@ CTL_LUN_FLAG_SERIAL_NUM
#define SYNCHRONIZE_CACHE_16
static __inline uint64_t scsi_8btou64(const uint8_t *bytes)
#define SSD_KEY_MISCOMPARE
#define SGLS_SERVICE_ACTION
#define SYNCHRONIZE_CACHE
static __inline uint32_t scsi_4btoul(const uint8_t *bytes)
static __inline void scsi_ulto4b(u_int32_t val, u_int8_t *bytes)
static __inline void scsi_u64to8b(u_int64_t val, u_int8_t *bytes)
#define SERVICE_ACTION_IN
char name[CTL_BE_NAME_LEN]
struct ctl_be_block_softc * softc
struct ctl_be_block_lun * lun
devstat_tag_type ds_tag_type
void(* beio_cont)(struct ctl_be_block_io *beio)
struct iovec xiovecs[CTLBLK_MAX_SEGS]
uint64_t first_error_offset
devstat_trans_flags ds_trans_type
struct ctl_sg_entry sg_segs[CTLBLK_MAX_SEGS]
struct ctl_be_block_softc * softc
struct ctl_be_lun cbe_lun
ctl_be_block_type dev_type
struct devstat * disk_stats
ctl_be_block_lun_flags flags
cbb_dispatch_t get_lba_status
struct ctl_lun_create_params params
union ctl_be_block_bedata backend
uint8_t device_id[CTL_DEVID_LEN]
uint8_t serial_num[CTL_SN_LEN]
be_callback_t lun_shutdown
struct ctl_backend_driver * be
ctl_backend_lun_flags flags
union ctl_priv ctl_private[CTL_NUM_PRIV]
ctl_backend_lun_flags flags
uint8_t serial_num[CTL_SN_LEN]
uint8_t device_id[CTL_DEVID_LEN]
char error_str[CTL_ERROR_STR_LEN]
union ctl_lunreq_data reqdata
int(* be_move_done)(union ctl_io *io, bool samethr)
uint8_t cdb[CTL_MAX_CDBLEN]
struct scsi_get_lba_status_data_descr descr[]
struct ctl_be_block_filedata file
struct ctl_lun_rm_params rm
struct ctl_lun_modify_params modify
struct ctl_lun_create_params create