Changeset View
Changeset View
Standalone View
Standalone View
sys/cam/ctl/ctl_backend_block.c
Show First 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | |||||
#include <cam/ctl/ctl_error.h> | #include <cam/ctl/ctl_error.h> | ||||
/* | /* | ||||
* The idea here is that we'll allocate enough S/G space to hold a 1MB | * The idea here is that we'll allocate enough S/G space to hold a 1MB | ||||
* I/O. If we get an I/O larger than that, we'll split it. | * I/O. If we get an I/O larger than that, we'll split it. | ||||
*/ | */ | ||||
#define CTLBLK_HALF_IO_SIZE (512 * 1024) | #define CTLBLK_HALF_IO_SIZE (512 * 1024) | ||||
#define CTLBLK_MAX_IO_SIZE (CTLBLK_HALF_IO_SIZE * 2) | #define CTLBLK_MAX_IO_SIZE (CTLBLK_HALF_IO_SIZE * 2) | ||||
#define CTLBLK_MAX_SEG MIN(CTLBLK_HALF_IO_SIZE, MAXPHYS) | #define CTLBLK_MIN_SEG (128 * 1024) | ||||
#define CTLBLK_HALF_SEGS MAX(CTLBLK_HALF_IO_SIZE / CTLBLK_MAX_SEG, 1) | #define CTLBLK_MAX_SEG MIN(CTLBLK_HALF_IO_SIZE, maxphys) | ||||
#define CTLBLK_HALF_SEGS MAX(CTLBLK_HALF_IO_SIZE / CTLBLK_MIN_SEG, 1) | |||||
#define CTLBLK_MAX_SEGS (CTLBLK_HALF_SEGS * 2) | #define CTLBLK_MAX_SEGS (CTLBLK_HALF_SEGS * 2) | ||||
#define CTLBLK_NUM_SEGS (CTLBLK_MAX_IO_SIZE / CTLBLK_MAX_SEG) | |||||
#ifdef CTLBLK_DEBUG | #ifdef CTLBLK_DEBUG | ||||
#define DPRINTF(fmt, args...) \ | #define DPRINTF(fmt, args...) \ | ||||
printf("cbb(%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) | printf("cbb(%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) | ||||
#else | #else | ||||
#define DPRINTF(fmt, args...) do {} while(0) | #define DPRINTF(fmt, args...) do {} while(0) | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
* Overall softc structure for the block backend module. | * Overall softc structure for the block backend module. | ||||
*/ | */ | ||||
struct ctl_be_block_softc { | struct ctl_be_block_softc { | ||||
struct sx modify_lock; | struct sx modify_lock; | ||||
struct mtx lock; | struct mtx lock; | ||||
int num_luns; | int num_luns; | ||||
SLIST_HEAD(, ctl_be_block_lun) lun_list; | SLIST_HEAD(, ctl_be_block_lun) lun_list; | ||||
uma_zone_t beio_zone; | uma_zone_t beio_zone; | ||||
uma_zone_t buf_zone; | uma_zone_t bufmin_zone; | ||||
#if (CTLBLK_MAX_SEG > 131072) | uma_zone_t bufmax_zone; | ||||
uma_zone_t buf128_zone; | |||||
#endif | |||||
}; | }; | ||||
static struct ctl_be_block_softc backend_block_softc; | static struct ctl_be_block_softc backend_block_softc; | ||||
/* | /* | ||||
* Per-I/O information. | * Per-I/O information. | ||||
*/ | */ | ||||
struct ctl_be_block_io { | struct ctl_be_block_io { | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | |||||
MALLOC_DEFINE(M_CTLBLK, "ctlblock", "Memory used for CTL block backend"); | MALLOC_DEFINE(M_CTLBLK, "ctlblock", "Memory used for CTL block backend"); | ||||
CTL_BACKEND_DECLARE(cbb, ctl_be_block_driver); | CTL_BACKEND_DECLARE(cbb, ctl_be_block_driver); | ||||
static void | static void | ||||
ctl_alloc_seg(struct ctl_be_block_softc *softc, struct ctl_sg_entry *sg, | ctl_alloc_seg(struct ctl_be_block_softc *softc, struct ctl_sg_entry *sg, | ||||
size_t len) | size_t len) | ||||
{ | { | ||||
#if (CTLBLK_MAX_SEG > 131072) | if (len <= CTLBLK_MIN_SEG) { | ||||
if (len <= 131072) | sg->addr = uma_zalloc(softc->bufmin_zone, M_WAITOK); | ||||
sg->addr = uma_zalloc(softc->buf128_zone, M_WAITOK); | } else { | ||||
else | KASSERT(len <= CTLBLK_MAX_SEG, | ||||
#endif | ("Too large alloc %lu > %lu", len, CTLBLK_MAX_SEG)); | ||||
sg->addr = uma_zalloc(softc->buf_zone, M_WAITOK); | sg->addr = uma_zalloc(softc->bufmax_zone, M_WAITOK); | ||||
} | |||||
sg->len = len; | sg->len = len; | ||||
} | } | ||||
static void | static void | ||||
ctl_free_seg(struct ctl_be_block_softc *softc, struct ctl_sg_entry *sg) | ctl_free_seg(struct ctl_be_block_softc *softc, struct ctl_sg_entry *sg) | ||||
{ | { | ||||
#if (CTLBLK_MAX_SEG > 131072) | if (sg->len <= CTLBLK_MIN_SEG) { | ||||
if (sg->len <= 131072) | uma_zfree(softc->bufmin_zone, sg->addr); | ||||
uma_zfree(softc->buf128_zone, sg->addr); | } else { | ||||
else | KASSERT(sg->len <= CTLBLK_MAX_SEG, | ||||
#endif | ("Too large free %lu > %lu", sg->len, CTLBLK_MAX_SEG)); | ||||
uma_zfree(softc->buf_zone, sg->addr); | uma_zfree(softc->bufmax_zone, sg->addr); | ||||
} | } | ||||
} | |||||
static struct ctl_be_block_io * | static struct ctl_be_block_io * | ||||
ctl_alloc_beio(struct ctl_be_block_softc *softc) | ctl_alloc_beio(struct ctl_be_block_softc *softc) | ||||
{ | { | ||||
struct ctl_be_block_io *beio; | struct ctl_be_block_io *beio; | ||||
beio = uma_zalloc(softc->beio_zone, M_WAITOK | M_ZERO); | beio = uma_zalloc(softc->beio_zone, M_WAITOK | M_ZERO); | ||||
beio->softc = softc; | beio->softc = softc; | ||||
▲ Show 20 Lines • Show All 1,001 Lines • ▼ Show 20 Lines | DPRINTF("WRITE SAME at LBA %jx len %u\n", | ||||
(uintmax_t)lbalen->lba, lbalen->len); | (uintmax_t)lbalen->lba, lbalen->len); | ||||
pb = cbe_lun->blocksize << be_lun->cbe_lun.pblockexp; | pb = cbe_lun->blocksize << be_lun->cbe_lun.pblockexp; | ||||
if (be_lun->cbe_lun.pblockoff > 0) | if (be_lun->cbe_lun.pblockoff > 0) | ||||
pbo = pb - cbe_lun->blocksize * be_lun->cbe_lun.pblockoff; | pbo = pb - cbe_lun->blocksize * be_lun->cbe_lun.pblockoff; | ||||
else | else | ||||
pbo = 0; | pbo = 0; | ||||
len_left = (uint64_t)lbalen->len * cbe_lun->blocksize; | len_left = (uint64_t)lbalen->len * cbe_lun->blocksize; | ||||
for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) { | for (i = 0, lba = 0; i < CTLBLK_NUM_SEGS && len_left > 0; i++) { | ||||
/* | /* | ||||
* Setup the S/G entry for this chunk. | * Setup the S/G entry for this chunk. | ||||
*/ | */ | ||||
seglen = MIN(CTLBLK_MAX_SEG, len_left); | seglen = MIN(CTLBLK_MAX_SEG, len_left); | ||||
if (pb > cbe_lun->blocksize) { | if (pb > cbe_lun->blocksize) { | ||||
adj = ((lbalen->lba + lba) * cbe_lun->blocksize + | adj = ((lbalen->lba + lba) * cbe_lun->blocksize + | ||||
seglen - pbo) % pb; | seglen - pbo) % pb; | ||||
if (seglen > adj) | if (seglen > adj) | ||||
▲ Show 20 Lines • Show All 270 Lines • ▼ Show 20 Lines | ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, | ||||
for (i = 0, len_left = beio->io_len; len_left > 0; i++) { | for (i = 0, len_left = beio->io_len; len_left > 0; i++) { | ||||
KASSERT(i < CTLBLK_MAX_SEGS, ("Too many segs (%d >= %d)", | KASSERT(i < CTLBLK_MAX_SEGS, ("Too many segs (%d >= %d)", | ||||
i, CTLBLK_MAX_SEGS)); | i, CTLBLK_MAX_SEGS)); | ||||
/* | /* | ||||
* Setup the S/G entry for this chunk. | * Setup the S/G entry for this chunk. | ||||
*/ | */ | ||||
ctl_alloc_seg(softc, &beio->sg_segs[i], | ctl_alloc_seg(softc, &beio->sg_segs[i], | ||||
min(CTLBLK_MAX_SEG, len_left)); | MIN(CTLBLK_MAX_SEG, len_left)); | ||||
DPRINTF("segment %d addr %p len %zd\n", i, | DPRINTF("segment %d addr %p len %zd\n", i, | ||||
beio->sg_segs[i].addr, beio->sg_segs[i].len); | beio->sg_segs[i].addr, beio->sg_segs[i].len); | ||||
/* Set up second segment for compare operation. */ | /* Set up second segment for compare operation. */ | ||||
if (beio->two_sglists) { | if (beio->two_sglists) { | ||||
ctl_alloc_seg(softc, | ctl_alloc_seg(softc, | ||||
&beio->sg_segs[i + CTLBLK_HALF_SEGS], | &beio->sg_segs[i + CTLBLK_HALF_SEGS], | ||||
▲ Show 20 Lines • Show All 1,154 Lines • ▼ Show 20 Lines | |||||
ctl_be_block_init(void) | ctl_be_block_init(void) | ||||
{ | { | ||||
struct ctl_be_block_softc *softc = &backend_block_softc; | struct ctl_be_block_softc *softc = &backend_block_softc; | ||||
sx_init(&softc->modify_lock, "ctlblock modify"); | sx_init(&softc->modify_lock, "ctlblock modify"); | ||||
mtx_init(&softc->lock, "ctlblock", NULL, MTX_DEF); | mtx_init(&softc->lock, "ctlblock", NULL, MTX_DEF); | ||||
softc->beio_zone = uma_zcreate("beio", sizeof(struct ctl_be_block_io), | softc->beio_zone = uma_zcreate("beio", sizeof(struct ctl_be_block_io), | ||||
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); | NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); | ||||
softc->buf_zone = uma_zcreate("ctlblock", CTLBLK_MAX_SEG, | softc->bufmin_zone = uma_zcreate("ctlblockmin", CTLBLK_MIN_SEG, | ||||
NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); | NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); | ||||
#if (CTLBLK_MAX_SEG > 131072) | if (CTLBLK_MIN_SEG < CTLBLK_MAX_SEG) | ||||
softc->buf128_zone = uma_zcreate("ctlblock128", 131072, | softc->bufmax_zone = uma_zcreate("ctlblockmax", CTLBLK_MAX_SEG, | ||||
NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); | NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); | ||||
#endif | |||||
SLIST_INIT(&softc->lun_list); | SLIST_INIT(&softc->lun_list); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
ctl_be_block_shutdown(void) | ctl_be_block_shutdown(void) | ||||
{ | { | ||||
struct ctl_be_block_softc *softc = &backend_block_softc; | struct ctl_be_block_softc *softc = &backend_block_softc; | ||||
struct ctl_be_block_lun *lun; | struct ctl_be_block_lun *lun; | ||||
mtx_lock(&softc->lock); | mtx_lock(&softc->lock); | ||||
while ((lun = SLIST_FIRST(&softc->lun_list)) != NULL) { | while ((lun = SLIST_FIRST(&softc->lun_list)) != NULL) { | ||||
SLIST_REMOVE_HEAD(&softc->lun_list, links); | SLIST_REMOVE_HEAD(&softc->lun_list, links); | ||||
softc->num_luns--; | softc->num_luns--; | ||||
/* | /* | ||||
* Drop our lock here. Since ctl_remove_lun() can call | * Drop our lock here. Since ctl_remove_lun() can call | ||||
* back into us, this could potentially lead to a recursive | * back into us, this could potentially lead to a recursive | ||||
* lock of the same mutex, which would cause a hang. | * lock of the same mutex, which would cause a hang. | ||||
*/ | */ | ||||
mtx_unlock(&softc->lock); | mtx_unlock(&softc->lock); | ||||
ctl_remove_lun(&lun->cbe_lun); | ctl_remove_lun(&lun->cbe_lun); | ||||
mtx_lock(&softc->lock); | mtx_lock(&softc->lock); | ||||
} | } | ||||
mtx_unlock(&softc->lock); | mtx_unlock(&softc->lock); | ||||
uma_zdestroy(softc->buf_zone); | uma_zdestroy(softc->bufmin_zone); | ||||
#if (CTLBLK_MAX_SEG > 131072) | if (CTLBLK_MIN_SEG < CTLBLK_MAX_SEG) | ||||
uma_zdestroy(softc->buf128_zone); | uma_zdestroy(softc->bufmax_zone); | ||||
#endif | |||||
uma_zdestroy(softc->beio_zone); | uma_zdestroy(softc->beio_zone); | ||||
mtx_destroy(&softc->lock); | mtx_destroy(&softc->lock); | ||||
sx_destroy(&softc->modify_lock); | sx_destroy(&softc->modify_lock); | ||||
return (0); | return (0); | ||||
} | } |