From 78a6295c71cb276f8ab0bfc786f3543a4e756a8f Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Fri, 6 Apr 2018 11:31:41 -0700 Subject: scsi: target: prefer dbroot of /etc/target over /var/target The target database root directory, dbroot, has defaulted to /var/target for a while, but its main client, targetcli-fb, has been moving it to /etc/target for quite some time. With the plethora of target drivers now appearing, it has become more difficult to initialize this attribute before use by any child drivers. If the directory /etc/target exists, use that as the DB root. Otherwise, fall back to using /var/target. The ability to override this dbroot attribute still exists via sysfs. Signed-off-by: Lee Duncan Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/target/target_core_configfs.c | 25 +++++++++++++++++++++++++ drivers/target/target_core_internal.h | 1 + 2 files changed, 26 insertions(+) (limited to 'drivers/target') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 3f4bf126eed0..5ccef7d597fa 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -155,6 +155,8 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item, mutex_unlock(&g_tf_lock); + pr_debug("Target_Core_ConfigFS: db_root set to %s\n", db_root); + return read_bytes; } @@ -3213,6 +3215,27 @@ void target_setup_backend_cits(struct target_backend *tb) target_core_setup_dev_stat_cit(tb); } +static void target_init_dbroot(void) +{ + struct file *fp; + + snprintf(db_root_stage, DB_ROOT_LEN, DB_ROOT_PREFERRED); + fp = filp_open(db_root_stage, O_RDONLY, 0); + if (IS_ERR(fp)) { + pr_err("db_root: cannot open: %s\n", db_root_stage); + return; + } + if (!S_ISDIR(file_inode(fp)->i_mode)) { + filp_close(fp, NULL); + pr_err("db_root: not a valid directory: %s\n", db_root_stage); + return; + } + filp_close(fp, NULL); + + strncpy(db_root, db_root_stage, DB_ROOT_LEN); + pr_debug("Target_Core_ConfigFS: db_root set to %s\n", db_root); +} + static int __init target_core_init_configfs(void) { struct configfs_subsystem *subsys = &target_core_fabrics; @@ -3293,6 +3316,8 @@ static int __init target_core_init_configfs(void) if (ret < 0) goto out; + target_init_dbroot(); + return 0; out: diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 1d5afc3ae017..dead30b1d32c 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -166,6 +166,7 @@ extern struct se_portal_group xcopy_pt_tpg; /* target_core_configfs.c */ #define DB_ROOT_LEN 4096 #define DB_ROOT_DEFAULT "/var/target" +#define DB_ROOT_PREFERRED "/etc/target" extern char db_root[]; -- cgit v1.2.3 From 69589c9bb9c24499ace5158e236bed5906009efa Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Sun, 15 Apr 2018 00:25:57 +0530 Subject: scsi: target: Change return type to vm_fault_t Use new return type vm_fault_t for fault handler in struct vm_operations_struct. Signed-off-by: Souptick Joarder Reviewed-by: Matthew Wilcox Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 4ad89ea71a70..d6af29250d94 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1382,7 +1382,7 @@ static struct page *tcmu_try_get_block_page(struct tcmu_dev *udev, uint32_t dbi) return page; } -static int tcmu_vma_fault(struct vm_fault *vmf) +static vm_fault_t tcmu_vma_fault(struct vm_fault *vmf) { struct tcmu_dev *udev = vmf->vma->vm_private_data; struct uio_info *info = &udev->uio_info; -- cgit v1.2.3 From 1e74aff12dace677ab84e0ee0e7330e0ed5a9b86 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 14 Apr 2018 10:51:03 -0700 Subject: scsi: target: target_core_transport.c: fix kernel-doc warnings Correct a function parameter's name to eliminate kernel-doc warnings in drivers/target/target_core_transport.c. Fixes these kernel-doc warnings: (tested by adding these files to a new target.rst documentation file) ../drivers/target/target_core_transport.c:1671: warning: No description found for parameter 'fabric_tmr_ptr' ../drivers/target/target_core_transport.c:1671: warning: Excess function parameter 'fabric_context' description in 'target_submit_tmr' Signed-off-by: Randy Dunlap To: "Nicholas A. Bellinger" Cc: linux-scsi@vger.kernel.org Cc: target-devel@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Jonathan Corbet Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4558f2e1fe1b..f649cf0bed75 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1654,7 +1654,7 @@ static bool target_lookup_lun_from_tag(struct se_session *se_sess, u64 tag, * @se_sess: associated se_sess for endpoint * @sense: pointer to SCSI sense buffer * @unpacked_lun: unpacked LUN to reference for struct se_lun - * @fabric_context: fabric context for TMR req + * @fabric_tmr_ptr: fabric context for TMR req * @tm_type: Type of TM request * @gfp: gfp type for caller * @tag: referenced task tag for TMR_ABORT_TASK -- cgit v1.2.3 From 9ad97b8b409e0c6c90d5c8f35568d189bf1e6ed5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 14 Apr 2018 10:51:04 -0700 Subject: scsi: target: target_core_transport.c: enable+fix kernel-doc For exported functions that already have near-kernel-doc notation, fix them to begin with "/**" and make a few corrections so that they don't have any kernel-doc warnings. Signed-off-by: Randy Dunlap To: "Nicholas A. Bellinger" Cc: linux-scsi@vger.kernel.org Cc: target-devel@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Jonathan Corbet Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index f649cf0bed75..3500aa5927f2 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1431,7 +1431,7 @@ transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, return 0; } -/* +/** * target_submit_cmd_map_sgls - lookup unpacked lun and submit uninitialized * se_cmd + use pre-allocated SGL memory. * @@ -1441,7 +1441,7 @@ transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, * @sense: pointer to SCSI sense buffer * @unpacked_lun: unpacked LUN to reference for struct se_lun * @data_length: fabric expected data transfer length - * @task_addr: SAM task attribute + * @task_attr: SAM task attribute * @data_dir: DMA data direction * @flags: flags for command submission from target_sc_flags_tables * @sgl: struct scatterlist memory for unidirectional mapping @@ -1578,7 +1578,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess } EXPORT_SYMBOL(target_submit_cmd_map_sgls); -/* +/** * target_submit_cmd - lookup unpacked lun and submit uninitialized se_cmd * * @se_cmd: command descriptor to submit @@ -1587,7 +1587,7 @@ EXPORT_SYMBOL(target_submit_cmd_map_sgls); * @sense: pointer to SCSI sense buffer * @unpacked_lun: unpacked LUN to reference for struct se_lun * @data_length: fabric expected data transfer length - * @task_addr: SAM task attribute + * @task_attr: SAM task attribute * @data_dir: DMA data direction * @flags: flags for command submission from target_sc_flags_tables * @@ -2606,7 +2606,8 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) } EXPORT_SYMBOL(transport_generic_free_cmd); -/* target_get_sess_cmd - Add command to active ->sess_cmd_list +/** + * target_get_sess_cmd - Add command to active ->sess_cmd_list * @se_cmd: command descriptor to add * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() */ @@ -2800,7 +2801,8 @@ void target_show_cmd(const char *pfx, struct se_cmd *cmd) } EXPORT_SYMBOL(target_show_cmd); -/* target_sess_cmd_list_set_waiting - Flag all commands in +/** + * target_sess_cmd_list_set_waiting - Flag all commands in * sess_cmd_list to complete cmd_wait_comp. Set * sess_tearing_down so no more commands are queued. * @se_sess: session to flag @@ -2835,7 +2837,8 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) } EXPORT_SYMBOL(target_sess_cmd_list_set_waiting); -/* target_wait_for_sess_cmds - Wait for outstanding descriptors +/** + * target_wait_for_sess_cmds - Wait for outstanding descriptors * @se_sess: session to wait for active I/O */ void target_wait_for_sess_cmds(struct se_session *se_sess) -- cgit v1.2.3 From 572ccdab50bb3ae9096d6947c2e78a7107acf2dd Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 14 Apr 2018 10:51:05 -0700 Subject: scsi: target: target_core_user.[ch]: convert comments into DOC: Make documentation on target-supported userspace-I/O design be usable by kernel-doc by using "DOC:". This is used in the driver-api Documentation chapter. Signed-off-by: Randy Dunlap To: "Nicholas A. Bellinger" Cc: linux-scsi@vger.kernel.org Cc: target-devel@vger.kernel.org Cc: linux-doc@vger.kernel.org Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Cc: Jonathan Corbet Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 8 ++++++-- include/uapi/linux/target_core_user.h | 11 ++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index d6af29250d94..ae0aea9a3aad 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -42,7 +42,11 @@ #include -/* +/** + * DOC: Userspace I/O + * Userspace I/O + * ------------- + * * Define a shared-memory interface for LIO to pass SCSI commands and * data to userspace for processing. This is to allow backends that * are too complex for in-kernel support to be possible. @@ -53,7 +57,7 @@ * See the .h file for how the ring is laid out. Note that while the * command ring is defined, the particulars of the data area are * not. Offset values in the command entry point to other locations - * internal to the mmap()ed area. There is separate space outside the + * internal to the mmap-ed area. There is separate space outside the * command ring for data buffers. This leaves maximum flexibility for * moving buffer allocations, or even page flipping or other * allocation techniques, without altering the command ring layout. diff --git a/include/uapi/linux/target_core_user.h b/include/uapi/linux/target_core_user.h index 0be80f72646b..6e299349b158 100644 --- a/include/uapi/linux/target_core_user.h +++ b/include/uapi/linux/target_core_user.h @@ -9,21 +9,22 @@ #define TCMU_VERSION "2.0" -/* +/** + * DOC: Ring Design * Ring Design * ----------- * * The mmaped area is divided into three parts: - * 1) The mailbox (struct tcmu_mailbox, below) - * 2) The command ring - * 3) Everything beyond the command ring (data) + * 1) The mailbox (struct tcmu_mailbox, below); + * 2) The command ring; + * 3) Everything beyond the command ring (data). * * The mailbox tells userspace the offset of the command ring from the * start of the shared memory region, and how big the command ring is. * * The kernel passes SCSI commands to userspace by putting a struct * tcmu_cmd_entry in the ring, updating mailbox->cmd_head, and poking - * userspace via uio's interrupt mechanism. + * userspace via UIO's interrupt mechanism. * * tcmu_cmd_entry contains a header. If the header type is PAD, * userspace should skip hdr->length bytes (mod cmdr_size) to find the -- cgit v1.2.3 From 0e5aee393956f14b82c42486aefc327ba594ca60 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Wed, 2 May 2018 11:13:39 +0800 Subject: scsi: tcmu: add new netlink events helpers Add new netlink events helpers tcmu_netlink_event_init() and tcmu_netlink_event_send(). These new functions intend to replace existing netlink events helper function tcmu_netlink_event(). The existing function tcmu_netlink_event() works well for events like TCMU_ADDED_DEVICE and TCMU_REMOVED_DEVICE which only has one netlink attribute. But if there is a command requires more than one attributes to send out, we have to use a struct to adapt the paremeter reconfig_data, it is hard to use one struct or a union in one struct to adapt every command with different attributes, it may get long and ugly. With the new two functions, we can call tcmu_netlink_event_init() to initialize a netlink event, then add all attributes we need by using nla_put_xxx(), at last use tcmu_netlink_event_send() to send it out. So that we don't need to use a long struct or union if we want to send mulitple attributes for different commands. [mkp: typos] Signed-off-by: Zhu Lingshan Acked-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 59 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index ae0aea9a3aad..82f424dcee98 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1657,6 +1657,65 @@ free_skb: return ret; } +static int tcmu_netlink_event_init(struct tcmu_dev *udev, + enum tcmu_genl_cmd cmd, + struct sk_buff **buf, void **hdr) +{ + struct sk_buff *skb; + void *msg_header; + int ret = -ENOMEM; + + skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!skb) + return ret; + + msg_header = genlmsg_put(skb, 0, 0, &tcmu_genl_family, 0, cmd); + if (!msg_header) + goto free_skb; + + ret = nla_put_string(skb, TCMU_ATTR_DEVICE, udev->uio_info.name); + if (ret < 0) + goto free_skb; + + ret = nla_put_u32(skb, TCMU_ATTR_MINOR, udev->uio_info.uio_dev->minor); + if (ret < 0) + goto free_skb; + + ret = nla_put_u32(skb, TCMU_ATTR_DEVICE_ID, udev->se_dev.dev_index); + if (ret < 0) + goto free_skb; + + *buf = skb; + *hdr = msg_header; + return ret; + +free_skb: + nlmsg_free(skb); + return ret; +} + +static int tcmu_netlink_event_send(struct tcmu_dev *udev, + enum tcmu_genl_cmd cmd, + struct sk_buff **buf, void **hdr) +{ + int ret = 0; + struct sk_buff *skb = *buf; + void *msg_header = *hdr; + + genlmsg_end(skb, msg_header); + + tcmu_init_genl_cmd_reply(udev, cmd); + + ret = genlmsg_multicast_allns(&tcmu_genl_family, skb, 0, + TCMU_MCGRP_CONFIG, GFP_KERNEL); + /* We don't care if no one is listening */ + if (ret == -ESRCH) + ret = 0; + if (!ret) + ret = tcmu_wait_genl_cmd_reply(udev); + return ret; +} + static int tcmu_update_uio_info(struct tcmu_dev *udev) { struct tcmu_hba *hba = udev->hba->hba_ptr; -- cgit v1.2.3 From e0c240ac3aec565360bd38fae9e991b2ce376787 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Wed, 2 May 2018 11:13:40 +0800 Subject: scsi: tcmu: refactor add_device cmd with new nl helpers use new netlink events helpers tcmu_netlink_init() and tcmu_netlink_send() to refactor netlink event TCMU_CMD_ADDED_DEVICE Signed-off-by: Zhu Lingshan Acked-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 82f424dcee98..b0e3f03f77ed 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1716,6 +1716,21 @@ static int tcmu_netlink_event_send(struct tcmu_dev *udev, return ret; } +static int tcmu_send_dev_add_event(struct tcmu_dev *udev) +{ + struct sk_buff *skb = NULL; + void *msg_header = NULL; + int ret = 0; + + ret = tcmu_netlink_event_init(udev, TCMU_CMD_ADDED_DEVICE, &skb, + &msg_header); + if (ret < 0) + return ret; + return tcmu_netlink_event_send(udev, TCMU_CMD_ADDED_DEVICE, &skb, + &msg_header); + +} + static int tcmu_update_uio_info(struct tcmu_dev *udev) { struct tcmu_hba *hba = udev->hba->hba_ptr; @@ -1825,7 +1840,7 @@ static int tcmu_configure_device(struct se_device *dev) */ kref_get(&udev->kref); - ret = tcmu_netlink_event(udev, TCMU_CMD_ADDED_DEVICE, 0, NULL); + ret = tcmu_send_dev_add_event(udev); if (ret) goto err_netlink; -- cgit v1.2.3 From f892bd8ec14226d681021ef6e4c0cd2d5ca08e8d Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Wed, 2 May 2018 11:13:41 +0800 Subject: scsi: tcmu: refactor rm_device cmd with new nl helpers use new netlink events helpers tcmu_netlink_init() and tcmu_netlink_send() to refactor netlink event TCMU_CMD_REMOVED_DEVICE Signed-off-by: Zhu Lingshan Acked-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index b0e3f03f77ed..c621364cffc5 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1731,6 +1731,20 @@ static int tcmu_send_dev_add_event(struct tcmu_dev *udev) } +static int tcmu_send_dev_remove_event(struct tcmu_dev *udev) +{ + struct sk_buff *skb = NULL; + void *msg_header = NULL; + int ret = 0; + + ret = tcmu_netlink_event_init(udev, TCMU_CMD_REMOVED_DEVICE, + &skb, &msg_header); + if (ret < 0) + return ret; + return tcmu_netlink_event_send(udev, TCMU_CMD_REMOVED_DEVICE, + &skb, &msg_header); +} + static int tcmu_update_uio_info(struct tcmu_dev *udev) { struct tcmu_hba *hba = udev->hba->hba_ptr; @@ -1890,7 +1904,7 @@ static void tcmu_destroy_device(struct se_device *dev) list_del(&udev->node); mutex_unlock(&root_udev_mutex); - tcmu_netlink_event(udev, TCMU_CMD_REMOVED_DEVICE, 0, NULL); + tcmu_send_dev_remove_event(udev); uio_unregister_device(&udev->uio_info); -- cgit v1.2.3 From 02ccfb54ba7e73c47ce401920af8cf7a0c7bcaca Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Wed, 2 May 2018 11:13:42 +0800 Subject: scsi: tcmu: refactor nl dev_cfg attr with new nl helpers use new netlink events helpers tcmu_netlink_init() and tcmu_netlink_send() to refactor netlink event attribute TCMU_ATTR_DEV_CFG(belongs to TCMU_CMD_RECONFIG_DEVICE) which is also dev_config in configFS. Signed-off-by: Zhu Lingshan Acked-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index c621364cffc5..81495683ad3c 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2241,6 +2241,27 @@ static ssize_t tcmu_dev_config_show(struct config_item *item, char *page) return snprintf(page, PAGE_SIZE, "%s\n", udev->dev_config); } +static int tcmu_send_dev_config_event(struct tcmu_dev *udev, + const char *reconfig_data) +{ + struct sk_buff *skb = NULL; + void *msg_header = NULL; + int ret = 0; + + ret = tcmu_netlink_event_init(udev, TCMU_CMD_RECONFIG_DEVICE, + &skb, &msg_header); + if (ret < 0) + return ret; + ret = nla_put_string(skb, TCMU_ATTR_DEV_CFG, reconfig_data); + if (ret < 0) { + nlmsg_free(skb); + return ret; + } + return tcmu_netlink_event_send(udev, TCMU_CMD_RECONFIG_DEVICE, + &skb, &msg_header); +} + + static ssize_t tcmu_dev_config_store(struct config_item *item, const char *page, size_t count) { @@ -2255,8 +2276,7 @@ static ssize_t tcmu_dev_config_store(struct config_item *item, const char *page, /* Check if device has been configured before */ if (tcmu_dev_configured(udev)) { - ret = tcmu_netlink_event(udev, TCMU_CMD_RECONFIG_DEVICE, - TCMU_ATTR_DEV_CFG, page); + ret = tcmu_send_dev_config_event(udev, page); if (ret) { pr_err("Unable to reconfigure device\n"); return ret; -- cgit v1.2.3 From 84e285062848d9bca20b60827d26b7c72101c184 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Wed, 2 May 2018 11:13:43 +0800 Subject: scsi: tcmu: refactor nl dev_size attr with new helpers use new netlink events helpers tcmu_netlink_init() and tcmu_netlink_send() to refactor netlink event attribute TCMU_ATTR_DEV_SIZE(belongs to TCMU_CMD_RECONFIG_DEVICE) which is also dev_size in configFS. Signed-off-by: Zhu Lingshan Acked-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 81495683ad3c..a4c50482199c 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2303,6 +2303,26 @@ static ssize_t tcmu_dev_size_show(struct config_item *item, char *page) return snprintf(page, PAGE_SIZE, "%zu\n", udev->dev_size); } +static int tcmu_send_dev_size_event(struct tcmu_dev *udev, u64 size) +{ + struct sk_buff *skb = NULL; + void *msg_header = NULL; + int ret = 0; + + ret = tcmu_netlink_event_init(udev, TCMU_CMD_RECONFIG_DEVICE, + &skb, &msg_header); + if (ret < 0) + return ret; + ret = nla_put_u64_64bit(skb, TCMU_ATTR_DEV_SIZE, + size, TCMU_ATTR_PAD); + if (ret < 0) { + nlmsg_free(skb); + return ret; + } + return tcmu_netlink_event_send(udev, TCMU_CMD_RECONFIG_DEVICE, + &skb, &msg_header); +} + static ssize_t tcmu_dev_size_store(struct config_item *item, const char *page, size_t count) { @@ -2318,8 +2338,7 @@ static ssize_t tcmu_dev_size_store(struct config_item *item, const char *page, /* Check if device has been configured before */ if (tcmu_dev_configured(udev)) { - ret = tcmu_netlink_event(udev, TCMU_CMD_RECONFIG_DEVICE, - TCMU_ATTR_DEV_SIZE, &val); + ret = tcmu_send_dev_size_event(udev, val); if (ret) { pr_err("Unable to reconfigure device\n"); return ret; -- cgit v1.2.3 From 33d065ccb3b21e38412cd8c7d6f2704e3b341f63 Mon Sep 17 00:00:00 2001 From: Zhu Lingshan Date: Wed, 2 May 2018 11:13:44 +0800 Subject: scsi: tcmu: refactor nl wr_cache attr with new helpers use new netlink events helpers tcmu_netlink_init() and tcmu_netlink_send() to refactor netlink event attribute TCMU_ATTR_WRITECACHE(belongs to TCMU_CMD_RECONFIG_DEVICE) which is also emulate_write_cache in configFS. Removed tcmu_netlink_event() since we have new netlink events helpers now. Signed-off-by: Zhu Lingshan Acked-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 89 +++++++++------------------------------ 1 file changed, 20 insertions(+), 69 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index a4c50482199c..19a9c5fd7e1d 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1590,73 +1590,6 @@ static int tcmu_wait_genl_cmd_reply(struct tcmu_dev *udev) return ret; } -static int tcmu_netlink_event(struct tcmu_dev *udev, enum tcmu_genl_cmd cmd, - int reconfig_attr, const void *reconfig_data) -{ - struct sk_buff *skb; - void *msg_header; - int ret = -ENOMEM; - - skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!skb) - return ret; - - msg_header = genlmsg_put(skb, 0, 0, &tcmu_genl_family, 0, cmd); - if (!msg_header) - goto free_skb; - - ret = nla_put_string(skb, TCMU_ATTR_DEVICE, udev->uio_info.name); - if (ret < 0) - goto free_skb; - - ret = nla_put_u32(skb, TCMU_ATTR_MINOR, udev->uio_info.uio_dev->minor); - if (ret < 0) - goto free_skb; - - ret = nla_put_u32(skb, TCMU_ATTR_DEVICE_ID, udev->se_dev.dev_index); - if (ret < 0) - goto free_skb; - - if (cmd == TCMU_CMD_RECONFIG_DEVICE) { - switch (reconfig_attr) { - case TCMU_ATTR_DEV_CFG: - ret = nla_put_string(skb, reconfig_attr, reconfig_data); - break; - case TCMU_ATTR_DEV_SIZE: - ret = nla_put_u64_64bit(skb, reconfig_attr, - *((u64 *)reconfig_data), - TCMU_ATTR_PAD); - break; - case TCMU_ATTR_WRITECACHE: - ret = nla_put_u8(skb, reconfig_attr, - *((u8 *)reconfig_data)); - break; - default: - BUG(); - } - - if (ret < 0) - goto free_skb; - } - - genlmsg_end(skb, msg_header); - - tcmu_init_genl_cmd_reply(udev, cmd); - - ret = genlmsg_multicast_allns(&tcmu_genl_family, skb, 0, - TCMU_MCGRP_CONFIG, GFP_KERNEL); - /* We don't care if no one is listening */ - if (ret == -ESRCH) - ret = 0; - if (!ret) - ret = tcmu_wait_genl_cmd_reply(udev); - - return ret; -free_skb: - nlmsg_free(skb); - return ret; -} - static int tcmu_netlink_event_init(struct tcmu_dev *udev, enum tcmu_genl_cmd cmd, struct sk_buff **buf, void **hdr) @@ -2386,6 +2319,25 @@ static ssize_t tcmu_emulate_write_cache_show(struct config_item *item, return snprintf(page, PAGE_SIZE, "%i\n", da->emulate_write_cache); } +static int tcmu_send_emulate_write_cache(struct tcmu_dev *udev, u8 val) +{ + struct sk_buff *skb = NULL; + void *msg_header = NULL; + int ret = 0; + + ret = tcmu_netlink_event_init(udev, TCMU_CMD_RECONFIG_DEVICE, + &skb, &msg_header); + if (ret < 0) + return ret; + ret = nla_put_u8(skb, TCMU_ATTR_WRITECACHE, val); + if (ret < 0) { + nlmsg_free(skb); + return ret; + } + return tcmu_netlink_event_send(udev, TCMU_CMD_RECONFIG_DEVICE, + &skb, &msg_header); +} + static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, const char *page, size_t count) { @@ -2401,8 +2353,7 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, /* Check if device has been configured before */ if (tcmu_dev_configured(udev)) { - ret = tcmu_netlink_event(udev, TCMU_CMD_RECONFIG_DEVICE, - TCMU_ATTR_WRITECACHE, &val); + ret = tcmu_send_emulate_write_cache(udev, val); if (ret) { pr_err("Unable to reconfigure device\n"); return ret; -- cgit v1.2.3 From 769031c92c8b85bd886f7e064430b7b512c68728 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Wed, 21 Mar 2018 23:55:02 -0700 Subject: scsi: target: target/file: Add support of direct and async I/O There are two advantages: * Direct I/O allows to avoid the write-back cache, so it reduces affects to other processes in the system. * Async I/O allows to handle a few commands concurrently. DIO + AIO shows a better perfomance for random write operations: Mode: O_DSYNC Async: 1 $ ./fio --bs=4K --direct=1 --rw=randwrite --ioengine=libaio --iodepth=64 --name=/dev/sda --runtime=20 --numjobs=2 WRITE: bw=45.9MiB/s (48.1MB/s), 21.9MiB/s-23.0MiB/s (22.0MB/s-25.2MB/s), io=919MiB (963MB), run=20002-20020msec Mode: O_DSYNC Async: 0 $ ./fio --bs=4K --direct=1 --rw=randwrite --ioengine=libaio --iodepth=64 --name=/dev/sdb --runtime=20 --numjobs=2 WRITE: bw=1607KiB/s (1645kB/s), 802KiB/s-805KiB/s (821kB/s-824kB/s), io=31.8MiB (33.4MB), run=20280-20295msec Known issue: DIF (PI) emulation doesn't work when a target uses async I/O, because DIF metadata is saved in a separate file, and it is another non-trivial task how to synchronize writing in two files, so that a following read operation always returns a consisten metadata for a specified block. Cc: "Nicholas A. Bellinger" Cc: Christoph Hellwig Cc: Bryant G. Ly Tested-by: Bryant G. Ly Signed-off-by: Andrei Vagin Reviewed-by: Christoph Hellwig Reviewed-by: Bryant G. Ly Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_file.c | 137 ++++++++++++++++++++++++++++++++++---- drivers/target/target_core_file.h | 1 + 2 files changed, 124 insertions(+), 14 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 9b2c0c773022..16751ae55d7b 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -250,6 +250,84 @@ static void fd_destroy_device(struct se_device *dev) } } +struct target_core_file_cmd { + unsigned long len; + struct se_cmd *cmd; + struct kiocb iocb; +}; + +static void cmd_rw_aio_complete(struct kiocb *iocb, long ret, long ret2) +{ + struct target_core_file_cmd *cmd; + + cmd = container_of(iocb, struct target_core_file_cmd, iocb); + + if (ret != cmd->len) + target_complete_cmd(cmd->cmd, SAM_STAT_CHECK_CONDITION); + else + target_complete_cmd(cmd->cmd, SAM_STAT_GOOD); + + kfree(cmd); +} + +static sense_reason_t +fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, + enum dma_data_direction data_direction) +{ + int is_write = !(data_direction == DMA_FROM_DEVICE); + struct se_device *dev = cmd->se_dev; + struct fd_dev *fd_dev = FD_DEV(dev); + struct file *file = fd_dev->fd_file; + struct target_core_file_cmd *aio_cmd; + struct iov_iter iter = {}; + struct scatterlist *sg; + struct bio_vec *bvec; + ssize_t len = 0; + int ret = 0, i; + + aio_cmd = kmalloc(sizeof(struct target_core_file_cmd), GFP_KERNEL); + if (!aio_cmd) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + bvec = kcalloc(sgl_nents, sizeof(struct bio_vec), GFP_KERNEL); + if (!bvec) { + kfree(aio_cmd); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + + for_each_sg(sgl, sg, sgl_nents, i) { + bvec[i].bv_page = sg_page(sg); + bvec[i].bv_len = sg->length; + bvec[i].bv_offset = sg->offset; + + len += sg->length; + } + + iov_iter_bvec(&iter, ITER_BVEC | is_write, bvec, sgl_nents, len); + + aio_cmd->cmd = cmd; + aio_cmd->len = len; + aio_cmd->iocb.ki_pos = cmd->t_task_lba * dev->dev_attrib.block_size; + aio_cmd->iocb.ki_filp = file; + aio_cmd->iocb.ki_complete = cmd_rw_aio_complete; + aio_cmd->iocb.ki_flags = IOCB_DIRECT; + + if (is_write && (cmd->se_cmd_flags & SCF_FUA)) + aio_cmd->iocb.ki_flags |= IOCB_DSYNC; + + if (is_write) + ret = call_write_iter(file, &aio_cmd->iocb, &iter); + else + ret = call_read_iter(file, &aio_cmd->iocb, &iter); + + kfree(bvec); + + if (ret != -EIOCBQUEUED) + cmd_rw_aio_complete(&aio_cmd->iocb, ret, 0); + + return 0; +} + static int fd_do_rw(struct se_cmd *cmd, struct file *fd, u32 block_size, struct scatterlist *sgl, u32 sgl_nents, u32 data_length, int is_write) @@ -527,7 +605,7 @@ fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) } static sense_reason_t -fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, +fd_execute_rw_buffered(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) { struct se_device *dev = cmd->se_dev; @@ -536,16 +614,6 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, struct file *pfile = fd_dev->fd_prot_file; sense_reason_t rc; int ret = 0; - /* - * We are currently limited by the number of iovecs (2048) per - * single vfs_[writev,readv] call. - */ - if (cmd->data_length > FD_MAX_BYTES) { - pr_err("FILEIO: Not able to process I/O of %u bytes due to" - "FD_MAX_BYTES: %u iovec count limitation\n", - cmd->data_length, FD_MAX_BYTES); - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } /* * Call vectorized fileio functions to map struct scatterlist * physical memory addresses to struct iovec virtual memory. @@ -620,14 +688,39 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, return 0; } +static sense_reason_t +fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, + enum dma_data_direction data_direction) +{ + struct se_device *dev = cmd->se_dev; + struct fd_dev *fd_dev = FD_DEV(dev); + + /* + * We are currently limited by the number of iovecs (2048) per + * single vfs_[writev,readv] call. + */ + if (cmd->data_length > FD_MAX_BYTES) { + pr_err("FILEIO: Not able to process I/O of %u bytes due to" + "FD_MAX_BYTES: %u iovec count limitation\n", + cmd->data_length, FD_MAX_BYTES); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + + if (fd_dev->fbd_flags & FDBD_HAS_ASYNC_IO) + return fd_execute_rw_aio(cmd, sgl, sgl_nents, data_direction); + return fd_execute_rw_buffered(cmd, sgl, sgl_nents, data_direction); +} + enum { - Opt_fd_dev_name, Opt_fd_dev_size, Opt_fd_buffered_io, Opt_err + Opt_fd_dev_name, Opt_fd_dev_size, Opt_fd_buffered_io, + Opt_fd_async_io, Opt_err }; static match_table_t tokens = { {Opt_fd_dev_name, "fd_dev_name=%s"}, {Opt_fd_dev_size, "fd_dev_size=%s"}, {Opt_fd_buffered_io, "fd_buffered_io=%d"}, + {Opt_fd_async_io, "fd_async_io=%d"}, {Opt_err, NULL} }; @@ -693,6 +786,21 @@ static ssize_t fd_set_configfs_dev_params(struct se_device *dev, fd_dev->fbd_flags |= FDBD_HAS_BUFFERED_IO_WCE; break; + case Opt_fd_async_io: + ret = match_int(args, &arg); + if (ret) + goto out; + if (arg != 1) { + pr_err("bogus fd_async_io=%d value\n", arg); + ret = -EINVAL; + goto out; + } + + pr_debug("FILEIO: Using async I/O" + " operations for struct fd_dev\n"); + + fd_dev->fbd_flags |= FDBD_HAS_ASYNC_IO; + break; default: break; } @@ -709,10 +817,11 @@ static ssize_t fd_show_configfs_dev_params(struct se_device *dev, char *b) ssize_t bl = 0; bl = sprintf(b + bl, "TCM FILEIO ID: %u", fd_dev->fd_dev_id); - bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s\n", + bl += sprintf(b + bl, " File: %s Size: %llu Mode: %s Async: %d\n", fd_dev->fd_dev_name, fd_dev->fd_dev_size, (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) ? - "Buffered-WCE" : "O_DSYNC"); + "Buffered-WCE" : "O_DSYNC", + !!(fd_dev->fbd_flags & FDBD_HAS_ASYNC_IO)); return bl; } diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h index 53be5ffd3261..929b1ecd544e 100644 --- a/drivers/target/target_core_file.h +++ b/drivers/target/target_core_file.h @@ -22,6 +22,7 @@ #define FBDF_HAS_PATH 0x01 #define FBDF_HAS_SIZE 0x02 #define FDBD_HAS_BUFFERED_IO_WCE 0x04 +#define FDBD_HAS_ASYNC_IO 0x08 #define FDBD_FORMAT_UNIT_SIZE 2048 struct fd_dev { -- cgit v1.2.3 From bd81372065fa467e262150c70be885f47f9535df Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Tue, 15 May 2018 18:25:24 -0700 Subject: scsi: target: transport should handle st FM/EOM/ILI reads When a tape drive is exported via LIO using the pscsi module, a read that requests more bytes per block than the tape can supply returns an empty buffer. This is because the pscsi pass-through target module sees the "ILI" illegal length bit set and thinks there is no reason to return the data. This is a long-standing transport issue, since it assumes that no data need be returned under a check condition, which isn't always the case for tape. Add in a check for tape reads with the ILI, EOM, or FM bits set, with a sense code of NO_SENSE, treating such cases as if the read succeeded. The layered tape driver then "does the right thing" when it gets such a response. Signed-off-by: Bodo Stroesser Signed-off-by: Lee Duncan Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/target/target_core_pscsi.c | 26 ++++++++++++++++++-- drivers/target/target_core_transport.c | 43 +++++++++++++++++++++++++++++----- include/target/target_core_base.h | 1 + 3 files changed, 62 insertions(+), 8 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 0d99b242e82e..f31215b1d009 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -689,8 +689,29 @@ after_mode_sense: } after_mode_select: - if (scsi_status == SAM_STAT_CHECK_CONDITION) + if (scsi_status == SAM_STAT_CHECK_CONDITION) { transport_copy_sense_to_cmd(cmd, req_sense); + + /* + * check for TAPE device reads with + * FM/EOM/ILI set, so that we can get data + * back despite framework assumption that a + * check condition means there is no data + */ + if (sd->type == TYPE_TAPE && + cmd->data_direction == DMA_FROM_DEVICE) { + /* + * is sense data valid, fixed format, + * and have FM, EOM, or ILI set? + */ + if (req_sense[0] == 0xf0 && /* valid, fixed format */ + req_sense[2] & 0xe0 && /* FM, EOM, or ILI */ + (req_sense[2] & 0xf) == 0) { /* key==NO_SENSE */ + pr_debug("Tape FM/EOM/ILI status detected. Treat as normal read.\n"); + cmd->se_cmd_flags |= SCF_TREAT_READ_AS_NORMAL; + } + } + } } enum { @@ -1061,7 +1082,8 @@ static void pscsi_req_done(struct request *req, blk_status_t status) switch (host_byte(result)) { case DID_OK: - target_complete_cmd(cmd, scsi_status); + target_complete_cmd_with_length(cmd, scsi_status, + cmd->data_length - scsi_req(req)->resid_len); break; default: pr_debug("PSCSI Host Byte exception at cmd: %p CDB:" diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3500aa5927f2..bde14f46ed5b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -779,7 +779,9 @@ EXPORT_SYMBOL(target_complete_cmd); void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) { - if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) { + if ((scsi_status == SAM_STAT_GOOD || + cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) && + length < cmd->data_length) { if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { cmd->residual_count += cmd->data_length - length; } else { @@ -2084,12 +2086,24 @@ static void transport_complete_qf(struct se_cmd *cmd) goto queue_status; } - if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) + /* + * Check if we need to send a sense buffer from + * the struct se_cmd in question. We do NOT want + * to take this path of the IO has been marked as + * needing to be treated like a "normal read". This + * is the case if it's a tape read, and either the + * FM, EOM, or ILI bits are set, but there is no + * sense data. + */ + if (!(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) && + cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) goto queue_status; switch (cmd->data_direction) { case DMA_FROM_DEVICE: - if (cmd->scsi_status) + /* queue status if not treating this as a normal read */ + if (cmd->scsi_status && + !(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL)) goto queue_status; trace_target_cmd_complete(cmd); @@ -2194,9 +2208,15 @@ static void target_complete_ok_work(struct work_struct *work) /* * Check if we need to send a sense buffer from - * the struct se_cmd in question. + * the struct se_cmd in question. We do NOT want + * to take this path of the IO has been marked as + * needing to be treated like a "normal read". This + * is the case if it's a tape read, and either the + * FM, EOM, or ILI bits are set, but there is no + * sense data. */ - if (cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { + if (!(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL) && + cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) { WARN_ON(!cmd->scsi_status); ret = transport_send_check_condition_and_sense( cmd, 0, 1); @@ -2238,7 +2258,18 @@ static void target_complete_ok_work(struct work_struct *work) queue_rsp: switch (cmd->data_direction) { case DMA_FROM_DEVICE: - if (cmd->scsi_status) + /* + * if this is a READ-type IO, but SCSI status + * is set, then skip returning data and just + * return the status -- unless this IO is marked + * as needing to be treated as a normal read, + * in which case we want to go ahead and return + * the data. This happens, for example, for tape + * reads with the FM, EOM, or ILI bits set, with + * no sense data. + */ + if (cmd->scsi_status && + !(cmd->se_cmd_flags & SCF_TREAT_READ_AS_NORMAL)) goto queue_status; atomic_long_add(cmd->data_length, diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 9f9f5902af38..922a39f45abc 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -143,6 +143,7 @@ enum se_cmd_flags_table { SCF_ACK_KREF = 0x00400000, SCF_USE_CPUID = 0x00800000, SCF_TASK_ATTR_SET = 0x01000000, + SCF_TREAT_READ_AS_NORMAL = 0x02000000, }; /* -- cgit v1.2.3 From c16782808865b3b984d530eb535cafa889346989 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 26 May 2018 16:02:29 +0100 Subject: scsi: target: fix spelling mistake "Uknown" -> "Unknown" Trivial fix to spelling mistake in pr_err message text. Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index bde14f46ed5b..f0e8f0f4ccb4 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -3366,7 +3366,7 @@ static void target_tmr_work(struct work_struct *work) tmr->response = TMR_FUNCTION_REJECTED; break; default: - pr_err("Uknown TMR function: 0x%02x.\n", + pr_err("Unknown TMR function: 0x%02x.\n", tmr->function); tmr->response = TMR_FUNCTION_REJECTED; break; -- cgit v1.2.3