From patchwork Wed May 27 14:13:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hannes Reinecke X-Patchwork-Id: 11573103 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5A7E414B7 for ; Wed, 27 May 2020 14:14:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 468C220899 for ; Wed, 27 May 2020 14:14:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388138AbgE0OOP (ORCPT ); Wed, 27 May 2020 10:14:15 -0400 Received: from mx2.suse.de ([195.135.220.15]:51224 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730131AbgE0OOO (ORCPT ); Wed, 27 May 2020 10:14:14 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id B3A9BB125; Wed, 27 May 2020 14:14:13 +0000 (UTC) From: Hannes Reinecke To: "Martin K. Petersen" Cc: Christoph Hellwig , Doug Gilbert , Daniel Wagner , James Bottomley , linux-scsi@vger.kernel.org, Hannes Reinecke Subject: [PATCH 1/4] scsi: convert target lookup to xarray Date: Wed, 27 May 2020 16:13:57 +0200 Message-Id: <20200527141400.58087-2-hare@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20200527141400.58087-1-hare@suse.de> References: <20200527141400.58087-1-hare@suse.de> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Use an xarray instead of lists for holding the scsi targets. I've also shortened the 'channel' and 'id' values to 16 bit as none of the drivers requires a full 32bit range for either of them, and by shortening them we can use them as the index into the xarray for storing the scsi_target pointer. Signed-off-by: Hannes Reinecke Reported-by: kbuild test robot Reported-by: kbuild test robot Reported-by: Dan Carpenter --- drivers/scsi/hosts.c | 2 +- drivers/scsi/scsi.c | 35 ++++++++++++++++++++++++----------- drivers/scsi/scsi_scan.c | 39 +++++++++++++-------------------------- drivers/scsi/scsi_sysfs.c | 15 +++++++++++---- include/scsi/scsi_device.h | 4 ++-- include/scsi/scsi_host.h | 2 +- 6 files changed, 52 insertions(+), 45 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 7ec91c3a66ca..7109afad0183 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -383,7 +383,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) spin_lock_init(shost->host_lock); shost->shost_state = SHOST_CREATED; INIT_LIST_HEAD(&shost->__devices); - INIT_LIST_HEAD(&shost->__targets); + xa_init(&shost->__targets); INIT_LIST_HEAD(&shost->eh_cmd_q); INIT_LIST_HEAD(&shost->starved_list); init_waitqueue_head(&shost->host_wait); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 56c24a73e0c7..25c815355d1a 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -575,6 +575,19 @@ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost, } EXPORT_SYMBOL(__scsi_iterate_devices); +/** + * __scsi_target_lookup - find a target based on channel and target id + * @shost: SCSI host pointer + * @channel: channel number of the target + * @id: ID of the target + * + */ +static struct scsi_target *__scsi_target_lookup(struct Scsi_Host *shost, + u16 channel, u16 id) +{ + return xa_load(&shost->__targets, (channel << 16) | id); +} + /** * starget_for_each_device - helper to walk all devices of a target * @starget: target whose devices we want to iterate over. @@ -670,8 +683,8 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target); struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget, u64 lun) { - struct scsi_device *sdev; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct scsi_device *sdev; unsigned long flags; spin_lock_irqsave(shost->host_lock, flags); @@ -701,19 +714,19 @@ EXPORT_SYMBOL(scsi_device_lookup_by_target); * really want to use scsi_device_lookup instead. **/ struct scsi_device *__scsi_device_lookup(struct Scsi_Host *shost, - uint channel, uint id, u64 lun) + u16 channel, u16 id, u64 lun) { + struct scsi_target *starget; struct scsi_device *sdev; - list_for_each_entry(sdev, &shost->__devices, siblings) { - if (sdev->sdev_state == SDEV_DEL) - continue; - if (sdev->channel == channel && sdev->id == id && - sdev->lun ==lun) - return sdev; - } + starget = __scsi_target_lookup(shost, channel, id); + if (!starget) + return NULL; + sdev = __scsi_device_lookup_by_target(starget, lun); + if (sdev && sdev->sdev_state == SDEV_DEL) + sdev = NULL; - return NULL; + return sdev; } EXPORT_SYMBOL(__scsi_device_lookup); @@ -729,7 +742,7 @@ EXPORT_SYMBOL(__scsi_device_lookup); * needs to be released with scsi_device_put once you're done with it. **/ struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost, - uint channel, uint id, u64 lun) + u16 channel, u16 id, u64 lun) { struct scsi_device *sdev; unsigned long flags; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index f2437a7570ce..c47cddef1839 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -304,11 +304,15 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, return NULL; } +#define scsi_target_index(s) \ + ((((unsigned long)(s)->channel) << 16) | (s)->id) + static void scsi_target_destroy(struct scsi_target *starget) { struct device *dev = &starget->dev; struct Scsi_Host *shost = dev_to_shost(dev->parent); unsigned long flags; + unsigned long tid = scsi_target_index(starget); BUG_ON(starget->state == STARGET_DEL); starget->state = STARGET_DEL; @@ -316,7 +320,7 @@ static void scsi_target_destroy(struct scsi_target *starget) spin_lock_irqsave(shost->host_lock, flags); if (shost->hostt->target_destroy) shost->hostt->target_destroy(starget); - list_del_init(&starget->siblings); + xa_erase(&shost->__targets, tid); spin_unlock_irqrestore(shost->host_lock, flags); put_device(dev); } @@ -341,27 +345,6 @@ int scsi_is_target_device(const struct device *dev) } EXPORT_SYMBOL(scsi_is_target_device); -static struct scsi_target *__scsi_find_target(struct device *parent, - int channel, uint id) -{ - struct scsi_target *starget, *found_starget = NULL; - struct Scsi_Host *shost = dev_to_shost(parent); - /* - * Search for an existing target for this sdev. - */ - list_for_each_entry(starget, &shost->__targets, siblings) { - if (starget->id == id && - starget->channel == channel) { - found_starget = starget; - break; - } - } - if (found_starget) - get_device(&found_starget->dev); - - return found_starget; -} - /** * scsi_target_reap_ref_release - remove target from visibility * @kref: the reap_ref in the target being released @@ -417,6 +400,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, struct scsi_target *starget; struct scsi_target *found_target; int error, ref_got; + unsigned long tid; starget = kzalloc(size, GFP_KERNEL); if (!starget) { @@ -433,19 +417,22 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, starget->id = id; starget->channel = channel; starget->can_queue = 0; - INIT_LIST_HEAD(&starget->siblings); INIT_LIST_HEAD(&starget->devices); starget->state = STARGET_CREATED; starget->scsi_level = SCSI_2; starget->max_target_blocked = SCSI_DEFAULT_TARGET_BLOCKED; + tid = scsi_target_index(starget); retry: spin_lock_irqsave(shost->host_lock, flags); - found_target = __scsi_find_target(parent, channel, id); + found_target = xa_load(&shost->__targets, tid); if (found_target) goto found; - - list_add_tail(&starget->siblings, &shost->__targets); + if (xa_insert(&shost->__targets, tid, starget, GFP_KERNEL)) { + dev_printk(KERN_ERR, dev, "target index busy\n"); + kfree(starget); + return NULL; + } spin_unlock_irqrestore(shost->host_lock, flags); /* allocate and add */ transport_setup_device(dev); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 163dbcb741c1..95aaa96ce03b 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1512,15 +1512,19 @@ void scsi_remove_target(struct device *dev) { struct Scsi_Host *shost = dev_to_shost(dev->parent); struct scsi_target *starget; + unsigned long tid = 0; unsigned long flags; -restart: spin_lock_irqsave(shost->host_lock, flags); - list_for_each_entry(starget, &shost->__targets, siblings) { + starget = xa_find(&shost->__targets, &tid, ULONG_MAX, XA_PRESENT); + while (starget) { if (starget->state == STARGET_DEL || starget->state == STARGET_REMOVE || - starget->state == STARGET_CREATED_REMOVE) + starget->state == STARGET_CREATED_REMOVE) { + starget = xa_find_after(&shost->__targets, &tid, + ULONG_MAX, XA_PRESENT); continue; + } if (starget->dev.parent == dev || &starget->dev == dev) { kref_get(&starget->reap_ref); if (starget->state == STARGET_CREATED) @@ -1530,7 +1534,10 @@ void scsi_remove_target(struct device *dev) spin_unlock_irqrestore(shost->host_lock, flags); __scsi_remove_target(starget); scsi_target_reap(starget); - goto restart; + spin_lock_irqsave(shost->host_lock, flags); + starget = xa_find_after(&shost->__targets, &tid, + ULONG_MAX, XA_PRESENT); + continue; } } spin_unlock_irqrestore(shost->host_lock, flags); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index c3cba2aaf934..28034cc0fce5 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -345,9 +345,9 @@ extern struct scsi_device *scsi_device_from_queue(struct request_queue *q); extern int __must_check scsi_device_get(struct scsi_device *); extern void scsi_device_put(struct scsi_device *); extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *, - uint, uint, u64); + u16, u16, u64); extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *, - uint, uint, u64); + u16, u16, u64); extern struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *, u64); extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *, diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 822e8cda8d9b..b9395676c75b 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -521,7 +521,7 @@ struct Scsi_Host { * access this list directly from a driver. */ struct list_head __devices; - struct list_head __targets; + struct xarray __targets; struct list_head starved_list; From patchwork Wed May 27 14:13:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hannes Reinecke X-Patchwork-Id: 11573095 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 073DB14B7 for ; Wed, 27 May 2020 14:14:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EC95E2084C for ; Wed, 27 May 2020 14:14:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730168AbgE0OOM (ORCPT ); Wed, 27 May 2020 10:14:12 -0400 Received: from mx2.suse.de ([195.135.220.15]:51212 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729302AbgE0OOM (ORCPT ); Wed, 27 May 2020 10:14:12 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id B325AB120; Wed, 27 May 2020 14:14:13 +0000 (UTC) From: Hannes Reinecke To: "Martin K. Petersen" Cc: Christoph Hellwig , Doug Gilbert , Daniel Wagner , James Bottomley , linux-scsi@vger.kernel.org, Hannes Reinecke Subject: [PATCH 2/4] target_core_pscsi: use __scsi_device_lookup() Date: Wed, 27 May 2020 16:13:58 +0200 Message-Id: <20200527141400.58087-3-hare@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20200527141400.58087-1-hare@suse.de> References: <20200527141400.58087-1-hare@suse.de> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Instead of walking the list of devices manually use the helper function to return the device directly. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn --- drivers/target/target_core_pscsi.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 4e37fa9b409d..38799e47b590 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -496,11 +496,9 @@ static int pscsi_configure_device(struct se_device *dev) } spin_lock_irq(sh->host_lock); - list_for_each_entry(sd, &sh->__devices, siblings) { - if ((pdv->pdv_channel_id != sd->channel) || - (pdv->pdv_target_id != sd->id) || - (pdv->pdv_lun_id != sd->lun)) - continue; + sd = __scsi_device_lookup(sh, pdv->pdv_channel_id, + pdv->pdv_target_id, pdv->pdv_lun_id); + if (sd) { /* * Functions will release the held struct scsi_host->host_lock * before calling calling pscsi_add_device_to_list() to register From patchwork Wed May 27 14:13:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hannes Reinecke X-Patchwork-Id: 11573099 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E3933159A for ; Wed, 27 May 2020 14:14:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CFDDB20899 for ; Wed, 27 May 2020 14:14:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388041AbgE0OON (ORCPT ); Wed, 27 May 2020 10:14:13 -0400 Received: from mx2.suse.de ([195.135.220.15]:51214 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729959AbgE0OON (ORCPT ); Wed, 27 May 2020 10:14:13 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id B336EB123; Wed, 27 May 2020 14:14:13 +0000 (UTC) From: Hannes Reinecke To: "Martin K. Petersen" Cc: Christoph Hellwig , Doug Gilbert , Daniel Wagner , James Bottomley , linux-scsi@vger.kernel.org, Hannes Reinecke Subject: [PATCH 3/4] scsi: move target device list to xarray Date: Wed, 27 May 2020 16:13:59 +0200 Message-Id: <20200527141400.58087-4-hare@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20200527141400.58087-1-hare@suse.de> References: <20200527141400.58087-1-hare@suse.de> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Use xarray for device lookup by target. LUNs below 256 are linear, and can be used directly as the index into the xarray. LUNs above 256 have a distinct LUN format, and are not necessarily linear. They'll be stored in indices above 256 in the xarray, with the next free index in the xarray. Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Reported-by: kbuild test robot Reported-by: kbuild test robot --- drivers/scsi/scsi.c | 28 +++++++++++++++------------- drivers/scsi/scsi_lib.c | 8 +++----- drivers/scsi/scsi_scan.c | 7 +++++-- drivers/scsi/scsi_sysfs.c | 15 +++++++++++++-- include/scsi/scsi_device.h | 4 ++-- 5 files changed, 38 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 25c815355d1a..36aec2b37caa 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -601,13 +601,14 @@ static struct scsi_target *__scsi_target_lookup(struct Scsi_Host *shost, void starget_for_each_device(struct scsi_target *starget, void *data, void (*fn)(struct scsi_device *, void *)) { - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct scsi_device *sdev; + unsigned long lun_id = 0; - shost_for_each_device(sdev, shost) { - if ((sdev->channel == starget->channel) && - (sdev->id == starget->id)) - fn(sdev, data); + xa_for_each(&starget->devices, lun_id, sdev) { + if (scsi_device_get(sdev)) + continue; + fn(sdev, data); + scsi_device_put(sdev); } } EXPORT_SYMBOL(starget_for_each_device); @@ -629,14 +630,11 @@ EXPORT_SYMBOL(starget_for_each_device); void __starget_for_each_device(struct scsi_target *starget, void *data, void (*fn)(struct scsi_device *, void *)) { - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct scsi_device *sdev; + unsigned long lun_id = 0; - __shost_for_each_device(sdev, shost) { - if ((sdev->channel == starget->channel) && - (sdev->id == starget->id)) - fn(sdev, data); - } + xa_for_each(&starget->devices, lun_id, sdev) + fn(sdev, data); } EXPORT_SYMBOL(__starget_for_each_device); @@ -659,11 +657,15 @@ struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget, u64 lun) { struct scsi_device *sdev; + unsigned long lun_idx = 0; + + if (lun < 256) + return xa_load(&starget->devices, lun); - list_for_each_entry(sdev, &starget->devices, same_target_siblings) { + xa_for_each(&starget->devices, lun_idx, sdev) { if (sdev->sdev_state == SDEV_DEL) continue; - if (sdev->lun ==lun) + if (sdev->lun == lun) return sdev; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index c163fa22267c..23c99fbe47d5 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -361,9 +361,9 @@ static void scsi_kick_queue(struct request_queue *q) static void scsi_single_lun_run(struct scsi_device *current_sdev) { struct Scsi_Host *shost = current_sdev->host; - struct scsi_device *sdev, *tmp; + struct scsi_device *sdev; struct scsi_target *starget = scsi_target(current_sdev); - unsigned long flags; + unsigned long flags, lun_id = 0; spin_lock_irqsave(shost->host_lock, flags); starget->starget_sdev_user = NULL; @@ -380,8 +380,7 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev) spin_lock_irqsave(shost->host_lock, flags); if (starget->starget_sdev_user) goto out; - list_for_each_entry_safe(sdev, tmp, &starget->devices, - same_target_siblings) { + xa_for_each(&starget->devices, lun_id, sdev) { if (sdev == current_sdev) continue; if (scsi_device_get(sdev)) @@ -390,7 +389,6 @@ static void scsi_single_lun_run(struct scsi_device *current_sdev) spin_unlock_irqrestore(shost->host_lock, flags); scsi_kick_queue(sdev->request_queue); spin_lock_irqsave(shost->host_lock, flags); - scsi_device_put(sdev); } out: diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index c47cddef1839..6fce5fe6ef32 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -232,10 +232,13 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, sdev->id = starget->id; sdev->lun = lun; sdev->channel = starget->channel; + if (lun < 256) + sdev->lun_idx = lun; + else + sdev->lun_idx = (unsigned int)-1; mutex_init(&sdev->state_mutex); sdev->sdev_state = SDEV_CREATED; INIT_LIST_HEAD(&sdev->siblings); - INIT_LIST_HEAD(&sdev->same_target_siblings); INIT_LIST_HEAD(&sdev->starved_entry); INIT_LIST_HEAD(&sdev->event_list); spin_lock_init(&sdev->list_lock); @@ -417,7 +420,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, starget->id = id; starget->channel = channel; starget->can_queue = 0; - INIT_LIST_HEAD(&starget->devices); + xa_init(&starget->devices); starget->state = STARGET_CREATED; starget->scsi_level = SCSI_2; starget->max_target_blocked = SCSI_DEFAULT_TARGET_BLOCKED; diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 95aaa96ce03b..b9ed56d6bd95 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -434,6 +434,7 @@ static void scsi_device_cls_release(struct device *class_dev) static void scsi_device_dev_release_usercontext(struct work_struct *work) { struct scsi_device *sdev; + struct scsi_target *starget = sdev->sdev_target; struct device *parent; struct list_head *this, *tmp; struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL; @@ -448,7 +449,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) spin_lock_irqsave(sdev->host->host_lock, flags); list_del(&sdev->siblings); - list_del(&sdev->same_target_siblings); + xa_erase(&starget->devices, sdev->lun_idx); list_del(&sdev->starved_entry); spin_unlock_irqrestore(sdev->host->host_lock, flags); @@ -1621,7 +1622,17 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) transport_setup_device(&sdev->sdev_gendev); spin_lock_irqsave(shost->host_lock, flags); - list_add_tail(&sdev->same_target_siblings, &starget->devices); + if (sdev->lun_idx != (unsigned long)-1) + WARN_ON(!xa_insert(&starget->devices, sdev->lun_idx, + sdev, GFP_KERNEL)); + else { + struct xa_limit scsi_lun_limit = { + .min = 256, + .max = UINT_MAX, + }; + WARN_ON(!xa_alloc(&starget->devices, &sdev->lun_idx, + sdev, scsi_lun_limit, GFP_KERNEL)); + } list_add_tail(&sdev->siblings, &shost->__devices); spin_unlock_irqrestore(shost->host_lock, flags); /* diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 28034cc0fce5..2c6b9d8bc40e 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -104,7 +104,6 @@ struct scsi_device { /* the next two are protected by the host->host_lock */ struct list_head siblings; /* list of all devices on this host */ - struct list_head same_target_siblings; /* just the devices sharing same target id */ atomic_t device_busy; /* commands actually active on LLDD */ atomic_t device_blocked; /* Device returned QUEUE_FULL. */ @@ -123,6 +122,7 @@ struct scsi_device { unsigned int id, channel; u64 lun; + unsigned int lun_idx; /* Index into target device xarray */ unsigned int manufacturer; /* Manufacturer of device, for using * vendor-specific cmd's */ unsigned sector_size; /* size in bytes */ @@ -285,7 +285,7 @@ enum scsi_target_state { struct scsi_target { struct scsi_device *starget_sdev_user; struct list_head siblings; - struct list_head devices; + struct xarray devices; struct device dev; struct kref reap_ref; /* last put renders target invisible */ unsigned int channel; From patchwork Wed May 27 14:14:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hannes Reinecke X-Patchwork-Id: 11573101 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7DFA614B7 for ; Wed, 27 May 2020 14:14:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 651C8207D8 for ; Wed, 27 May 2020 14:14:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729302AbgE0OOP (ORCPT ); Wed, 27 May 2020 10:14:15 -0400 Received: from mx2.suse.de ([195.135.220.15]:51216 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730030AbgE0OON (ORCPT ); Wed, 27 May 2020 10:14:13 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id B300FAB99; Wed, 27 May 2020 14:14:13 +0000 (UTC) From: Hannes Reinecke To: "Martin K. Petersen" Cc: Christoph Hellwig , Doug Gilbert , Daniel Wagner , James Bottomley , linux-scsi@vger.kernel.org, Hannes Reinecke Subject: [PATCH 4/4] scsi: remove direct device lookup per host Date: Wed, 27 May 2020 16:14:00 +0200 Message-Id: <20200527141400.58087-5-hare@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20200527141400.58087-1-hare@suse.de> References: <20200527141400.58087-1-hare@suse.de> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org Drop the per-host device list for direct lookup and iterate over the targets and devices xarrays instead. As both are now using xarrays the lookup is more efficient as we can use the provided indices based on the HCTL id to do a direct lookup instead of traversing lists. Signed-off-by: Hannes Reinecke Reported-by: kbuild test robot --- drivers/scsi/hosts.c | 1 - drivers/scsi/scsi.c | 68 +++++++++++++++++++++++++++++++++++++++++----- drivers/scsi/scsi_scan.c | 20 ++++++++------ drivers/scsi/scsi_sysfs.c | 13 ++------- include/scsi/scsi_device.h | 13 +++++---- include/scsi/scsi_host.h | 3 +- 6 files changed, 85 insertions(+), 33 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 7109afad0183..004a50a95560 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -382,7 +382,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->host_lock = &shost->default_lock; spin_lock_init(shost->host_lock); shost->shost_state = SHOST_CREATED; - INIT_LIST_HEAD(&shost->__devices); xa_init(&shost->__targets); INIT_LIST_HEAD(&shost->eh_cmd_q); INIT_LIST_HEAD(&shost->starved_list); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 36aec2b37caa..172767e7ee71 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -554,18 +554,39 @@ EXPORT_SYMBOL(scsi_device_put); struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost, struct scsi_device *prev) { - struct list_head *list = (prev ? &prev->siblings : &shost->__devices); + struct scsi_target *starget; struct scsi_device *next = NULL; unsigned long flags; + unsigned long tid = 0, lun_idx = 0; spin_lock_irqsave(shost->host_lock, flags); - while (list->next != &shost->__devices) { - next = list_entry(list->next, struct scsi_device, siblings); - /* skip devices that we can't get a reference to */ + if (!prev) { + starget = xa_find(&shost->__targets, &tid, + ULONG_MAX, XA_PRESENT); + if (starget) { + next = xa_find(&starget->devices, &lun_idx, + ULONG_MAX, XA_PRESENT); + if (!scsi_device_get(next)) { + spin_unlock_irqrestore(shost->host_lock, flags); + return next; + } + } + } else { + starget = prev->sdev_target; + lun_idx = prev->lun_idx; + } + while (starget) { + tid = (starget->channel << 16) | starget->id; + next = xa_find_after(&starget->devices, &tid, + ULONG_MAX, XA_PRESENT); + if (!next) { + lun_idx = 0; + starget = xa_find_after(&shost->__targets, &tid, + ULONG_MAX, XA_PRESENT); + continue; + } if (!scsi_device_get(next)) break; - next = NULL; - list = list->next; } spin_unlock_irqrestore(shost->host_lock, flags); @@ -575,6 +596,38 @@ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost, } EXPORT_SYMBOL(__scsi_iterate_devices); +/* helper for __shost_for_each_device, see that for documentation */ +struct scsi_device *__scsi_iterate_devices_unlocked(struct Scsi_Host *shost, + struct scsi_device *prev) +{ + struct scsi_target *starget; + struct scsi_device *next = NULL; + unsigned long tid = 0, lun_idx = 0; + + if (!prev) { + starget = xa_find(&shost->__targets, &tid, + ULONG_MAX, XA_PRESENT); + if (starget) + return xa_find(&starget->devices, &lun_idx, + ULONG_MAX, XA_PRESENT); + } else { + starget = prev->sdev_target; + lun_idx = prev->lun_idx; + } + while (starget) { + tid = (starget->channel << 16) | starget->id; + next = xa_find_after(&starget->devices, &tid, + ULONG_MAX, XA_PRESENT); + if (next) + return next; + lun_idx = 0; + starget = xa_find_after(&shost->__targets, &tid, + ULONG_MAX, XA_PRESENT); + } + return NULL; +} +EXPORT_SYMBOL(__scsi_iterate_devices_unlocked); + /** * __scsi_target_lookup - find a target based on channel and target id * @shost: SCSI host pointer @@ -582,11 +635,12 @@ EXPORT_SYMBOL(__scsi_iterate_devices); * @id: ID of the target * */ -static struct scsi_target *__scsi_target_lookup(struct Scsi_Host *shost, +struct scsi_target *__scsi_target_lookup(struct Scsi_Host *shost, u16 channel, u16 id) { return xa_load(&shost->__targets, (channel << 16) | id); } +EXPORT_SYMBOL(__scsi_target_lookup); /** * starget_for_each_device - helper to walk all devices of a target diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 6fce5fe6ef32..24179591848b 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -238,7 +238,6 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, sdev->lun_idx = (unsigned int)-1; mutex_init(&sdev->state_mutex); sdev->sdev_state = SDEV_CREATED; - INIT_LIST_HEAD(&sdev->siblings); INIT_LIST_HEAD(&sdev->starved_entry); INIT_LIST_HEAD(&sdev->event_list); spin_lock_init(&sdev->list_lock); @@ -1849,17 +1848,22 @@ EXPORT_SYMBOL(scsi_scan_host); void scsi_forget_host(struct Scsi_Host *shost) { + struct scsi_target *starget; struct scsi_device *sdev; unsigned long flags; + unsigned long tid = 0; - restart: spin_lock_irqsave(shost->host_lock, flags); - list_for_each_entry(sdev, &shost->__devices, siblings) { - if (sdev->sdev_state == SDEV_DEL) - continue; - spin_unlock_irqrestore(shost->host_lock, flags); - __scsi_remove_device(sdev); - goto restart; + xa_for_each(&shost->__targets, tid, starget) { + unsigned long lun_id = 0; + + xa_for_each(&starget->devices, lun_id, sdev) { + if (sdev->sdev_state == SDEV_DEL) + continue; + spin_unlock_irqrestore(shost->host_lock, flags); + __scsi_remove_device(sdev); + spin_lock_irqsave(shost->host_lock, flags); + } } spin_unlock_irqrestore(shost->host_lock, flags); } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index b9ed56d6bd95..24822f6ee136 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -434,7 +434,6 @@ static void scsi_device_cls_release(struct device *class_dev) static void scsi_device_dev_release_usercontext(struct work_struct *work) { struct scsi_device *sdev; - struct scsi_target *starget = sdev->sdev_target; struct device *parent; struct list_head *this, *tmp; struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL; @@ -448,8 +447,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) parent = sdev->sdev_gendev.parent; spin_lock_irqsave(sdev->host->host_lock, flags); - list_del(&sdev->siblings); - xa_erase(&starget->devices, sdev->lun_idx); + xa_erase(&sdev->sdev_target->devices, sdev->lun_idx); list_del(&sdev->starved_entry); spin_unlock_irqrestore(sdev->host->host_lock, flags); @@ -1475,19 +1473,16 @@ static void __scsi_remove_target(struct scsi_target *starget) struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); unsigned long flags; struct scsi_device *sdev; + unsigned long lun_idx = 0; spin_lock_irqsave(shost->host_lock, flags); - restart: - list_for_each_entry(sdev, &shost->__devices, siblings) { + xa_for_each(&starget->devices, lun_idx, sdev) { /* * We cannot call scsi_device_get() here, as * we might've been called from rmmod() causing * scsi_device_get() to fail the module_is_live() * check. */ - if (sdev->channel != starget->channel || - sdev->id != starget->id) - continue; if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL || !get_device(&sdev->sdev_gendev)) @@ -1496,7 +1491,6 @@ static void __scsi_remove_target(struct scsi_target *starget) scsi_remove_device(sdev); put_device(&sdev->sdev_gendev); spin_lock_irqsave(shost->host_lock, flags); - goto restart; } spin_unlock_irqrestore(shost->host_lock, flags); } @@ -1633,7 +1627,6 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) WARN_ON(!xa_alloc(&starget->devices, &sdev->lun_idx, sdev, scsi_lun_limit, GFP_KERNEL)); } - list_add_tail(&sdev->siblings, &shost->__devices); spin_unlock_irqrestore(shost->host_lock, flags); /* * device can now only be removed via __scsi_remove_device() so hold diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 2c6b9d8bc40e..b811b5e3adfe 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -102,9 +102,6 @@ struct scsi_device { struct Scsi_Host *host; struct request_queue *request_queue; - /* the next two are protected by the host->host_lock */ - struct list_head siblings; /* list of all devices on this host */ - atomic_t device_busy; /* commands actually active on LLDD */ atomic_t device_blocked; /* Device returned QUEUE_FULL. */ @@ -376,6 +373,10 @@ extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *, (sdev); \ (sdev) = __scsi_iterate_devices((shost), (sdev))) +/* only exposed to implement shost_for_each_device */ +struct scsi_device *__scsi_iterate_devices_unlocked(struct Scsi_Host *, + struct scsi_device *); + /** * __shost_for_each_device - iterate over all devices of a host (UNLOCKED) * @sdev: the &struct scsi_device to use as a cursor @@ -389,8 +390,10 @@ extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *, * device list in interrupt context. Otherwise you really want to use * shost_for_each_device instead. */ -#define __shost_for_each_device(sdev, shost) \ - list_for_each_entry((sdev), &((shost)->__devices), siblings) +#define __shost_for_each_device(sdev, shost) \ + for((sdev) = __scsi_iterate_devices_unlocked((shost), NULL); \ + (sdev); \ + (sdev) = __scsi_iterate_devices_unlocked((shost),(sdev))) extern int scsi_change_queue_depth(struct scsi_device *, int); extern int scsi_track_queue_full(struct scsi_device *, int); diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index b9395676c75b..ee0b72075e9f 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -520,9 +520,8 @@ struct Scsi_Host { * their __ prefixed variants with the lock held. NEVER * access this list directly from a driver. */ - struct list_head __devices; struct xarray __targets; - + struct list_head starved_list; spinlock_t default_lock;