From owner-svn-src-all@FreeBSD.ORG Thu May 8 07:10:39 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 3F77AD6B; Thu, 8 May 2014 07:10:39 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 2183F828; Thu, 8 May 2014 07:10:39 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s487AdFO053545; Thu, 8 May 2014 07:10:39 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s487Acrw053540; Thu, 8 May 2014 07:10:38 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201405080710.s487Acrw053540@svn.freebsd.org> From: Alexander Motin Date: Thu, 8 May 2014 07:10:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r265642 - stable/10/sys/cam/ctl X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 08 May 2014 07:10:39 -0000 Author: mav Date: Thu May 8 07:10:38 2014 New Revision: 265642 URL: http://svnweb.freebsd.org/changeset/base/265642 Log: MFC r264886: Remove limits on size of READ/WRITE operations. Instead of allocating up to 16MB or RAM at once to handle whole I/O, allocate up to 1MB at a time, but do multiple ctl_datamove() and storage I/Os if needed. Modified: stable/10/sys/cam/ctl/ctl.c stable/10/sys/cam/ctl/ctl_backend_block.c stable/10/sys/cam/ctl/ctl_backend_ramdisk.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/cam/ctl/ctl.c ============================================================================== --- stable/10/sys/cam/ctl/ctl.c Thu May 8 07:08:47 2014 (r265641) +++ stable/10/sys/cam/ctl/ctl.c Thu May 8 07:10:38 2014 (r265642) @@ -9534,7 +9534,7 @@ ctl_inquiry_evpd_block_limits(struct ctl bl_ptr->page_code = SVPD_BLOCK_LIMITS; scsi_ulto2b(sizeof(*bl_ptr), bl_ptr->page_length); - scsi_ulto4b((16 * 1024 * 1024) / bs, bl_ptr->max_txfer_len); + scsi_ulto4b(0xffffffff, bl_ptr->max_txfer_len); scsi_ulto4b(MAXPHYS / bs, bl_ptr->opt_txfer_len); if (lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) { scsi_ulto4b(0xffffffff, bl_ptr->max_unmap_lba_cnt); Modified: stable/10/sys/cam/ctl/ctl_backend_block.c ============================================================================== --- stable/10/sys/cam/ctl/ctl_backend_block.c Thu May 8 07:08:47 2014 (r265641) +++ stable/10/sys/cam/ctl/ctl_backend_block.c Thu May 8 07:10:38 2014 (r265642) @@ -91,11 +91,12 @@ __FBSDID("$FreeBSD$"); #include /* - * The idea here is that we'll allocate enough S/G space to hold a 16MB - * I/O. If we get an I/O larger than that, we'll reject it. + * 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. */ -#define CTLBLK_MAX_IO_SIZE (16 * 1024 * 1024) -#define CTLBLK_MAX_SEGS (CTLBLK_MAX_IO_SIZE / MAXPHYS) + 1 +#define CTLBLK_MAX_IO_SIZE (1024 * 1024) +#define CTLBLK_MAX_SEG MAXPHYS +#define CTLBLK_MAX_SEGS MAX(CTLBLK_MAX_IO_SIZE / CTLBLK_MAX_SEG, 1) #ifdef CTLBLK_DEBUG #define DPRINTF(fmt, args...) \ @@ -500,14 +501,6 @@ ctl_be_block_biodone(struct bio *bio) ctl_set_success(&io->scsiio); ctl_complete_beio(beio); } else { - io->scsiio.be_move_done = ctl_be_block_move_done; - io->scsiio.kern_data_ptr = (uint8_t *)beio->sg_segs; - io->scsiio.kern_data_len = beio->io_len; - io->scsiio.kern_total_len = beio->io_len; - io->scsiio.kern_rel_offset = 0; - io->scsiio.kern_data_resid = 0; - io->scsiio.kern_sg_entries = beio->num_segs; - io->io_hdr.flags |= CTL_FLAG_ALLOCATED | CTL_FLAG_KDPTR_SGLIST; #ifdef CTL_TIME_IO getbintime(&io->io_hdr.dma_start_bt); #endif @@ -707,14 +700,6 @@ ctl_be_block_dispatch_file(struct ctl_be ctl_complete_beio(beio); } else { SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); - io->scsiio.be_move_done = ctl_be_block_move_done; - io->scsiio.kern_data_ptr = (uint8_t *)beio->sg_segs; - io->scsiio.kern_data_len = beio->io_len; - io->scsiio.kern_total_len = beio->io_len; - io->scsiio.kern_rel_offset = 0; - io->scsiio.kern_data_resid = 0; - io->scsiio.kern_sg_entries = beio->num_segs; - io->io_hdr.flags |= CTL_FLAG_ALLOCATED | CTL_FLAG_KDPTR_SGLIST; #ifdef CTL_TIME_IO getbintime(&io->io_hdr.dma_start_bt); #endif @@ -1014,7 +999,7 @@ ctl_be_block_cw_dispatch_ws(struct ctl_b /* * Setup the S/G entry for this chunk. */ - seglen = MIN(MAXPHYS, len_left); + seglen = MIN(CTLBLK_MAX_SEG, len_left); seglen -= seglen % be_lun->blocksize; beio->sg_segs[i].len = seglen; beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); @@ -1167,13 +1152,44 @@ SDT_PROBE_DEFINE1(cbb, kernel, read, all SDT_PROBE_DEFINE1(cbb, kernel, write, alloc_done, "uint64_t"); static void +ctl_be_block_next(struct ctl_be_block_io *beio) +{ + struct ctl_be_block_lun *be_lun; + union ctl_io *io; + + io = beio->io; + be_lun = beio->lun; + ctl_free_beio(beio); + if (((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE) + && ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { + ctl_done(io); + return; + } + + io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; + io->io_hdr.status &= ~CTL_STATUS_MASK; + io->io_hdr.status |= CTL_STATUS_NONE; + + mtx_lock(&be_lun->lock); + /* + * XXX KDM make sure that links is okay to use at this point. + * Otherwise, we either need to add another field to ctl_io_hdr, + * or deal with resource allocation here. + */ + STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); + mtx_unlock(&be_lun->lock); + + taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); +} + +static void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, union ctl_io *io) { struct ctl_be_block_io *beio; struct ctl_be_block_softc *softc; struct ctl_lba_len lbalen; - uint64_t len_left, io_size_bytes; + uint64_t len_left, lbaoff; int i; softc = be_lun->softc; @@ -1186,29 +1202,6 @@ ctl_be_block_dispatch(struct ctl_be_bloc SDT_PROBE(cbb, kernel, write, start, 0, 0, 0, 0, 0); } - memcpy(&lbalen, io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN].bytes, - sizeof(lbalen)); - - io_size_bytes = lbalen.len * be_lun->blocksize; - - /* - * XXX KDM this is temporary, until we implement chaining of beio - * structures and multiple datamove calls to move all the data in - * or out. - */ - if (io_size_bytes > CTLBLK_MAX_IO_SIZE) { - printf("%s: IO length %ju > max io size %u\n", __func__, - io_size_bytes, CTLBLK_MAX_IO_SIZE); - ctl_set_invalid_field(&io->scsiio, - /*sks_valid*/ 0, - /*command*/ 1, - /*field*/ 0, - /*bit_valid*/ 0, - /*bit*/ 0); - ctl_done(io); - return; - } - beio = ctl_alloc_beio(softc); beio->io = io; beio->lun = be_lun; @@ -1255,20 +1248,25 @@ ctl_be_block_dispatch(struct ctl_be_bloc beio->ds_trans_type = DEVSTAT_WRITE; } - beio->io_len = lbalen.len * be_lun->blocksize; - beio->io_offset = lbalen.lba * be_lun->blocksize; - - DPRINTF("%s at LBA %jx len %u\n", + memcpy(&lbalen, io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN].bytes, + sizeof(lbalen)); + DPRINTF("%s at LBA %jx len %u @%ju\n", (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", - (uintmax_t)lbalen.lba, lbalen.len); - - for (i = 0, len_left = io_size_bytes; i < CTLBLK_MAX_SEGS && - len_left > 0; i++) { + (uintmax_t)lbalen.lba, lbalen.len, lbaoff); + lbaoff = io->scsiio.kern_rel_offset / be_lun->blocksize; + beio->io_offset = (lbalen.lba + lbaoff) * be_lun->blocksize; + beio->io_len = MIN((lbalen.len - lbaoff) * be_lun->blocksize, + CTLBLK_MAX_IO_SIZE); + beio->io_len -= beio->io_len % be_lun->blocksize; + + for (i = 0, len_left = beio->io_len; len_left > 0; i++) { + KASSERT(i < CTLBLK_MAX_SEGS, ("Too many segs (%d >= %d)", + i, CTLBLK_MAX_SEGS)); /* * Setup the S/G entry for this chunk. */ - beio->sg_segs[i].len = min(MAXPHYS, len_left); + beio->sg_segs[i].len = min(CTLBLK_MAX_SEG, len_left); beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); DPRINTF("segment %d addr %p len %zd\n", i, @@ -1277,6 +1275,15 @@ ctl_be_block_dispatch(struct ctl_be_bloc beio->num_segs++; len_left -= beio->sg_segs[i].len; } + if (io->scsiio.kern_rel_offset + beio->io_len < + io->scsiio.kern_total_len) + beio->beio_cont = ctl_be_block_next; + io->scsiio.be_move_done = ctl_be_block_move_done; + io->scsiio.kern_data_ptr = (uint8_t *)beio->sg_segs; + io->scsiio.kern_data_len = beio->io_len; + io->scsiio.kern_data_resid = 0; + io->scsiio.kern_sg_entries = beio->num_segs; + io->io_hdr.flags |= CTL_FLAG_ALLOCATED | CTL_FLAG_KDPTR_SGLIST; /* * For the read case, we need to read the data into our buffers and @@ -1288,14 +1295,6 @@ ctl_be_block_dispatch(struct ctl_be_bloc be_lun->dispatch(be_lun, beio); } else { SDT_PROBE(cbb, kernel, write, alloc_done, 0, 0, 0, 0, 0); - io->scsiio.be_move_done = ctl_be_block_move_done; - io->scsiio.kern_data_ptr = (uint8_t *)beio->sg_segs; - io->scsiio.kern_data_len = beio->io_len; - io->scsiio.kern_total_len = beio->io_len; - io->scsiio.kern_rel_offset = 0; - io->scsiio.kern_data_resid = 0; - io->scsiio.kern_sg_entries = beio->num_segs; - io->io_hdr.flags |= CTL_FLAG_ALLOCATED | CTL_FLAG_KDPTR_SGLIST; #ifdef CTL_TIME_IO getbintime(&io->io_hdr.dma_start_bt); #endif @@ -1386,6 +1385,7 @@ ctl_be_block_worker(void *context, int p static int ctl_be_block_submit(union ctl_io *io) { + struct ctl_lba_len lbalen; struct ctl_be_block_lun *be_lun; struct ctl_be_lun *ctl_be_lun; int retval; @@ -1404,6 +1404,11 @@ ctl_be_block_submit(union ctl_io *io) KASSERT(io->io_hdr.io_type == CTL_IO_SCSI, ("Non-SCSI I/O (type " "%#x) encountered", io->io_hdr.io_type)); + memcpy(&lbalen, io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN].bytes, + sizeof(lbalen)); + io->scsiio.kern_total_len = lbalen.len * be_lun->blocksize; + io->scsiio.kern_rel_offset = 0; + mtx_lock(&be_lun->lock); /* * XXX KDM make sure that links is okay to use at this point. @@ -1840,7 +1845,7 @@ ctl_be_block_create(struct ctl_be_block_ sprintf(be_lun->lunname, "cblk%d", softc->num_luns); mtx_init(&be_lun->lock, be_lun->lunname, NULL, MTX_DEF); - be_lun->lun_zone = uma_zcreate(be_lun->lunname, MAXPHYS, + be_lun->lun_zone = uma_zcreate(be_lun->lunname, CTLBLK_MAX_SEG, NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); if (be_lun->lun_zone == NULL) { Modified: stable/10/sys/cam/ctl/ctl_backend_ramdisk.c ============================================================================== --- stable/10/sys/cam/ctl/ctl_backend_ramdisk.c Thu May 8 07:08:47 2014 (r265641) +++ stable/10/sys/cam/ctl/ctl_backend_ramdisk.c Thu May 8 07:10:38 2014 (r265642) @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -73,12 +74,17 @@ typedef enum { } ctl_be_ramdisk_lun_flags; struct ctl_be_ramdisk_lun { + char lunname[32]; uint64_t size_bytes; uint64_t size_blocks; struct ctl_be_ramdisk_softc *softc; ctl_be_ramdisk_lun_flags flags; STAILQ_ENTRY(ctl_be_ramdisk_lun) links; struct ctl_be_lun ctl_be_lun; + struct taskqueue *io_taskqueue; + struct task io_task; + STAILQ_HEAD(, ctl_io_hdr) cont_queue; + struct mtx lock; }; struct ctl_be_ramdisk_softc { @@ -100,6 +106,7 @@ int ctl_backend_ramdisk_init(void); void ctl_backend_ramdisk_shutdown(void); static int ctl_backend_ramdisk_move_done(union ctl_io *io); static int ctl_backend_ramdisk_submit(union ctl_io *io); +static void ctl_backend_ramdisk_continue(union ctl_io *io); static int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td); static int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, @@ -108,6 +115,7 @@ static int ctl_backend_ramdisk_create(st struct ctl_lun_req *req, int do_wait); static int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, struct ctl_lun_req *req); +static void ctl_backend_ramdisk_worker(void *context, int pending); static void ctl_backend_ramdisk_lun_shutdown(void *be_lun); static void ctl_backend_ramdisk_lun_config_status(void *be_lun, ctl_lun_config_status status); @@ -145,7 +153,7 @@ ctl_backend_ramdisk_init(void) mtx_init(&softc->lock, "ramdisk", NULL, MTX_DEF); STAILQ_INIT(&softc->lun_list); - softc->rd_size = 4 * 1024 * 1024; + softc->rd_size = 1024 * 1024; #ifdef CTL_RAMDISK_PAGES softc->num_pages = softc->rd_size / PAGE_SIZE; softc->ramdisk_pages = (uint8_t **)malloc(sizeof(uint8_t *) * @@ -211,16 +219,39 @@ ctl_backend_ramdisk_shutdown(void) static int ctl_backend_ramdisk_move_done(union ctl_io *io) { + struct ctl_be_lun *ctl_be_lun; + struct ctl_be_ramdisk_lun *be_lun; #ifdef CTL_TIME_IO struct bintime cur_bt; #endif CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n")); + ctl_be_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ + CTL_PRIV_BACKEND_LUN].ptr; + be_lun = (struct ctl_be_ramdisk_lun *)ctl_be_lun->be_lun; +#ifdef CTL_TIME_IO + getbintime(&cur_bt); + bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); + bintime_add(&io->io_hdr.dma_bt, &cur_bt); + io->io_hdr.num_dmas++; +#endif + if (io->scsiio.kern_sg_entries > 0) + free(io->scsiio.kern_data_ptr, M_RAMDISK); + io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; if ((io->io_hdr.port_status == 0) && ((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_STATUS_NONE)) { + if (io->scsiio.kern_rel_offset < io->scsiio.kern_total_len) { + mtx_lock(&be_lun->lock); + STAILQ_INSERT_TAIL(&be_lun->cont_queue, + &io->io_hdr, links); + mtx_unlock(&be_lun->lock); + taskqueue_enqueue(be_lun->io_taskqueue, + &be_lun->io_task); + return (0); + } io->io_hdr.status = CTL_SUCCESS; - else if ((io->io_hdr.port_status != 0) + } else if ((io->io_hdr.port_status != 0) && ((io->io_hdr.flags & CTL_FLAG_ABORT) == 0) && ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)){ /* @@ -236,15 +267,6 @@ ctl_backend_ramdisk_move_done(union ctl_ /*retry_count*/ io->io_hdr.port_status); } -#ifdef CTL_TIME_IO - getbintime(&cur_bt); - bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); - bintime_add(&io->io_hdr.dma_bt, &cur_bt); - io->io_hdr.num_dmas++; -#endif - - if (io->scsiio.kern_sg_entries > 0) - free(io->scsiio.kern_data_ptr, M_RAMDISK); ctl_done(io); return(0); } @@ -253,93 +275,100 @@ static int ctl_backend_ramdisk_submit(union ctl_io *io) { struct ctl_lba_len lbalen; -#ifdef CTL_RAMDISK_PAGES - struct ctl_sg_entry *sg_entries; - int len_filled; - int i; -#endif - int num_sg_entries, len; - struct ctl_be_ramdisk_softc *softc; struct ctl_be_lun *ctl_be_lun; - struct ctl_be_ramdisk_lun *be_lun; - softc = &rd_softc; - ctl_be_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ CTL_PRIV_BACKEND_LUN].ptr; - be_lun = (struct ctl_be_ramdisk_lun *)ctl_be_lun->be_lun; memcpy(&lbalen, io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN].bytes, sizeof(lbalen)); + io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; + io->scsiio.kern_total_len = lbalen.len * ctl_be_lun->blocksize; + io->scsiio.kern_rel_offset = 0; + io->scsiio.kern_data_resid = 0; + ctl_backend_ramdisk_continue(io); - len = lbalen.len * ctl_be_lun->blocksize; - - /* - * Kick out the request if it's bigger than we can handle. - */ - if (len > softc->rd_size) { - ctl_set_internal_failure(&io->scsiio, - /*sks_valid*/ 0, - /*retry_count*/ 0); - ctl_done(io); - return (CTL_RETVAL_COMPLETE); - } - - /* - * Kick out the request if it's larger than the device size that - * the user requested. - */ - if (((lbalen.lba * ctl_be_lun->blocksize) + len) > be_lun->size_bytes) { - ctl_set_lba_out_of_range(&io->scsiio); - ctl_done(io); - return (CTL_RETVAL_COMPLETE); - } + return (CTL_RETVAL_COMPLETE); +} +static void +ctl_backend_ramdisk_continue(union ctl_io *io) +{ + struct ctl_be_ramdisk_softc *softc; + int len, len_filled, sg_filled; #ifdef CTL_RAMDISK_PAGES - num_sg_entries = len >> PAGE_SHIFT; - if ((len & (PAGE_SIZE - 1)) != 0) - num_sg_entries++; + struct ctl_sg_entry *sg_entries; + int i; +#endif - if (num_sg_entries > 1) { + softc = &rd_softc; + len = io->scsiio.kern_total_len - io->scsiio.kern_rel_offset; +#ifdef CTL_RAMDISK_PAGES + sg_filled = min(btoc(len), softc->num_pages); + if (sg_filled > 1) { io->scsiio.kern_data_ptr = malloc(sizeof(struct ctl_sg_entry) * - num_sg_entries, M_RAMDISK, + sg_filled, M_RAMDISK, M_WAITOK); sg_entries = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; - for (i = 0, len_filled = 0; i < num_sg_entries; - i++, len_filled += PAGE_SIZE) { + for (i = 0, len_filled = 0; i < sg_filled; i++) { sg_entries[i].addr = softc->ramdisk_pages[i]; sg_entries[i].len = ctl_min(PAGE_SIZE, len - len_filled); + len_filled += sg_entries[i].len; } + io->io_hdr.flags |= CTL_FLAG_KDPTR_SGLIST; } else { -#endif /* CTL_RAMDISK_PAGES */ - /* - * If this is less than 1 page, don't bother allocating a - * scatter/gather list for it. This saves time/overhead. - */ - num_sg_entries = 0; -#ifdef CTL_RAMDISK_PAGES + sg_filled = 0; + len_filled = len; io->scsiio.kern_data_ptr = softc->ramdisk_pages[0]; -#else - io->scsiio.kern_data_ptr = softc->ramdisk_buffer; -#endif -#ifdef CTL_RAMDISK_PAGES } -#endif +#else + sg_filled = 0; + len_filled = min(len, softc->rd_size); + io->scsiio.kern_data_ptr = softc->ramdisk_buffer; +#endif /* CTL_RAMDISK_PAGES */ - io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; - io->scsiio.kern_data_len = len; - io->scsiio.kern_total_len = len; - io->scsiio.kern_rel_offset = 0; - io->scsiio.kern_data_resid = 0; - io->scsiio.kern_sg_entries = num_sg_entries; - io->io_hdr.flags |= CTL_FLAG_ALLOCATED | CTL_FLAG_KDPTR_SGLIST; + io->scsiio.kern_data_len = len_filled; + io->scsiio.kern_sg_entries = sg_filled; + io->io_hdr.flags |= CTL_FLAG_ALLOCATED; #ifdef CTL_TIME_IO getbintime(&io->io_hdr.dma_start_bt); #endif ctl_datamove(io); +} - return (CTL_RETVAL_COMPLETE); +static void +ctl_backend_ramdisk_worker(void *context, int pending) +{ + struct ctl_be_ramdisk_softc *softc; + struct ctl_be_ramdisk_lun *be_lun; + union ctl_io *io; + + be_lun = (struct ctl_be_ramdisk_lun *)context; + softc = be_lun->softc; + + mtx_lock(&be_lun->lock); + for (;;) { + io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue); + if (io != NULL) { + STAILQ_REMOVE(&be_lun->cont_queue, &io->io_hdr, + ctl_io_hdr, links); + + mtx_unlock(&be_lun->lock); + + ctl_backend_ramdisk_continue(io); + + mtx_lock(&be_lun->lock); + continue; + } + + /* + * If we get here, there is no work left in the queues, so + * just break out and let the task queue go to sleep. + */ + break; + } + mtx_unlock(&be_lun->lock); } static int @@ -470,8 +499,12 @@ ctl_backend_ramdisk_rm(struct ctl_be_ram mtx_unlock(&softc->lock); - if (retval == 0) + if (retval == 0) { + taskqueue_drain(be_lun->io_taskqueue, &be_lun->io_task); + taskqueue_free(be_lun->io_taskqueue); + mtx_destroy(&be_lun->lock); free(be_lun, M_RAMDISK); + } req->status = CTL_LUN_OK; @@ -509,6 +542,7 @@ ctl_backend_ramdisk_create(struct ctl_be sizeof(*be_lun)); goto bailout_error; } + sprintf(be_lun->lunname, "cram%d", softc->num_luns); STAILQ_INIT(&be_lun->ctl_be_lun.options); if (params->flags & CTL_LUN_FLAG_DEV_TYPE) @@ -611,6 +645,27 @@ ctl_backend_ramdisk_create(struct ctl_be sizeof(params->device_id))); } + STAILQ_INIT(&be_lun->cont_queue); + mtx_init(&be_lun->lock, "CTL ramdisk", NULL, MTX_DEF); + TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker, + be_lun); + + be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, + taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); + if (be_lun->io_taskqueue == NULL) { + snprintf(req->error_str, sizeof(req->error_str), + "%s: Unable to create taskqueue", __func__); + goto bailout_error; + } + + retval = taskqueue_start_threads(&be_lun->io_taskqueue, + /*num threads*/1, + /*priority*/PWAIT, + /*thread name*/ + "%s taskq", be_lun->lunname); + if (retval != 0) + goto bailout_error; + mtx_lock(&softc->lock); softc->num_luns++; STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); @@ -669,7 +724,13 @@ ctl_backend_ramdisk_create(struct ctl_be bailout_error: req->status = CTL_LUN_ERROR; - free(be_lun, M_RAMDISK); + if (be_lun != NULL) { + if (be_lun->io_taskqueue != NULL) { + taskqueue_free(be_lun->io_taskqueue); + } + mtx_destroy(&be_lun->lock); + free(be_lun, M_RAMDISK); + } return (retval); }