aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nvme/target
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-12-16 13:09:32 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2020-12-16 13:09:32 -0800
commit69f637c33560b02ae7313e0c142d847361cc723a (patch)
tree6a99c455e5d72032758512383cbf39195b75b022 /drivers/nvme/target
parentMerge tag 'for-5.11/block-2020-12-14' of git://git.kernel.dk/linux-block (diff)
parentblock: drop dead assignments in loop_init() (diff)
downloadlinux-dev-69f637c33560b02ae7313e0c142d847361cc723a.tar.xz
linux-dev-69f637c33560b02ae7313e0c142d847361cc723a.zip
Merge tag 'for-5.11/drivers-2020-12-14' of git://git.kernel.dk/linux-block
Pull block driver updates from Jens Axboe: "Nothing major in here: - NVMe pull request from Christoph: - nvmet passthrough improvements (Chaitanya Kulkarni) - fcloop error injection support (James Smart) - read-only support for zoned namespaces without Zone Append (Javier González) - improve some error message (Minwoo Im) - reject I/O to offline fabrics namespaces (Victor Gladkov) - PCI queue allocation cleanups (Niklas Schnelle) - remove an unused allocation in nvmet (Amit Engel) - a Kconfig spelling fix (Colin Ian King) - nvme_req_qid simplication (Baolin Wang) - MD pull request from Song: - Fix race condition in md_ioctl() (Dae R. Jeong) - Initialize read_slot properly for raid10 (Kevin Vigor) - Code cleanup (Pankaj Gupta) - md-cluster resync/reshape fix (Zhao Heming) - Move null_blk into its own directory (Damien Le Moal) - null_blk zone and discard improvements (Damien Le Moal) - bcache race fix (Dongsheng Yang) - Set of rnbd fixes/improvements (Gioh Kim, Guoqing Jiang, Jack Wang, Lutz Pogrell, Md Haris Iqbal) - lightnvm NULL pointer deref fix (tangzhenhao) - sr in_interrupt() removal (Sebastian Andrzej Siewior) - FC endpoint security support for s390/dasd (Jan Höppner, Sebastian Ott, Vineeth Vijayan). From the s390 arch guys, arch bits included as it made it easier for them to funnel the feature through the block driver tree. - Follow up fixes (Colin Ian King)" * tag 'for-5.11/drivers-2020-12-14' of git://git.kernel.dk/linux-block: (64 commits) block: drop dead assignments in loop_init() sr: Remove in_interrupt() usage in sr_init_command(). sr: Switch the sector size back to 2048 if sr_read_sector() changed it. cdrom: Reset sector_size back it is not 2048. drivers/lightnvm: fix a null-ptr-deref bug in pblk-core.c null_blk: Move driver into its own directory null_blk: Allow controlling max_hw_sectors limit null_blk: discard zones on reset null_blk: cleanup discard handling null_blk: Improve implicit zone close null_blk: improve zone locking block: Align max_hw_sectors to logical blocksize null_blk: Fail zone append to conventional zones null_blk: Fix zone size initialization bcache: fix race between setting bdev state to none and new write request direct to backing block/rnbd: fix a null pointer dereference on dev->blk_symlink_name block/rnbd-clt: Dynamically alloc buffer for pathname & blk_symlink_name block/rnbd: call kobject_put in the failure path Documentation/ABI/rnbd-srv: add document for force_close block/rnbd-srv: close a mapped device from server side. ...
Diffstat (limited to 'drivers/nvme/target')
-rw-r--r--drivers/nvme/target/Kconfig2
-rw-r--r--drivers/nvme/target/configfs.c40
-rw-r--r--drivers/nvme/target/core.c15
-rw-r--r--drivers/nvme/target/discovery.c1
-rw-r--r--drivers/nvme/target/fcloop.c81
-rw-r--r--drivers/nvme/target/loop.c2
-rw-r--r--drivers/nvme/target/nvmet.h4
-rw-r--r--drivers/nvme/target/passthru.c37
8 files changed, 147 insertions, 35 deletions
diff --git a/drivers/nvme/target/Kconfig b/drivers/nvme/target/Kconfig
index 8056955e652c..4be2ececbc45 100644
--- a/drivers/nvme/target/Kconfig
+++ b/drivers/nvme/target/Kconfig
@@ -24,7 +24,7 @@ config NVME_TARGET_PASSTHRU
This enables target side NVMe passthru controller support for the
NVMe Over Fabrics protocol. It allows for hosts to manage and
directly access an actual NVMe controller residing on the target
- side, incuding executing Vendor Unique Commands.
+ side, including executing Vendor Unique Commands.
If unsure, say N.
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 37e1d7784e17..c61ffd767062 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -736,9 +736,49 @@ static ssize_t nvmet_passthru_enable_store(struct config_item *item,
}
CONFIGFS_ATTR(nvmet_passthru_, enable);
+static ssize_t nvmet_passthru_admin_timeout_show(struct config_item *item,
+ char *page)
+{
+ return sprintf(page, "%u\n", to_subsys(item->ci_parent)->admin_timeout);
+}
+
+static ssize_t nvmet_passthru_admin_timeout_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nvmet_subsys *subsys = to_subsys(item->ci_parent);
+ unsigned int timeout;
+
+ if (kstrtouint(page, 0, &timeout))
+ return -EINVAL;
+ subsys->admin_timeout = timeout;
+ return count;
+}
+CONFIGFS_ATTR(nvmet_passthru_, admin_timeout);
+
+static ssize_t nvmet_passthru_io_timeout_show(struct config_item *item,
+ char *page)
+{
+ return sprintf(page, "%u\n", to_subsys(item->ci_parent)->io_timeout);
+}
+
+static ssize_t nvmet_passthru_io_timeout_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nvmet_subsys *subsys = to_subsys(item->ci_parent);
+ unsigned int timeout;
+
+ if (kstrtouint(page, 0, &timeout))
+ return -EINVAL;
+ subsys->io_timeout = timeout;
+ return count;
+}
+CONFIGFS_ATTR(nvmet_passthru_, io_timeout);
+
static struct configfs_attribute *nvmet_passthru_attrs[] = {
&nvmet_passthru_attr_device_path,
&nvmet_passthru_attr_enable,
+ &nvmet_passthru_attr_admin_timeout,
+ &nvmet_passthru_attr_io_timeout,
NULL,
};
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 957b39a82431..8ce4d59cc9e7 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -757,8 +757,6 @@ void nvmet_cq_setup(struct nvmet_ctrl *ctrl, struct nvmet_cq *cq,
{
cq->qid = qid;
cq->size = size;
-
- ctrl->cqs[qid] = cq;
}
void nvmet_sq_setup(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq,
@@ -1344,20 +1342,14 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
if (!ctrl->changed_ns_list)
goto out_free_ctrl;
- ctrl->cqs = kcalloc(subsys->max_qid + 1,
- sizeof(struct nvmet_cq *),
- GFP_KERNEL);
- if (!ctrl->cqs)
- goto out_free_changed_ns_list;
-
ctrl->sqs = kcalloc(subsys->max_qid + 1,
sizeof(struct nvmet_sq *),
GFP_KERNEL);
if (!ctrl->sqs)
- goto out_free_cqs;
+ goto out_free_changed_ns_list;
if (subsys->cntlid_min > subsys->cntlid_max)
- goto out_free_cqs;
+ goto out_free_changed_ns_list;
ret = ida_simple_get(&cntlid_ida,
subsys->cntlid_min, subsys->cntlid_max,
@@ -1395,8 +1387,6 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
out_free_sqs:
kfree(ctrl->sqs);
-out_free_cqs:
- kfree(ctrl->cqs);
out_free_changed_ns_list:
kfree(ctrl->changed_ns_list);
out_free_ctrl:
@@ -1426,7 +1416,6 @@ static void nvmet_ctrl_free(struct kref *ref)
nvmet_async_events_free(ctrl);
kfree(ctrl->sqs);
- kfree(ctrl->cqs);
kfree(ctrl->changed_ns_list);
kfree(ctrl);
diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c
index f40c05c33c3a..682854e0e079 100644
--- a/drivers/nvme/target/discovery.c
+++ b/drivers/nvme/target/discovery.c
@@ -69,6 +69,7 @@ void nvmet_subsys_disc_changed(struct nvmet_subsys *subsys,
struct nvmet_port *port;
struct nvmet_subsys_link *s;
+ lockdep_assert_held(&nvmet_config_sem);
nvmet_genctr++;
list_for_each_entry(port, nvmet_ports, global_entry)
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index 3da067a8311e..733d9363900e 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -564,6 +564,50 @@ fcloop_call_host_done(struct nvmefc_fcp_req *fcpreq,
fcloop_tfcp_req_put(tfcp_req);
}
+static bool drop_fabric_opcode;
+#define DROP_OPCODE_MASK 0x00FF
+/* fabrics opcode will have a bit set above 1st byte */
+static int drop_opcode = -1;
+static int drop_instance;
+static int drop_amount;
+static int drop_current_cnt;
+
+/*
+ * Routine to parse io and determine if the io is to be dropped.
+ * Returns:
+ * 0 if io is not obstructed
+ * 1 if io was dropped
+ */
+static int check_for_drop(struct fcloop_fcpreq *tfcp_req)
+{
+ struct nvmefc_fcp_req *fcpreq = tfcp_req->fcpreq;
+ struct nvme_fc_cmd_iu *cmdiu = fcpreq->cmdaddr;
+ struct nvme_command *sqe = &cmdiu->sqe;
+
+ if (drop_opcode == -1)
+ return 0;
+
+ pr_info("%s: seq opcd x%02x fctype x%02x: drop F %s op x%02x "
+ "inst %d start %d amt %d\n",
+ __func__, sqe->common.opcode, sqe->fabrics.fctype,
+ drop_fabric_opcode ? "y" : "n",
+ drop_opcode, drop_current_cnt, drop_instance, drop_amount);
+
+ if ((drop_fabric_opcode &&
+ (sqe->common.opcode != nvme_fabrics_command ||
+ sqe->fabrics.fctype != drop_opcode)) ||
+ (!drop_fabric_opcode && sqe->common.opcode != drop_opcode))
+ return 0;
+
+ if (++drop_current_cnt >= drop_instance) {
+ if (drop_current_cnt >= drop_instance + drop_amount)
+ drop_opcode = -1;
+ return 1;
+ }
+
+ return 0;
+}
+
static void
fcloop_fcp_recv_work(struct work_struct *work)
{
@@ -590,10 +634,14 @@ fcloop_fcp_recv_work(struct work_struct *work)
if (unlikely(aborted))
ret = -ECANCELED;
- else
- ret = nvmet_fc_rcv_fcp_req(tfcp_req->tport->targetport,
+ else {
+ if (likely(!check_for_drop(tfcp_req)))
+ ret = nvmet_fc_rcv_fcp_req(tfcp_req->tport->targetport,
&tfcp_req->tgt_fcp_req,
fcpreq->cmdaddr, fcpreq->cmdlen);
+ else
+ pr_info("%s: dropped command ********\n", __func__);
+ }
if (ret)
fcloop_call_host_done(fcpreq, tfcp_req, ret);
@@ -1449,6 +1497,33 @@ fcloop_delete_target_port(struct device *dev, struct device_attribute *attr,
return ret ? ret : count;
}
+static ssize_t
+fcloop_set_cmd_drop(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int opcode, starting, amount;
+
+ if (sscanf(buf, "%x:%d:%d", &opcode, &starting, &amount) != 3)
+ return -EBADRQC;
+
+ drop_current_cnt = 0;
+ drop_fabric_opcode = (opcode & ~DROP_OPCODE_MASK) ? true : false;
+ drop_opcode = (opcode & DROP_OPCODE_MASK);
+ drop_instance = starting;
+ /* the check to drop routine uses instance + count to know when
+ * to end. Thus, if dropping 1 instance, count should be 0.
+ * so subtract 1 from the count.
+ */
+ drop_amount = amount - 1;
+
+ pr_info("%s: DROP: Starting at instance %d of%s opcode x%x drop +%d "
+ "instances\n",
+ __func__, drop_instance, drop_fabric_opcode ? " fabric" : "",
+ drop_opcode, drop_amount);
+
+ return count;
+}
+
static DEVICE_ATTR(add_local_port, 0200, NULL, fcloop_create_local_port);
static DEVICE_ATTR(del_local_port, 0200, NULL, fcloop_delete_local_port);
@@ -1456,6 +1531,7 @@ static DEVICE_ATTR(add_remote_port, 0200, NULL, fcloop_create_remote_port);
static DEVICE_ATTR(del_remote_port, 0200, NULL, fcloop_delete_remote_port);
static DEVICE_ATTR(add_target_port, 0200, NULL, fcloop_create_target_port);
static DEVICE_ATTR(del_target_port, 0200, NULL, fcloop_delete_target_port);
+static DEVICE_ATTR(set_cmd_drop, 0200, NULL, fcloop_set_cmd_drop);
static struct attribute *fcloop_dev_attrs[] = {
&dev_attr_add_local_port.attr,
@@ -1464,6 +1540,7 @@ static struct attribute *fcloop_dev_attrs[] = {
&dev_attr_del_remote_port.attr,
&dev_attr_add_target_port.attr,
&dev_attr_del_target_port.attr,
+ &dev_attr_set_cmd_drop.attr,
NULL
};
diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c
index 07806016c09d..cb6f86572b24 100644
--- a/drivers/nvme/target/loop.c
+++ b/drivers/nvme/target/loop.c
@@ -355,7 +355,7 @@ static int nvme_loop_configure_admin_queue(struct nvme_loop_ctrl *ctrl)
NVME_INLINE_SG_CNT * sizeof(struct scatterlist);
ctrl->admin_tag_set.driver_data = ctrl;
ctrl->admin_tag_set.nr_hw_queues = 1;
- ctrl->admin_tag_set.timeout = ADMIN_TIMEOUT;
+ ctrl->admin_tag_set.timeout = NVME_ADMIN_TIMEOUT;
ctrl->admin_tag_set.flags = BLK_MQ_F_NO_SCHED;
ctrl->queues[0].ctrl = ctrl;
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 559a15ccc322..592763732065 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -164,7 +164,6 @@ static inline struct nvmet_port *ana_groups_to_port(
struct nvmet_ctrl {
struct nvmet_subsys *subsys;
- struct nvmet_cq **cqs;
struct nvmet_sq **sqs;
bool cmd_seen;
@@ -249,6 +248,8 @@ struct nvmet_subsys {
struct nvme_ctrl *passthru_ctrl;
char *passthru_ctrl_path;
struct config_group passthru_group;
+ unsigned int admin_timeout;
+ unsigned int io_timeout;
#endif /* CONFIG_NVME_TARGET_PASSTHRU */
};
@@ -330,6 +331,7 @@ struct nvmet_req {
struct work_struct work;
} f;
struct {
+ struct bio inline_bio;
struct request *rq;
struct work_struct work;
bool use_workqueue;
diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c
index 8ee94f056898..b9776fc8f08f 100644
--- a/drivers/nvme/target/passthru.c
+++ b/drivers/nvme/target/passthru.c
@@ -188,35 +188,31 @@ static void nvmet_passthru_req_done(struct request *rq,
static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)
{
struct scatterlist *sg;
- int op_flags = 0;
struct bio *bio;
- int i, ret;
+ int i;
if (req->sg_cnt > BIO_MAX_PAGES)
return -EINVAL;
- if (req->cmd->common.opcode == nvme_cmd_flush)
- op_flags = REQ_FUA;
- else if (nvme_is_write(req->cmd))
- op_flags = REQ_SYNC | REQ_IDLE;
-
- bio = bio_alloc(GFP_KERNEL, req->sg_cnt);
- bio->bi_end_io = bio_put;
- bio->bi_opf = req_op(rq) | op_flags;
+ if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) {
+ bio = &req->p.inline_bio;
+ bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec));
+ } else {
+ bio = bio_alloc(GFP_KERNEL, min(req->sg_cnt, BIO_MAX_PAGES));
+ bio->bi_end_io = bio_put;
+ }
+ bio->bi_opf = req_op(rq);
for_each_sg(req->sg, sg, req->sg_cnt, i) {
if (bio_add_pc_page(rq->q, bio, sg_page(sg), sg->length,
sg->offset) < sg->length) {
- bio_put(bio);
+ if (bio != &req->p.inline_bio)
+ bio_put(bio);
return -EINVAL;
}
}
- ret = blk_rq_append_bio(rq, &bio);
- if (unlikely(ret)) {
- bio_put(bio);
- return ret;
- }
+ blk_rq_bio_prep(rq, bio, req->sg_cnt);
return 0;
}
@@ -227,6 +223,7 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
struct request_queue *q = ctrl->admin_q;
struct nvme_ns *ns = NULL;
struct request *rq = NULL;
+ unsigned int timeout;
u32 effects;
u16 status;
int ret;
@@ -242,14 +239,20 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
}
q = ns->queue;
+ timeout = req->sq->ctrl->subsys->io_timeout;
+ } else {
+ timeout = req->sq->ctrl->subsys->admin_timeout;
}
- rq = nvme_alloc_request(q, req->cmd, 0, NVME_QID_ANY);
+ rq = nvme_alloc_request(q, req->cmd, 0);
if (IS_ERR(rq)) {
status = NVME_SC_INTERNAL;
goto out_put_ns;
}
+ if (timeout)
+ rq->timeout = timeout;
+
if (req->sg_cnt) {
ret = nvmet_passthru_map_sg(req, rq);
if (unlikely(ret)) {