Re: [PATCH] mpt3sas: correct reset of smid while clearing scsi tracker
Any update on this patch!. Thanks, Sreekanth On Fri, Jul 20, 2018 at 5:56 PM, Sreekanth Reddy wrote: > In mpt3sas_base_clear_st() function smid value is reseted in wrong line, > i.e. driver should reset smid value to zero after decrementing chain_offset > counter in chain_lookup table but in current code, driver is resetting smid > value before decrementing the chain_offset counter. which we are correcting > with this patch. > > v1 changelog: > Added memory barriers before & after atomic_set() API. > > Signed-off-by: Sreekanth Reddy > --- > drivers/scsi/mpt3sas/mpt3sas_base.c | 8 +++- > 1 file changed, 7 insertions(+), 1 deletion(-) > > diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c > b/drivers/scsi/mpt3sas/mpt3sas_base.c > index 902610d..94359d8 100644 > --- a/drivers/scsi/mpt3sas/mpt3sas_base.c > +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c > @@ -1702,6 +1702,8 @@ static int mpt3sas_remove_dead_ioc_func(void *arg) > return NULL; > > chain_req = >chain_lookup[smid - > 1].chains_per_smid[chain_offset]; > + /* Adding memory barrier before atomic operation. */ > + smp_mb__before_atomic(); > atomic_inc(>chain_lookup[smid - 1].chain_offset); > return chain_req; > } > @@ -3283,8 +3285,12 @@ void mpt3sas_base_clear_st(struct MPT3SAS_ADAPTER *ioc, > return; > st->cb_idx = 0xFF; > st->direct_io = 0; > - st->smid = 0; > + /* Adding memory barrier before atomic operation. */ > + smp_mb__before_atomic(); > atomic_set(>chain_lookup[st->smid - 1].chain_offset, 0); > + /* Adding memory barrier after atomic operation. */ > + smp_mb__after_atomic(); > + st->smid = 0; > } > > /** > -- > 1.8.3.1 >
[PATCH 9/9] tcmu: use u64 for dev_size
We use unsigned long, size_t and u64 for dev_size. This has us standardize on u64. Signed-off-by: Mike Christie --- drivers/target/target_core_user.c | 21 - 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index cfe4f4b..b34179a 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -137,7 +137,7 @@ struct tcmu_dev { struct inode *inode; struct tcmu_mailbox *mb_addr; - size_t dev_size; + uint64_t dev_size; u32 cmdr_size; u32 cmdr_last_cleaned; /* Offset of data area from start of mb */ @@ -2016,7 +2016,7 @@ enum { static match_table_t tokens = { {Opt_dev_config, "dev_config=%s"}, - {Opt_dev_size, "dev_size=%u"}, + {Opt_dev_size, "dev_size=%s"}, {Opt_hw_block_size, "hw_block_size=%d"}, {Opt_hw_max_sectors, "hw_max_sectors=%d"}, {Opt_nl_reply_supported, "nl_reply_supported=%d"}, @@ -2083,7 +2083,7 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, const char *page, ssize_t count) { struct tcmu_dev *udev = TCMU_DEV(dev); - char *orig, *ptr, *opts, *arg_p; + char *orig, *ptr, *opts; substring_t args[MAX_OPT_ARGS]; int ret = 0, token; @@ -2108,15 +2108,10 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, pr_debug("TCMU: Referencing Path: %s\n", udev->dev_config); break; case Opt_dev_size: - arg_p = match_strdup([0]); - if (!arg_p) { - ret = -ENOMEM; - break; - } - ret = kstrtoul(arg_p, 0, (unsigned long *) >dev_size); - kfree(arg_p); + ret = match_u64([0], >dev_size); if (ret < 0) - pr_err("kstrtoul() failed for dev_size=\n"); + pr_err("match_u64() failed for dev_size=. Error %d.\n", + ret); break; case Opt_hw_block_size: ret = tcmu_set_dev_attrib([0], @@ -2154,7 +2149,7 @@ static ssize_t tcmu_show_configfs_dev_params(struct se_device *dev, char *b) bl = sprintf(b + bl, "Config: %s ", udev->dev_config[0] ? udev->dev_config : "NULL"); - bl += sprintf(b + bl, "Size: %zu ", udev->dev_size); + bl += sprintf(b + bl, "Size: %llu ", udev->dev_size); bl += sprintf(b + bl, "MaxDataAreaMB: %u\n", TCMU_BLOCKS_TO_MBS(udev->max_blocks)); @@ -2323,7 +2318,7 @@ static ssize_t tcmu_dev_size_show(struct config_item *item, char *page) struct se_dev_attrib, da_group); struct tcmu_dev *udev = TCMU_DEV(da->da_dev); - return snprintf(page, PAGE_SIZE, "%zu\n", udev->dev_size); + return snprintf(page, PAGE_SIZE, "%llu\n", udev->dev_size); } static int tcmu_send_dev_size_event(struct tcmu_dev *udev, u64 size) -- 1.8.3.1
[PATCH 5/9] tcmu: check if dev is configured before block/reset
Do not allow userspace to block or reset the ring until the device has been configured. This will prevent the bug where userspace can write to those files and access mb_addr before it has been setup. Signed-off-by: Mike Christie --- drivers/target/target_core_user.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index bc8121f..d6b4022 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2480,6 +2480,11 @@ static ssize_t tcmu_block_dev_store(struct config_item *item, const char *page, u8 val; int ret; + if (!target_dev_configured(>se_dev)) { + pr_err("Device is not configured.\n"); + return -EINVAL; + } + ret = kstrtou8(page, 0, ); if (ret < 0) return ret; @@ -2507,6 +2512,11 @@ static ssize_t tcmu_reset_ring_store(struct config_item *item, const char *page, u8 val; int ret; + if (!target_dev_configured(>se_dev)) { + pr_err("Device is not configured.\n"); + return -EINVAL; + } + ret = kstrtou8(page, 0, ); if (ret < 0) return ret; -- 1.8.3.1
[PATCH 4/9] tcmu: use lio core se_device configuration helper
Use the lio core helper to check if the device is configured. Signed-off-by: Mike Christie --- drivers/target/target_core_user.c | 11 +++ 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index b010ed7..bc8121f 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1908,11 +1908,6 @@ static int tcmu_configure_device(struct se_device *dev) return ret; } -static bool tcmu_dev_configured(struct tcmu_dev *udev) -{ - return udev->uio_info.uio_dev ? true : false; -} - static void tcmu_free_device(struct se_device *dev) { struct tcmu_dev *udev = TCMU_DEV(dev); @@ -2305,7 +2300,7 @@ static ssize_t tcmu_dev_config_store(struct config_item *item, const char *page, return -EINVAL; /* Check if device has been configured before */ - if (tcmu_dev_configured(udev)) { + if (target_dev_configured(>se_dev)) { ret = tcmu_send_dev_config_event(udev, page); if (ret) { pr_err("Unable to reconfigure device\n"); @@ -2367,7 +2362,7 @@ static ssize_t tcmu_dev_size_store(struct config_item *item, const char *page, return ret; /* Check if device has been configured before */ - if (tcmu_dev_configured(udev)) { + if (target_dev_configured(>se_dev)) { ret = tcmu_send_dev_size_event(udev, val); if (ret) { pr_err("Unable to reconfigure device\n"); @@ -2449,7 +2444,7 @@ static ssize_t tcmu_emulate_write_cache_store(struct config_item *item, return ret; /* Check if device has been configured before */ - if (tcmu_dev_configured(udev)) { + if (target_dev_configured(>se_dev)) { ret = tcmu_send_emulate_write_cache(udev, val); if (ret) { pr_err("Unable to reconfigure device\n"); -- 1.8.3.1
[PATCH 8/9] tcmu: use match_int for dev params
Instead of doing strdup and kstrto* just use match_int for dev params. It will be ok to use int instead of unsigned long in tcmu_set_dev_attrib because that is only being used for max sectors and block size and the supported values for them are well under the max possible integer value. Signed-off-by: Mike Christie --- drivers/target/target_core_user.c | 37 ++--- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 969ccba..cfe4f4b 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2017,8 +2017,8 @@ enum { static match_table_t tokens = { {Opt_dev_config, "dev_config=%s"}, {Opt_dev_size, "dev_size=%u"}, - {Opt_hw_block_size, "hw_block_size=%u"}, - {Opt_hw_max_sectors, "hw_max_sectors=%u"}, + {Opt_hw_block_size, "hw_block_size=%d"}, + {Opt_hw_max_sectors, "hw_max_sectors=%d"}, {Opt_nl_reply_supported, "nl_reply_supported=%d"}, {Opt_max_data_area_mb, "max_data_area_mb=%d"}, {Opt_err, NULL} @@ -2026,25 +2026,21 @@ enum { static int tcmu_set_dev_attrib(substring_t *arg, u32 *dev_attrib) { - unsigned long tmp_ul; - char *arg_p; - int ret; - - arg_p = match_strdup(arg); - if (!arg_p) - return -ENOMEM; + int val, ret; - ret = kstrtoul(arg_p, 0, _ul); - kfree(arg_p); + ret = match_int(arg, ); if (ret < 0) { - pr_err("kstrtoul() failed for dev attrib\n"); + pr_err("match_int() failed for dev attrib. Error %d.\n", + ret); return ret; } - if (!tmp_ul) { - pr_err("dev attrib must be nonzero\n"); + + if (val <= 0) { + pr_err("Invalid dev attrib value %d. Must be greater than zero.\n", + val); return -EINVAL; } - *dev_attrib = tmp_ul; + *dev_attrib = val; return 0; } @@ -2131,15 +2127,10 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, &(dev->dev_attrib.hw_max_sectors)); break; case Opt_nl_reply_supported: - arg_p = match_strdup([0]); - if (!arg_p) { - ret = -ENOMEM; - break; - } - ret = kstrtoint(arg_p, 0, >nl_reply_supported); - kfree(arg_p); + ret = match_int([0], >nl_reply_supported); if (ret < 0) - pr_err("kstrtoint() failed for nl_reply_supported=\n"); + pr_err("match_int() failed for nl_reply_supported=. Error %d.\n", + ret); break; case Opt_max_data_area_mb: ret = tcmu_set_max_blocks_param(udev, [0]); -- 1.8.3.1
[PATCH 7/9] tcmu: do not set max_blocks if data_bitmap has been setup
This patch prevents a bug where data_bitmap is allocated in tcmu_configure_device, userspace changes the max_blocks setting, the device is mapped to a LUN, then we try to access the data_bitmap based on the new max_blocks limit which may now be out of range. To prevent this, we just check if data_bitmap has been setup. If it has then we fail the max_blocks update operation. Signed-off-by: Mike Christie --- drivers/target/target_core_user.c | 73 +-- 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 31cfe83..969ccba 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1811,9 +1811,11 @@ static int tcmu_configure_device(struct se_device *dev) info = >uio_info; + mutex_lock(>cmdr_lock); udev->data_bitmap = kcalloc(BITS_TO_LONGS(udev->max_blocks), sizeof(unsigned long), GFP_KERNEL); + mutex_unlock(>cmdr_lock); if (!udev->data_bitmap) { ret = -ENOMEM; goto err_bitmap_alloc; @@ -2018,7 +2020,7 @@ enum { {Opt_hw_block_size, "hw_block_size=%u"}, {Opt_hw_max_sectors, "hw_max_sectors=%u"}, {Opt_nl_reply_supported, "nl_reply_supported=%d"}, - {Opt_max_data_area_mb, "max_data_area_mb=%u"}, + {Opt_max_data_area_mb, "max_data_area_mb=%d"}, {Opt_err, NULL} }; @@ -2046,13 +2048,48 @@ static int tcmu_set_dev_attrib(substring_t *arg, u32 *dev_attrib) return 0; } +static int tcmu_set_max_blocks_param(struct tcmu_dev *udev, substring_t *arg) +{ + int val, ret; + + ret = match_int(arg, ); + if (ret < 0) { + pr_err("match_int() failed for max_data_area_mb=. Error %d.\n", + ret); + return ret; + } + + if (val <= 0) { + pr_err("Invalid max_data_area %d.\n", val); + return -EINVAL; + } + + mutex_lock(>cmdr_lock); + if (udev->data_bitmap) { + pr_err("Cannot set max_data_area_mb after it has been enabled.\n"); + ret = -EINVAL; + goto unlock; + } + + udev->max_blocks = TCMU_MBS_TO_BLOCKS(val); + if (udev->max_blocks > tcmu_global_max_blocks) { + pr_err("%d is too large. Adjusting max_data_area_mb to global limit of %u\n", + val, TCMU_BLOCKS_TO_MBS(tcmu_global_max_blocks)); + udev->max_blocks = tcmu_global_max_blocks; + } + +unlock: + mutex_unlock(>cmdr_lock); + return ret; +} + static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, const char *page, ssize_t count) { struct tcmu_dev *udev = TCMU_DEV(dev); char *orig, *ptr, *opts, *arg_p; substring_t args[MAX_OPT_ARGS]; - int ret = 0, token, tmpval; + int ret = 0, token; opts = kstrdup(page, GFP_KERNEL); if (!opts) @@ -2105,37 +2142,7 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, pr_err("kstrtoint() failed for nl_reply_supported=\n"); break; case Opt_max_data_area_mb: - if (dev->export_count) { - pr_err("Unable to set max_data_area_mb while exports exist\n"); - ret = -EINVAL; - break; - } - - arg_p = match_strdup([0]); - if (!arg_p) { - ret = -ENOMEM; - break; - } - ret = kstrtoint(arg_p, 0, ); - kfree(arg_p); - if (ret < 0) { - pr_err("kstrtoint() failed for max_data_area_mb=\n"); - break; - } - - if (tmpval <= 0) { - pr_err("Invalid max_data_area %d\n", tmpval); - ret = -EINVAL; - break; - } - - udev->max_blocks = TCMU_MBS_TO_BLOCKS(tmpval); - if (udev->max_blocks > tcmu_global_max_blocks) { - pr_err("%d is too large. Adjusting max_data_area_mb to global limit of %u\n", - tmpval, - TCMU_BLOCKS_TO_MBS(tcmu_global_max_blocks)); - udev->max_blocks = tcmu_global_max_blocks; - } + ret = tcmu_set_max_blocks_param(udev, [0]); break; default: break; -- 1.8.3.1
[PATCH 0/9] tcmu: configuration fixes and cleanups
The following patches were made over Martin's for-next branch. The first patch fixes a locking bug in the command setup path. The rest of the patches fix several bugs and cleanup the setup and configuration code paths.
[PATCH 2/9] tcmu: initialize list head
Use INIT_LIST_HEAD to initialize node list head. Signed-off-by: Mike Christie --- drivers/target/target_core_user.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index fafe65f..b010ed7 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1342,6 +1342,7 @@ static struct se_device *tcmu_alloc_device(struct se_hba *hba, const char *name) udev->max_blocks = DATA_BLOCK_BITS_DEF; mutex_init(>cmdr_lock); + INIT_LIST_HEAD(>node); INIT_LIST_HEAD(>timedout_entry); INIT_LIST_HEAD(>cmdr_queue); idr_init(>commands); -- 1.8.3.1
[PATCH 6/9] tcmu: unmap if dev is configured
The tcmu dev is added to the list of tcmu devices during configuration. At this time the tcmu setup has completed, but lio core has not completed its setup. The device is not yet usable so do not try to unmap blocks from it Signed-off-by: Mike Christie --- drivers/target/target_core_user.c | 5 + 1 file changed, 5 insertions(+) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index d6b4022..31cfe83 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -2581,6 +2581,11 @@ static void find_free_blocks(void) list_for_each_entry(udev, _udev, node) { mutex_lock(>cmdr_lock); + if (!target_dev_configured(>se_dev)) { + mutex_unlock(>cmdr_lock); + continue; + } + /* Try to complete the finished commands first */ tcmu_handle_completions(udev); -- 1.8.3.1
[PATCH 3/9] target: add helper to check if dev is configured
This just adds a helper function to check if a device is configured and it converts the target users to use it. The next patch will add a backend module user so those types of modules do not have to know the lio core details. Signed-off-by: Mike Christie --- drivers/target/target_core_configfs.c| 8 drivers/target/target_core_device.c | 6 +++--- drivers/target/target_core_fabric_configfs.c | 3 ++- include/target/target_core_backend.h | 4 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 93d3ff3..f6b1549 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -810,7 +810,7 @@ static ssize_t pi_prot_type_store(struct config_item *item, dev->transport->name); return -ENOSYS; } - if (!(dev->dev_flags & DF_CONFIGURED)) { + if (!target_dev_configured(dev)) { pr_err("DIF protection requires device to be configured\n"); return -ENODEV; } @@ -859,7 +859,7 @@ static ssize_t pi_prot_format_store(struct config_item *item, dev->transport->name); return -ENOSYS; } - if (!(dev->dev_flags & DF_CONFIGURED)) { + if (!target_dev_configured(dev)) { pr_err("DIF protection format requires device to be configured\n"); return -ENODEV; } @@ -1948,7 +1948,7 @@ static ssize_t target_dev_enable_show(struct config_item *item, char *page) { struct se_device *dev = to_device(item); - return snprintf(page, PAGE_SIZE, "%d\n", !!(dev->dev_flags & DF_CONFIGURED)); + return snprintf(page, PAGE_SIZE, "%d\n", target_dev_configured(dev)); } static ssize_t target_dev_enable_store(struct config_item *item, @@ -2473,7 +2473,7 @@ static ssize_t target_tg_pt_gp_alua_access_state_store(struct config_item *item, " tg_pt_gp ID: %hu\n", tg_pt_gp->tg_pt_gp_valid_id); return -EINVAL; } - if (!(dev->dev_flags & DF_CONFIGURED)) { + if (!target_dev_configured(dev)) { pr_err("Unable to set alua_access_state while device is" " not configured\n"); return -ENODEV; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 73675ee..47b5ef1 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -900,7 +900,7 @@ static int target_devices_idr_iter(int id, void *p, void *data) * to allow other callers to access partially setup devices, * so we skip them here. */ - if (!(dev->dev_flags & DF_CONFIGURED)) + if (!target_dev_configured(dev)) return 0; iter->prev_item = config_item_get_unless_zero(>dev_group.cg_item); @@ -940,7 +940,7 @@ int target_configure_device(struct se_device *dev) struct se_hba *hba = dev->se_hba; int ret, id; - if (dev->dev_flags & DF_CONFIGURED) { + if (target_dev_configured(dev)) { pr_err("se_dev->se_dev_ptr already set for storage" " object\n"); return -EEXIST; @@ -1045,7 +1045,7 @@ void target_free_device(struct se_device *dev) WARN_ON(!list_empty(>dev_sep_list)); - if (dev->dev_flags & DF_CONFIGURED) { + if (target_dev_configured(dev)) { destroy_workqueue(dev->tmr_wq); dev->transport->destroy_device(dev); diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 1fa436e..aa2f4f6 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -34,6 +34,7 @@ #include #include +#include #include #include "target_core_internal.h" @@ -642,7 +643,7 @@ static int target_fabric_port_link( } dev = container_of(to_config_group(se_dev_ci), struct se_device, dev_group); - if (!(dev->dev_flags & DF_CONFIGURED)) { + if (!target_dev_configured(dev)) { pr_err("se_device not configured yet, cannot port link\n"); return -ENODEV; } diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index c3ac472..51b6f50 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -111,6 +111,10 @@ sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd, bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib, struct request_queue *q); +static inline bool target_dev_configured(struct se_device *se_dev) +{ + return !!(se_dev->dev_flags & DF_CONFIGURED); +} /* Only use get_unaligned_be24() if reading p - 1 is allowed. */ static inline uint32_t
[PATCH 1/9] target_core_user: fix double unlock
The caller of queue_cmd_ring grabs and releases the lock, so the tcmu_setup_cmd_timer failure handling inside queue_cmd_ring should not call mutex_unlock. Signed-off-by: Mike Christie --- drivers/target/target_core_user.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 847707a..fafe65f 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -1066,7 +1066,6 @@ static sense_reason_t queue_cmd_ring(struct tcmu_cmd *tcmu_cmd, int *scsi_err) >cmd_timer); if (ret) { tcmu_cmd_free_data(tcmu_cmd, tcmu_cmd->dbi_cnt); - mutex_unlock(>cmdr_lock); *scsi_err = TCM_OUT_OF_RESOURCES; return -1; -- 1.8.3.1
[no subject]
-- Hallo Am Mrs Mavis Wancyzk, Sie haben eine Spende von 4,800,000.00EUR Ich gewann die America Lottery im Wert von $ 758.7 Millionen und ich spende einen Teil davon an fünf glückliche Menschen und Wohltätigkeits-Häuser in Erinnerung an meinen verstorbenen Ehemann, der an Krebs gestorben ist. Kontaktieren Sie mich für weitere Details unter: [maviswanczy...@hotmail.com]