Re: [PATCH v3 7/7] ata: libata: Improve CDL resource management

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2024/09/03 17:01, Niklas Cassel wrote:
> On Tue, Sep 03, 2024 at 07:55:05AM +0900, Damien Le Moal wrote:
>> On 9/3/24 06:04, Niklas Cassel wrote:
>>>> @@ -6000,11 +6018,19 @@ static void ata_port_detach(struct ata_port *ap)
>>>>  	ata_port_wait_eh(ap);
>>>>  
>>>>  	mutex_lock(&ap->scsi_scan_mutex);
>>>> +
>>>> +	/* Cleanup CDL device resources */
>>>> +	ata_for_each_link(link, ap, HOST_FIRST) {
>>>> +		ata_for_each_dev(dev, link, ALL)
>>>> +			ata_dev_cleanup_cdl_resources(dev);
>>>
>>> Here you clean up resources.
>>> Why?
>>> Resources will get cleaned up when ata_port_free() is called,
>>> which will be called by ata_devres_release() -> ata_host_put()
>>> -> ata_host_release() -> ata_port_free(), when the device is
>>> removed.
>>
>> That happens only if the host (=port) is removed, but not if only the device is
>> being removed, e.g. because it was yanked out of its slot (hotplug) or the user
>> removed it using sysfs. In such case, the port remains and is not deleted, so
>> ata_port_free() is not called. Ports exists for as long as the adapter exist.
>>
>>> I don't see any reason to free it here as well.
>>
>> Hotplug of drives :)
> 
> ?
> 
> This code is in ata_port_detach(), which is called only by ata_host_detach().
> 
> So the code you have added here is only when the port is detached, not when
> the device is detached / hotplug removed.

Indeed. I screwed-up with this one :)

> For hotplug it is these functions:
> ata_eh_detach_dev() and ata_scsi_handle_link_detach() that will be called.

And that's the path I should have modified.

> We know that the struct ata_device is never freed until the port is freed,
> but if you want to be nice and free the device's resources on hotplug,
> then I think it is better to remove the freeing for the resources in
> ata_port_free(), and only perform it in ata_eh_dev_disable(), since
> ata_eh_dev_disable() is called both on hotplug removals (by ata_eh_detach_dev())
> and on unload (by ata_eh_unload()).
> 
> Unload is performed by ata_port_detach(), so ata_eh_unload() ->
> ata_eh_dev_disable() will always be called, there is no need for an additional
> freeing in ata_port_detach() (or in ata_port_free()).
> 
> I suggest something like the following on top of your v4:
> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
> index afc245b2f7cc..57e40987b10a 100644
> --- a/drivers/ata/libata-core.c
> +++ b/drivers/ata/libata-core.c
> @@ -5463,11 +5463,6 @@ void ata_port_free(struct ata_port *ap)
>         if (!ap)
>                 return;
>  
> -       ata_for_each_link(link, ap, HOST_FIRST) {
> -               ata_for_each_dev(dev, link, ALL)
> -                       ata_dev_cleanup_cdl_resources(dev);
> -       }
> -
>         kfree(ap->pmp_link);
>         kfree(ap->slave_link);
>         ida_free(&ata_ida, ap->print_id);
> @@ -6019,12 +6014,6 @@ static void ata_port_detach(struct ata_port *ap)
>  
>         mutex_lock(&ap->scsi_scan_mutex);
>  
> -       /* Cleanup CDL device resources */
> -       ata_for_each_link(link, ap, HOST_FIRST) {
> -               ata_for_each_dev(dev, link, ALL)
> -                       ata_dev_cleanup_cdl_resources(dev);
> -       }
> -
>         spin_lock_irqsave(ap->lock, flags);
>  
>         /* Remove scsi devices */
> @@ -6055,13 +6044,6 @@ static void ata_port_detach(struct ata_port *ap)
>         cancel_delayed_work_sync(&ap->hotplug_task);
>         cancel_delayed_work_sync(&ap->scsi_rescan_task);
>  
> -       /* clean up zpodd on port removal */
> -       ata_for_each_link(link, ap, HOST_FIRST) {
> -               ata_for_each_dev(dev, link, ALL) {
> -                       if (zpodd_dev_enabled(dev))
> -                               zpodd_exit(dev);
> -               }
> -       }
>         if (ap->pmp_link) {
>                 int i;
>                 for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
> diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
> index 41f1bee0b434..9e870e01509d 100644
> --- a/drivers/ata/libata-eh.c
> +++ b/drivers/ata/libata-eh.c
> @@ -494,13 +494,21 @@ void ata_eh_release(struct ata_port *ap)
>         mutex_unlock(&ap->host->eh_mutex);
>  }
>  
> +static void ata_eh_dev_free_resources(struct ata_device *dev)
> +{
> +       if (zpodd_dev_enabled(dev))
> +               zpodd_exit(dev);
> +
> +       ata_dev_cleanup_cdl_resources(dev);
> +}
> +
>  static void ata_eh_dev_disable(struct ata_device *dev)
>  {
>         ata_acpi_on_disable(dev);
>         ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET);
>         dev->class++;
>  
> -       ata_dev_cleanup_cdl_resources(dev);
> +       ata_eh_dev_free_resources(dev);
>  
>         /* From now till the next successful probe, ering is used to
>          * track probe failures.  Clear accumulated device error info.
> diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
> index 3407e764a5ff..8cd241d39c14 100644
> --- a/drivers/ata/libata-scsi.c
> +++ b/drivers/ata/libata-scsi.c
> @@ -4612,9 +4612,6 @@ static void ata_scsi_handle_link_detach(struct ata_link *link)
>                 dev->flags &= ~ATA_DFLAG_DETACHED;
>                 spin_unlock_irqrestore(ap->lock, flags);
>  
> -               if (zpodd_dev_enabled(dev))
> -                       zpodd_exit(dev);
> -
>                 ata_scsi_remove_dev(dev);
>         }
>  }
> 
> 
> So that we keep all the freeing of struct ata_device's resources in a single
> function.

Looks better. I will integrate that in patch 7. Thanks.

> 
> 
> Kind regards,
> Niklas

-- 
Damien Le Moal
Western Digital Research





[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux