From: Niklas Cassel <cassel@kernel.org>
To: Damien Le Moal <dlemoal@kernel.org>
Cc: linux-ide@vger.kernel.org
Subject: Re: [PATCH 7/7] ata: libata: Improve CDL resource management
Date: Mon, 26 Aug 2024 17:37:21 +0200 [thread overview]
Message-ID: <ZsyhMdG_Z1o5EbFv@ryzen.lan> (raw)
In-Reply-To: <20240826073106.56918-8-dlemoal@kernel.org>
On Mon, Aug 26, 2024 at 04:31:06PM +0900, Damien Le Moal wrote:
> The command duration limits (CDL) log buffer of struct ata_device is
> needed only if a device actually supports CDL. The same applies to the
> ncq_sense_log buffer.
>
> Group these 2 buffers into a new structure ata_cdl defining both buffers
> as embedded buffers (no allocation needed) and allocate this structure
> from ata_dev_config_cdl() only for devices that support CDL.
>
> The functions ata_dev_init_cdl_resources() and
> ata_dev_cleanup_cdl_resources() are defined to manage this new structure
> allocation, initialization and cleanup when a device is removed.
> ata_dev_cleanup_cdl_resources() is called from ata_tdev_free().
>
> Note that the cdl log buffer name is changed to desc_log_buf to make it
> clearer what it is.
>
> This change reduces the size of struct ata_device and reduces memory
> usage for ATA devices that do not support CDL.
>
> Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Like previous comment, as long as sector_buf belongs to struct ata_port,
it seems a bit weird to keep this in struct ata_device.
Perhaps we can move sector_buf to struct ata_device?
(and modify the ata_read_log() functions to not take a buffer,
as the buffer would not be in the struct ata_device, which we already
supply to the ata_read_log() functions as the first argument.)
If we do that, then I think it is okay to keep a struct ata_cdl
in struct ata_device. Although I still don't like cleaning this
up in ata_tdev_() functions.
Perhaps we could call ata_device_cleanup()/ata_device_free_resource()
from ata_port_free() ?
ata_tport_release() will call ata_host_put().
ata_host_put() calls kref_put(&host->kref, ata_host_release);
ata_host_release() calls ata_port_free().
But ata_tport_add() is simply adding the sysfs entry IMO.
The sysfs entry takes a ata_host reference.
Once the refcount is zero, it will be freed.
Which is why I think that it makes more sense to clean this up in in
ata_port_free() (at least with the current design where the fixed size
ata_device array is part of struct ata_port (via struct ata_link)).
Perhaps something like:
void ata_port_free(struct ata_port *ap)
{
....
ata_for_each_link (link, ap, ...) {
ata_for_each_dev (dev, link, ...) {
ata_device_cleanup(dev);
}
}
}
Kind regards,
Niklas
> ---
> drivers/ata/libata-core.c | 56 +++++++++++++++++++++-------------
> drivers/ata/libata-sata.c | 2 +-
> drivers/ata/libata-scsi.c | 2 +-
> drivers/ata/libata-transport.c | 4 +--
> drivers/ata/libata.h | 1 +
> include/linux/libata.h | 18 +++++++++--
> 6 files changed, 54 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
> index 6a1d300dd1f5..bcee96e29b34 100644
> --- a/drivers/ata/libata-core.c
> +++ b/drivers/ata/libata-core.c
> @@ -2475,12 +2475,41 @@ static void ata_dev_config_trusted(struct ata_device *dev)
> dev->flags |= ATA_DFLAG_TRUSTED;
> }
>
> +static int ata_dev_init_cdl_resources(struct ata_device *dev)
> +{
> + struct ata_cdl *cdl = dev->cdl;
> + unsigned int err_mask;
> +
> + if (!cdl) {
> + cdl = kzalloc(sizeof(struct ata_cdl), GFP_KERNEL);
> + if (!cdl)
> + return -ENOMEM;
> + dev->cdl = cdl;
> + }
> +
> + err_mask = ata_read_log_page(dev, ATA_LOG_CDL, 0, cdl->desc_log_buf,
> + ATA_LOG_CDL_SIZE / ATA_SECT_SIZE);
> + if (err_mask) {
> + ata_dev_warn(dev, "Read Command Duration Limits log failed\n");
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +void ata_dev_cleanup_cdl_resources(struct ata_device *dev)
> +{
> + kfree(dev->cdl);
> + dev->cdl = NULL;
> +}
> +
> static void ata_dev_config_cdl(struct ata_device *dev)
> {
> struct ata_port *ap = dev->link->ap;
> unsigned int err_mask;
> bool cdl_enabled;
> u64 val;
> + int ret;
>
> if (ata_id_major_version(dev->id) < 11)
> goto not_supported;
> @@ -2575,37 +2604,20 @@ static void ata_dev_config_cdl(struct ata_device *dev)
> }
> }
>
> - /*
> - * Allocate a buffer to handle reading the sense data for successful
> - * NCQ Commands log page for commands using a CDL with one of the limit
> - * policy set to 0xD (successful completion with sense data available
> - * bit set).
> - */
> - if (!dev->ncq_sense_buf) {
> - dev->ncq_sense_buf = kmalloc(ATA_LOG_SENSE_NCQ_SIZE, GFP_KERNEL);
> - if (!dev->ncq_sense_buf)
> - goto not_supported;
> - }
> -
> - /*
> - * Command duration limits is supported: cache the CDL log page 18h
> - * (command duration descriptors).
> - */
> - err_mask = ata_read_log_page(dev, ATA_LOG_CDL, 0, ap->sector_buf, 1);
> - if (err_mask) {
> - ata_dev_warn(dev, "Read Command Duration Limits log failed\n");
> + /* CDL is supported: allocate and initialize needed resources. */
> + ret = ata_dev_init_cdl_resources(dev);
> + if (ret) {
> + ata_dev_warn(dev, "Initialize CDL resources failed\n");
> goto not_supported;
> }
>
> - memcpy(dev->cdl, ap->sector_buf, ATA_LOG_CDL_SIZE);
> dev->flags |= ATA_DFLAG_CDL;
>
> return;
>
> not_supported:
> dev->flags &= ~(ATA_DFLAG_CDL | ATA_DFLAG_CDL_ENABLED);
> - kfree(dev->ncq_sense_buf);
> - dev->ncq_sense_buf = NULL;
> + ata_dev_cleanup_cdl_resources(dev);
> }
>
> static int ata_dev_config_lba(struct ata_device *dev)
> diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c
> index 50ea254a213d..e05fb09af061 100644
> --- a/drivers/ata/libata-sata.c
> +++ b/drivers/ata/libata-sata.c
> @@ -1505,7 +1505,7 @@ int ata_eh_get_ncq_success_sense(struct ata_link *link)
> {
> struct ata_device *dev = link->device;
> struct ata_port *ap = dev->link->ap;
> - u8 *buf = dev->ncq_sense_buf;
> + u8 *buf = dev->cdl->ncq_sense_log_buf;
> struct ata_queued_cmd *qc;
> unsigned int err_mask, tag;
> u8 *sense, sk = 0, asc = 0, ascq = 0;
> diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
> index a3ffce4b218d..7fed924d6561 100644
> --- a/drivers/ata/libata-scsi.c
> +++ b/drivers/ata/libata-scsi.c
> @@ -2259,7 +2259,7 @@ static inline u16 ata_xlat_cdl_limit(u8 *buf)
> static unsigned int ata_msense_control_spgt2(struct ata_device *dev, u8 *buf,
> u8 spg)
> {
> - u8 *b, *cdl = dev->cdl, *desc;
> + u8 *b, *cdl = dev->cdl->desc_log_buf, *desc;
> u32 policy;
> int i;
>
> diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
> index 14f50c91ceb9..add230c0d51e 100644
> --- a/drivers/ata/libata-transport.c
> +++ b/drivers/ata/libata-transport.c
> @@ -671,9 +671,7 @@ static int ata_tdev_match(struct attribute_container *cont,
> */
> static void ata_tdev_free(struct ata_device *dev)
> {
> - kfree(dev->ncq_sense_buf);
> - dev->ncq_sense_buf = NULL;
> -
> + ata_dev_cleanup_cdl_resources(dev);
> transport_destroy_device(&dev->tdev);
> put_device(&dev->tdev);
> }
> diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
> index 5ca17784a350..df11f923e1a2 100644
> --- a/drivers/ata/libata.h
> +++ b/drivers/ata/libata.h
> @@ -89,6 +89,7 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
> extern const char *sata_spd_string(unsigned int spd);
> extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
> u8 page, void *buf, unsigned int sectors);
> +void ata_dev_cleanup_cdl_resources(struct ata_device *dev);
>
> #define to_ata_port(d) container_of(d, struct ata_port, tdev)
>
> diff --git a/include/linux/libata.h b/include/linux/libata.h
> index 3fb6980c8aa1..37a5509adc77 100644
> --- a/include/linux/libata.h
> +++ b/include/linux/libata.h
> @@ -700,6 +700,21 @@ struct ata_cpr_log {
> struct ata_cpr cpr[] __counted_by(nr_cpr);
> };
>
> +struct ata_cdl {
> + /*
> + * Buffer to cache the CDL log page 18h (command duration descriptors)
> + * for SCSI-ATA translation.
> + */
> + u8 desc_log_buf[ATA_LOG_CDL_SIZE];
> +
> + /*
> + * Buffer to handle reading the sense data for successful NCQ Commands
> + * log page for commands using a CDL with one of the limits policy set
> + * to 0xD (successful completion with sense data available bit set).
> + */
> + u8 ncq_sense_log_buf[ATA_LOG_SENSE_NCQ_SIZE];
> +};
> +
> struct ata_device {
> struct ata_link *link;
> unsigned int devno; /* 0 or 1 */
> @@ -763,8 +778,7 @@ struct ata_device {
> struct ata_cpr_log *cpr_log;
>
> /* Command Duration Limits support */
> - u8 *ncq_sense_buf;
> - u8 cdl[ATA_LOG_CDL_SIZE];
> + struct ata_cdl *cdl;
>
> /* error history */
> int spdn_cnt;
> --
> 2.46.0
>
next prev parent reply other threads:[~2024-08-26 15:37 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-26 7:30 [PATCH 0/7] Code cleanup and CDL memory usage reduction Damien Le Moal
2024-08-26 7:31 ` [PATCH 1/7] ata: libata: Fix ata_tdev_free() kdoc comment Damien Le Moal
2024-08-26 14:38 ` Niklas Cassel
2024-08-26 7:31 ` [PATCH 2/7] ata: libata: Improve __ata_qc_complete() Damien Le Moal
2024-08-26 14:39 ` Niklas Cassel
2024-08-26 7:31 ` [PATCH 3/7] ata: libata: Move sata_down_spd_limit() to libata-sata.c Damien Le Moal
2024-08-26 14:39 ` Niklas Cassel
2024-08-26 7:31 ` [PATCH 4/7] ata: libata: Move sata_std_hardreset() definition " Damien Le Moal
2024-08-26 14:39 ` Niklas Cassel
2024-08-26 7:31 ` [PATCH 5/7] ata: libata: Rename ata_eh_read_sense_success_ncq_log() Damien Le Moal
2024-08-26 14:39 ` Niklas Cassel
2024-08-26 7:31 ` [PATCH 6/7] ata: libata: Move ncq_sense_buf to struct ata_device Damien Le Moal
2024-08-26 14:48 ` Niklas Cassel
2024-08-27 7:50 ` Damien Le Moal
2024-08-27 9:21 ` Niklas Cassel
2024-08-26 7:31 ` [PATCH 7/7] ata: libata: Improve CDL resource management Damien Le Moal
2024-08-26 15:37 ` Niklas Cassel [this message]
2024-08-26 22:07 ` Damien Le Moal
2024-08-26 14:32 ` [PATCH 0/7] Code cleanup and CDL memory usage reduction Niklas Cassel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZsyhMdG_Z1o5EbFv@ryzen.lan \
--to=cassel@kernel.org \
--cc=dlemoal@kernel.org \
--cc=linux-ide@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.