/** * blk_rq_map_user - map user data to a request, for REQ_TYPE_BLOCK_PC usage * @q: request queue where request should be inserted * @rq: request structure to fill * @map_data: pointer to the rq_map_data holding pages (if necessary) * @ubuf: the user buffer * @len: length of user data * @gfp_mask: memory allocation flags * * Description: * Data will be mapped directly for zero copy I/O, if possible. Otherwise * a kernel bounce buffer is used. * * A matching blk_rq_unmap_user() must be issued at the end of I/O, while * still in process context. * * Note: The mapped bio may need to be bounced through blk_queue_bounce() * before being submitted to the device, as pages mapped may be out of * reach. It's the callers responsibility to make sure this happens. The * original bio must be passed back in to blk_rq_unmap_user() for proper * unmapping. */ int blk_rq_map_user(struct request_queue *q, struct request *rq, struct rq_map_data *map_data, void __user *ubuf, unsigned long len, gfp_t gfp_mask) { unsigned long bytes_read = 0; struct bio *bio = NULL; int ret; if (len > (queue_max_hw_sectors(q) << 9)) return -EINVAL; if (!len) return -EINVAL; if (!ubuf && (!map_data || !map_data->null_mapped)) return -EINVAL; while (bytes_read != len) { unsigned long map_len, end, start; map_len = min_t(unsigned long, len - bytes_read, BIO_MAX_SIZE); end = ((unsigned long)ubuf + map_len + PAGE_SIZE - 1) >> PAGE_SHIFT; start = (unsigned long)ubuf >> PAGE_SHIFT; /* * A bad offset could cause us to require BIO_MAX_PAGES + 1 * pages. If this happens we just lower the requested * mapping len by a page so that we can fit */ if (end - start > BIO_MAX_PAGES) map_len -= PAGE_SIZE; ret = __blk_rq_map_user(q, rq, map_data, ubuf, map_len, gfp_mask); if (ret < 0) goto unmap_rq; if (!bio) bio = rq->bio; bytes_read += ret; ubuf += ret; if (map_data) map_data->offset += ret; } if (!bio_flagged(bio, BIO_USER_MAPPED)) rq->cmd_flags |= REQ_COPY_USER; rq->buffer = NULL; return 0; unmap_rq: blk_rq_unmap_user(bio); rq->bio = NULL; return ret; }
static int pscsi_add_device_to_list(struct se_device *dev, struct scsi_device *sd) { struct pscsi_dev_virt *pdv = PSCSI_DEV(dev); struct request_queue *q = sd->request_queue; pdv->pdv_sd = sd; if (!sd->queue_depth) { sd->queue_depth = PSCSI_DEFAULT_QUEUEDEPTH; pr_err("Set broken SCSI Device %d:%d:%llu" " queue_depth to %d\n", sd->channel, sd->id, sd->lun, sd->queue_depth); } dev->dev_attrib.hw_block_size = min_not_zero((int)sd->sector_size, 512); dev->dev_attrib.hw_max_sectors = min_not_zero(sd->host->max_sectors, queue_max_hw_sectors(q)); dev->dev_attrib.hw_queue_depth = sd->queue_depth; /* * Setup our standard INQUIRY info into se_dev->t10_wwn */ pscsi_set_inquiry_info(sd, &dev->t10_wwn); /* * Locate VPD WWN Information used for various purposes within * the Storage Engine. */ if (!pscsi_get_inquiry_vpd_serial(sd, &dev->t10_wwn)) { /* * If VPD Unit Serial returned GOOD status, try * VPD Device Identification page (0x83). */ pscsi_get_inquiry_vpd_device_ident(sd, &dev->t10_wwn); } /* * For TYPE_TAPE, attempt to determine blocksize with MODE_SENSE. */ if (sd->type == TYPE_TAPE) { pscsi_tape_read_blocksize(dev, sd); dev->dev_attrib.hw_block_size = sd->sector_size; } return 0; }
static int slave_configure(struct scsi_device *sdev) { struct us_data *us = host_to_us(sdev->host); /* Many devices have trouble transferring more than 32KB at a time, * while others have trouble with more than 64K. At this time we * are limiting both to 32K (64 sectores). */ if (us->fflags & (US_FL_MAX_SECTORS_64 | US_FL_MAX_SECTORS_MIN)) { unsigned int max_sectors = 64; if (us->fflags & US_FL_MAX_SECTORS_MIN) max_sectors = PAGE_CACHE_SIZE >> 9; if (queue_max_hw_sectors(sdev->request_queue) > max_sectors) blk_queue_max_hw_sectors(sdev->request_queue, max_sectors); } else if (sdev->type == TYPE_TAPE) {
static int nvme_nvm_get_l2p_tbl(struct nvm_dev *nvmdev, u64 slba, u32 nlb, nvm_l2p_update_fn *update_l2p, void *priv) { struct nvme_ns *ns = nvmdev->q->queuedata; struct nvme_nvm_command c = {}; u32 len = queue_max_hw_sectors(ns->ctrl->admin_q) << 9; u32 nlb_pr_rq = len / sizeof(u64); u64 cmd_slba = slba; void *entries; int ret = 0; c.l2p.opcode = nvme_nvm_admin_get_l2p_tbl; c.l2p.nsid = cpu_to_le32(ns->ns_id); entries = kmalloc(len, GFP_KERNEL); if (!entries) return -ENOMEM; while (nlb) { u32 cmd_nlb = min(nlb_pr_rq, nlb); c.l2p.slba = cpu_to_le64(cmd_slba); c.l2p.nlb = cpu_to_le32(cmd_nlb); ret = nvme_submit_sync_cmd(ns->ctrl->admin_q, (struct nvme_command *)&c, entries, len); if (ret) { dev_err(ns->ctrl->device, "L2P table transfer failed (%d)\n", ret); ret = -EIO; goto out; } if (update_l2p(cmd_slba, cmd_nlb, entries, priv)) { ret = -EINTR; goto out; } cmd_slba += cmd_nlb; nlb -= cmd_nlb; } out: kfree(entries); return ret; }
/** * blk_rq_map_kern - map kernel data to a request, for REQ_TYPE_BLOCK_PC usage * @q: request queue where request should be inserted * @rq: request to fill * @kbuf: the kernel buffer * @len: length of user data * @gfp_mask: memory allocation flags * * Description: * Data will be mapped directly if possible. Otherwise a bounce * buffer is used. Can be called multple times to append multple * buffers. */ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, unsigned int len, gfp_t gfp_mask) { int reading = rq_data_dir(rq) == READ; unsigned long addr = (unsigned long) kbuf; int do_copy = 0; struct bio *bio; int ret; if (len > (queue_max_hw_sectors(q) << 9)) return -EINVAL; if (!len || !kbuf) return -EINVAL; do_copy = !blk_rq_aligned(q, addr, len) || object_is_on_stack(kbuf); if (do_copy) bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading); else bio = bio_map_kern(q, kbuf, len, gfp_mask); if (IS_ERR(bio)) return PTR_ERR(bio); if (!reading) bio->bi_rw |= REQ_WRITE; if (do_copy) rq->cmd_flags |= REQ_COPY_USER; ret = blk_rq_append_bio(q, rq, bio); if (unlikely(ret)) { /* request is too big */ bio_put(bio); return ret; } blk_queue_bounce(q, &rq->bio); rq->buffer = NULL; return 0; }
static int stackbd_start(char dev_path[]) { unsigned max_sectors; if (!(stackbd.bdev_raw = stackbd_bdev_open(dev_path))) return -EFAULT; /* Set up our internal device */ stackbd.capacity = get_capacity(stackbd.bdev_raw->bd_disk); printk("stackbd: Device real capacity: %llu\n", (unsigned long long) stackbd.capacity); set_capacity(stackbd.gd, stackbd.capacity); max_sectors = queue_max_hw_sectors(bdev_get_queue(stackbd.bdev_raw)); blk_queue_max_hw_sectors(stackbd.queue, max_sectors); printk("stackbd: Max sectors: %u\n", max_sectors); stackbd.thread = kthread_create(stackbd_threadfn, NULL, stackbd.gd->disk_name); if (IS_ERR(stackbd.thread)) { printk("stackbd: error kthread_create <%lu>\n", PTR_ERR(stackbd.thread)); goto error_after_bdev; } printk("stackbd: done initializing successfully\n"); stackbd.is_active = 1; wake_up_process(stackbd.thread); return 0; error_after_bdev: blkdev_put(stackbd.bdev_raw, STACKBD_BDEV_MODE); bdput(stackbd.bdev_raw); return -EFAULT; }
static int sg_io(struct request_queue *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr, fmode_t mode) { unsigned long start_time; int writing = 0, ret = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; struct bio *bio; if (hdr->interface_id != 'S') return -EINVAL; if (hdr->cmd_len > BLK_MAX_CDB) return -EINVAL; if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9)) return -EIO; if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: return -EINVAL; case SG_DXFER_TO_DEV: writing = 1; break; case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: break; } rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (!rq) return -ENOMEM; if (blk_fill_sghdr_rq(q, rq, hdr, mode)) { blk_put_request(rq); return -EFAULT; } if (hdr->iovec_count) { const int size = sizeof(struct sg_iovec) * hdr->iovec_count; size_t iov_data_len; struct sg_iovec *sg_iov; struct iovec *iov; int i; sg_iov = kmalloc(size, GFP_KERNEL); if (!sg_iov) { ret = -ENOMEM; goto out; } if (copy_from_user(sg_iov, hdr->dxferp, size)) { kfree(sg_iov); ret = -EFAULT; goto out; } /* * Sum up the vecs, making sure they don't overflow */ iov = (struct iovec *) sg_iov; iov_data_len = 0; for (i = 0; i < hdr->iovec_count; i++) { if (iov_data_len + iov[i].iov_len < iov_data_len) { kfree(sg_iov); ret = -EINVAL; goto out; } iov_data_len += iov[i].iov_len; } /* SG_IO howto says that the shorter of the two wins */ if (hdr->dxfer_len < iov_data_len) { hdr->iovec_count = iov_shorten(iov, hdr->iovec_count, hdr->dxfer_len); iov_data_len = hdr->dxfer_len; } ret = blk_rq_map_user_iov(q, rq, NULL, sg_iov, hdr->iovec_count, iov_data_len, GFP_KERNEL); kfree(sg_iov); } else if (hdr->dxfer_len) ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, GFP_KERNEL); if (ret) goto out; bio = rq->bio; memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; rq->retries = 0; start_time = jiffies; /* ignore return value. All information is passed back to caller * (if he doesn't check that is his problem). * N.B. a non-zero SCSI status is _not_ necessarily an error. */ blk_execute_rq(q, bd_disk, rq, 0); hdr->duration = jiffies_to_msecs(jiffies - start_time); return blk_complete_sghdr_rq(rq, hdr, bio); out: blk_put_request(rq); return ret; }
static int sg_io(struct request_queue *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr, fmode_t mode) { unsigned long start_time; ssize_t ret = 0; int writing = 0; int at_head = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; struct bio *bio; if (hdr->interface_id != 'S') return -EINVAL; if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9)) return -EIO; if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: return -EINVAL; case SG_DXFER_TO_DEV: writing = 1; break; case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: break; } if (hdr->flags & SG_FLAG_Q_AT_HEAD) at_head = 1; ret = -ENOMEM; rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (IS_ERR(rq)) return PTR_ERR(rq); blk_rq_set_block_pc(rq); if (hdr->cmd_len > BLK_MAX_CDB) { rq->cmd = kzalloc(hdr->cmd_len, GFP_KERNEL); if (!rq->cmd) goto out_put_request; } ret = blk_fill_sghdr_rq(q, rq, hdr, mode); if (ret < 0) goto out_free_cdb; ret = 0; if (hdr->iovec_count) { struct iov_iter i; struct iovec *iov = NULL; ret = import_iovec(rq_data_dir(rq), hdr->dxferp, hdr->iovec_count, 0, &iov, &i); if (ret < 0) goto out_free_cdb; /* SG_IO howto says that the shorter of the two wins */ iov_iter_truncate(&i, hdr->dxfer_len); ret = blk_rq_map_user_iov(q, rq, NULL, &i, GFP_KERNEL); kfree(iov); } else if (hdr->dxfer_len) ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, GFP_KERNEL); if (ret) goto out_free_cdb; bio = rq->bio; memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; rq->retries = 0; start_time = jiffies; /* ignore return value. All information is passed back to caller * (if he doesn't check that is his problem). * N.B. a non-zero SCSI status is _not_ necessarily an error. */ blk_execute_rq(q, bd_disk, rq, at_head); hdr->duration = jiffies_to_msecs(jiffies - start_time); ret = blk_complete_sghdr_rq(rq, hdr, bio); out_free_cdb: if (rq->cmd != rq->__cmd) kfree(rq->cmd); out_put_request: blk_put_request(rq); return ret; }
/* fd_create_virtdevice(): (Part of se_subsystem_api_t template) * * */ static struct se_device *fd_create_virtdevice( struct se_hba *hba, struct se_subsystem_dev *se_dev, void *p) { char *dev_p = NULL; struct se_device *dev; struct se_dev_limits dev_limits; struct queue_limits *limits; struct fd_dev *fd_dev = p; struct fd_host *fd_host = hba->hba_ptr; mm_segment_t old_fs; struct file *file; struct inode *inode = NULL; int dev_flags = 0, flags, ret = -EINVAL; memset(&dev_limits, 0, sizeof(struct se_dev_limits)); old_fs = get_fs(); set_fs(get_ds()); dev_p = getname(fd_dev->fd_dev_name); set_fs(old_fs); if (IS_ERR(dev_p)) { pr_err("getname(%s) failed: %lu\n", fd_dev->fd_dev_name, IS_ERR(dev_p)); ret = PTR_ERR(dev_p); goto fail; } /* * Use O_DSYNC by default instead of O_SYNC to forgo syncing * of pure timestamp updates. */ flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC; /* * Optionally allow fd_buffered_io=1 to be enabled for people * who want use the fs buffer cache as an WriteCache mechanism. * * This means that in event of a hard failure, there is a risk * of silent data-loss if the SCSI client has *not* performed a * forced unit access (FUA) write, or issued SYNCHRONIZE_CACHE * to write-out the entire device cache. */ if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) { pr_debug("FILEIO: Disabling O_DSYNC, using buffered FILEIO\n"); flags &= ~O_DSYNC; } file = filp_open(dev_p, flags, 0600); if (IS_ERR(file)) { pr_err("filp_open(%s) failed\n", dev_p); ret = PTR_ERR(file); goto fail; } if (!file || !file->f_dentry) { pr_err("filp_open(%s) failed\n", dev_p); goto fail; } fd_dev->fd_file = file; /* * If using a block backend with this struct file, we extract * fd_dev->fd_[block,dev]_size from struct block_device. * * Otherwise, we use the passed fd_size= from configfs */ inode = file->f_mapping->host; if (S_ISBLK(inode->i_mode)) { struct request_queue *q; unsigned long long dev_size; /* * Setup the local scope queue_limits from struct request_queue->limits * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. */ q = bdev_get_queue(inode->i_bdev); limits = &dev_limits.limits; limits->logical_block_size = bdev_logical_block_size(inode->i_bdev); limits->max_hw_sectors = queue_max_hw_sectors(q); limits->max_sectors = queue_max_sectors(q); /* * Determine the number of bytes from i_size_read() minus * one (1) logical sector from underlying struct block_device */ fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev); dev_size = (i_size_read(file->f_mapping->host) - fd_dev->fd_block_size); pr_debug("FILEIO: Using size: %llu bytes from struct" " block_device blocks: %llu logical_block_size: %d\n", dev_size, div_u64(dev_size, fd_dev->fd_block_size), fd_dev->fd_block_size); } else { if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) { pr_err("FILEIO: Missing fd_dev_size=" " parameter, and no backing struct" " block_device\n"); goto fail; } limits = &dev_limits.limits; limits->logical_block_size = FD_BLOCKSIZE; limits->max_hw_sectors = FD_MAX_SECTORS; limits->max_sectors = FD_MAX_SECTORS; fd_dev->fd_block_size = FD_BLOCKSIZE; } dev_limits.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH; dev_limits.queue_depth = FD_DEVICE_QUEUE_DEPTH; dev = transport_add_device_to_core_hba(hba, &fileio_template, se_dev, dev_flags, fd_dev, &dev_limits, "FILEIO", FD_VERSION); if (!dev) goto fail; if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) { pr_debug("FILEIO: Forcing setting of emulate_write_cache=1" " with FDBD_HAS_BUFFERED_IO_WCE\n"); dev->se_sub_dev->se_dev_attrib.emulate_write_cache = 1; } fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; fd_dev->fd_queue_depth = dev->queue_depth; pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s," " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id, fd_dev->fd_dev_name, fd_dev->fd_dev_size); putname(dev_p); return dev; fail: if (fd_dev->fd_file) { filp_close(fd_dev->fd_file, NULL); fd_dev->fd_file = NULL; } putname(dev_p); return ERR_PTR(ret); }
/* fd_create_virtdevice(): (Part of se_subsystem_api_t template) * * */ static struct se_device *fd_create_virtdevice( struct se_hba *hba, struct se_subsystem_dev *se_dev, void *p) { char *dev_p = NULL; struct se_device *dev; struct se_dev_limits dev_limits; struct queue_limits *limits; struct fd_dev *fd_dev = p; struct fd_host *fd_host = hba->hba_ptr; mm_segment_t old_fs; struct file *file; struct inode *inode = NULL; int dev_flags = 0, flags, ret = -EINVAL; memset(&dev_limits, 0, sizeof(struct se_dev_limits)); old_fs = get_fs(); set_fs(get_ds()); dev_p = getname(fd_dev->fd_dev_name); set_fs(old_fs); if (IS_ERR(dev_p)) { pr_err("getname(%s) failed: %lu\n", fd_dev->fd_dev_name, IS_ERR(dev_p)); ret = PTR_ERR(dev_p); goto fail; } /* * Use O_DSYNC by default instead of O_SYNC to forgo syncing * of pure timestamp updates. */ flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC; file = filp_open(dev_p, flags, 0600); if (IS_ERR(file)) { pr_err("filp_open(%s) failed\n", dev_p); ret = PTR_ERR(file); goto fail; } if (!file || !file->f_dentry) { pr_err("filp_open(%s) failed\n", dev_p); goto fail; } fd_dev->fd_file = file; /* * If using a block backend with this struct file, we extract * fd_dev->fd_[block,dev]_size from struct block_device. * * Otherwise, we use the passed fd_size= from configfs */ inode = file->f_mapping->host; if (S_ISBLK(inode->i_mode)) { struct request_queue *q; unsigned long long dev_size; /* * Setup the local scope queue_limits from struct request_queue->limits * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. */ q = bdev_get_queue(inode->i_bdev); limits = &dev_limits.limits; limits->logical_block_size = bdev_logical_block_size(inode->i_bdev); limits->max_hw_sectors = queue_max_hw_sectors(q); limits->max_sectors = queue_max_sectors(q); /* * Determine the number of bytes from i_size_read() minus * one (1) logical sector from underlying struct block_device */ fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev); dev_size = (i_size_read(file->f_mapping->host) - fd_dev->fd_block_size); pr_debug("FILEIO: Using size: %llu bytes from struct" " block_device blocks: %llu logical_block_size: %d\n", dev_size, div_u64(dev_size, fd_dev->fd_block_size), fd_dev->fd_block_size); } else { if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) { pr_err("FILEIO: Missing fd_dev_size=" " parameter, and no backing struct" " block_device\n"); goto fail; } limits = &dev_limits.limits; limits->logical_block_size = FD_BLOCKSIZE; limits->max_hw_sectors = FD_MAX_SECTORS; limits->max_sectors = FD_MAX_SECTORS; fd_dev->fd_block_size = FD_BLOCKSIZE; } dev_limits.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH; dev_limits.queue_depth = FD_DEVICE_QUEUE_DEPTH; dev = transport_add_device_to_core_hba(hba, &fileio_template, se_dev, dev_flags, fd_dev, &dev_limits, "FILEIO", FD_VERSION); if (!dev) goto fail; fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; fd_dev->fd_queue_depth = dev->queue_depth; pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s," " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id, fd_dev->fd_dev_name, fd_dev->fd_dev_size); putname(dev_p); return dev; fail: if (fd_dev->fd_file) { filp_close(fd_dev->fd_file, NULL); fd_dev->fd_file = NULL; } putname(dev_p); return ERR_PTR(ret); }
int ssd_register(char *path) { struct ssd_info *ssd; int ret = -1; mutex_lock(&gctx.ctl_mtx); do { ssd = _alloc_ssd(path); if (!ssd) { ERR("iostash: Could not allocate ssd_info struct.\n"); break; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) ssd->bdev = blkdev_get_by_path(path, FMODE_READ | FMODE_WRITE | FMODE_EXCL, &gctx.ssdtbl); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) ssd->bdev = open_bdev_exclusive(path, FMODE_READ | FMODE_WRITE | FMODE_EXCL, &gctx.ssdtbl); #else ERR("Kernel version < 2.6.28 currently not supported.\n"); ssd->bdev = ERR_PTR(-ENOENT); #endif if (IS_ERR(ssd->bdev)) { ERR("iostash: SSD device lookup failed.\n"); ssd->bdev = NULL; break; } rmb(); if (1 < ssd->bdev->bd_openers) { ERR("iostash: the SSD device is in use, cannot open it exclusively.\n"); break; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ssd->nr_sctr = get_capacity(ssd->bdev->bd_disk); #elif LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) ssd->nr_sctr = ssd->bdev->bd_part->nr_sects; #else ssd->nr_sctr = part_nr_sects_read(ssd->bdev->bd_part); #endif if (ssd->nr_sctr < IOSTASH_HEADERSCT) { ERR("SSD capacity less than minimum size of %uB", IOSTASH_HEADERSIZE); break; } ssd->nr_sctr -= IOSTASH_HEADERSCT; DBG("iostash: ssd->nr_sctr = %ld\n", (long)ssd->nr_sctr); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) ssd->queue_max_hw_sectors = queue_max_hw_sectors(bdev_get_queue(ssd->bdev)); #else /* 2.6.29 and 2.6.30 */ ssd->queue_max_hw_sectors = (bdev_get_queue(ssd->bdev))->max_hw_sectors; #endif ssd->cdev = sce_addcdev(gctx.sce, ssd->nr_sctr, ssd); if (ssd->cdev == NULL) { ERR("iostash: sce_add_device() failed.\n"); break; } ret = _ssd_create_kobj(ssd); if (ret) { ERR("ssd_create_kobj failed with %d.\n", ret); break; } /* insert it to our ssd hash table, it is ready to service requests */ _insert_ssd(ssd); ssd->online = 1; gctx.nr_ssd++; DBG("iostash: SSD %s has been added successfully.\n", path); ret = 0; } while (0); if (ret) _destroy_ssd(ssd); mutex_unlock(&gctx.ctl_mtx); return ret; }
static int iblock_configure_device(struct se_device *dev) { struct iblock_dev *ib_dev = IBLOCK_DEV(dev); struct request_queue *q; struct block_device *bd = NULL; fmode_t mode; int ret = -ENOMEM; if (!(ib_dev->ibd_flags & IBDF_HAS_UDEV_PATH)) { pr_err("Missing udev_path= parameters for IBLOCK\n"); return -EINVAL; } ib_dev->ibd_bio_set = bioset_create(IBLOCK_BIO_POOL_SIZE, 0); if (!ib_dev->ibd_bio_set) { pr_err("IBLOCK: Unable to create bioset\n"); goto out; } pr_debug( "IBLOCK: Claiming struct block_device: %s\n", ib_dev->ibd_udev_path); mode = FMODE_READ|FMODE_EXCL; if (!ib_dev->ibd_readonly) mode |= FMODE_WRITE; bd = blkdev_get_by_path(ib_dev->ibd_udev_path, mode, ib_dev); if (IS_ERR(bd)) { ret = PTR_ERR(bd); goto out_free_bioset; } ib_dev->ibd_bd = bd; q = bdev_get_queue(bd); dev->dev_attrib.hw_block_size = bdev_logical_block_size(bd); dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q); dev->dev_attrib.hw_queue_depth = q->nr_requests; /* * Check if the underlying struct block_device request_queue supports * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM * in ATA and we need to set TPE=1 */ if (blk_queue_discard(q)) { dev->dev_attrib.max_unmap_lba_count = q->limits.max_discard_sectors; /* * Currently hardcoded to 1 in Linux/SCSI code.. */ dev->dev_attrib.max_unmap_block_desc_count = 1; dev->dev_attrib.unmap_granularity = q->limits.discard_granularity >> 9; dev->dev_attrib.unmap_granularity_alignment = q->limits.discard_alignment; pr_debug("IBLOCK: BLOCK Discard support available," " disabled by default\n"); } /* * Enable write same emulation for IBLOCK and use 0xFFFF as * the smaller WRITE_SAME(10) only has a two-byte block count. */ dev->dev_attrib.max_write_same_len = 0xFFFF; if (blk_queue_nonrot(q)) dev->dev_attrib.is_nonrot = 1; return 0; out_free_bioset: bioset_free(ib_dev->ibd_bio_set); ib_dev->ibd_bio_set = NULL; out: return ret; }
static int sg_io(struct request_queue *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr, fmode_t mode) { unsigned long start_time; ssize_t ret = 0; int writing = 0; int at_head = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; struct bio *bio; if (hdr->interface_id != 'S') return -EINVAL; if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9)) return -EIO; if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: return -EINVAL; case SG_DXFER_TO_DEV: writing = 1; break; case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: break; } if (hdr->flags & SG_FLAG_Q_AT_HEAD) at_head = 1; ret = -ENOMEM; rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (IS_ERR(rq)) return PTR_ERR(rq); blk_rq_set_block_pc(rq); if (hdr->cmd_len > BLK_MAX_CDB) { rq->cmd = kzalloc(hdr->cmd_len, GFP_KERNEL); if (!rq->cmd) goto out_put_request; } ret = -EFAULT; if (blk_fill_sghdr_rq(q, rq, hdr, mode)) goto out_free_cdb; ret = 0; if (hdr->iovec_count) { struct iov_iter i; struct iovec *iov = NULL; ret = rw_copy_check_uvector(-1, hdr->dxferp, hdr->iovec_count, 0, NULL, &iov); if (ret < 0) { kfree(iov); goto out_free_cdb; } /* SG_IO howto says that the shorter of the two wins */ iov_iter_init(&i, rq_data_dir(rq), iov, hdr->iovec_count, min_t(unsigned, ret, hdr->dxfer_len)); ret = blk_rq_map_user_iov(q, rq, NULL, &i, GFP_KERNEL); kfree(iov); } else if (hdr->dxfer_len)
static int sg_io(struct request_queue *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr, fmode_t mode) { unsigned long start_time; int writing = 0, ret = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; struct bio *bio; if (hdr->interface_id != 'S') return -EINVAL; if (hdr->cmd_len > BLK_MAX_CDB) return -EINVAL; if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9)) return -EIO; if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: return -EINVAL; case SG_DXFER_TO_DEV: writing = 1; break; case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: break; } rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (!rq) return -ENOMEM; if (blk_fill_sghdr_rq(q, rq, hdr, mode)) { blk_put_request(rq); return -EFAULT; } if (hdr->iovec_count) { const int size = sizeof(struct sg_iovec) * hdr->iovec_count; size_t iov_data_len; struct sg_iovec *sg_iov; struct iovec *iov; int i; sg_iov = kmalloc(size, GFP_KERNEL); if (!sg_iov) { ret = -ENOMEM; goto out; } if (copy_from_user(sg_iov, hdr->dxferp, size)) { kfree(sg_iov); ret = -EFAULT; goto out; } iov = (struct iovec *) sg_iov; iov_data_len = 0; for (i = 0; i < hdr->iovec_count; i++) { if (iov_data_len + iov[i].iov_len < iov_data_len) { kfree(sg_iov); ret = -EINVAL; goto out; } iov_data_len += iov[i].iov_len; } if (hdr->dxfer_len < iov_data_len) { hdr->iovec_count = iov_shorten(iov, hdr->iovec_count, hdr->dxfer_len); iov_data_len = hdr->dxfer_len; } ret = blk_rq_map_user_iov(q, rq, NULL, sg_iov, hdr->iovec_count, iov_data_len, GFP_KERNEL); kfree(sg_iov); } else if (hdr->dxfer_len) ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, GFP_KERNEL); if (ret) goto out; bio = rq->bio; memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; rq->retries = 0; start_time = jiffies; blk_execute_rq(q, bd_disk, rq, 0); hdr->duration = jiffies_to_msecs(jiffies - start_time); return blk_complete_sghdr_rq(rq, hdr, bio); out: blk_put_request(rq); return ret; }