From: David Laight <david.laight.linux@gmail.com>
To: Mikulas Patocka <mpatocka@redhat.com>,
Tony Asleson <tasleson@redhat.com>,
"Bryn M . Reeves" <bmr@redhat.com>,
Alasdair Kergon <agk@redhat.com>,
Mike Snitzer <snitzer@kernel.org>,
Benjamin Marzinski <bmarzins@redhat.com>,
dm-devel@lists.linux.dev, linux-kernel@vger.kernel.org
Cc: David Laight <david.laight.linux@gmail.com>
Subject: [PATCH 1/3] dm: __list_versions(): Only process targets once
Date: Wed, 24 Jun 2026 15:52:41 +0100 [thread overview]
Message-ID: <20260624145243.2736-2-david.laight.linux@gmail.com> (raw)
In-Reply-To: <20260624145243.2736-1-david.laight.linux@gmail.com>
Instead of doing a prescan to determine the length of buffer required,
checking the supplied buffer is big enough, and then doing a second
scan to fill the output buffer just do a single scan and detect when
the buffer is too short.
This removes any problems that might occur if a 'target' is added
between the scans.
For additional safety only call strlen(tt->name) once and use the
returned length for everything (incuding the copy).
Ensure than all the pad bytes between the entries are zero.
Set param->data_size to the actual size of the data.
It was slightly large because ALIGN_MASK was added in instead of the size
being rounded up.
Signed-off-by: David Laight <david.laight.linux@gmail.com>
---
This seems to be the only code that uses dm_target_iterate() and the
dm_get_target_type() call is just a linear scan of the same list that
replaces the lock() with MODULE_GET().
It would all be simpler with a loop here that scanned the list,
but the required locking primitives aren't exposed.
Changing that is a larger change that I wanted to do now.
drivers/md/dm-ioctl.c | 73 +++++++++++++++++--------------------------
1 file changed, 29 insertions(+), 44 deletions(-)
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index a529174c94cf..6234cb8b86b7 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -54,10 +54,8 @@ struct hash_cell {
};
struct vers_iter {
- size_t param_size;
struct dm_target_versions *vers, *old_vers;
char *end;
- uint32_t flags;
};
@@ -684,41 +682,38 @@ static int list_devices(struct file *filp, struct dm_ioctl *param, size_t param_
return 0;
}
-static void list_version_get_needed(struct target_type *tt, void *needed_param)
-{
- size_t *needed = needed_param;
-
- *needed += sizeof(struct dm_target_versions);
- *needed += strlen(tt->name) + 1;
- *needed += ALIGN_MASK;
-}
-
static void list_version_get_info(struct target_type *tt, void *param)
{
struct vers_iter *info = param;
+ struct dm_target_versions *vers = info->vers;
+ size_t name_len = strlen(tt->name);
+
+ if (!vers)
+ return;
- /* Check space - it might have changed since the first iteration */
- if ((char *)info->vers + sizeof(tt->version) + strlen(tt->name) + 1 > info->end) {
- info->flags = DM_BUFFER_FULL_FLAG;
+ info->old_vers = vers;
+ info->vers = align_ptr((void *)(info->vers + 1) + name_len + 1);
+
+ /* Check space */
+ if ((char *)info->vers > info->end) {
+ info->vers = NULL;
return;
}
- if (info->old_vers)
- info->old_vers->next = (uint32_t) ((void *)info->vers - (void *)info->old_vers);
+ /* Zero padding and terminate vers->name[] */
+ ((u64 *)info->vers)[-1] = 0;
- info->vers->version[0] = tt->version[0];
- info->vers->version[1] = tt->version[1];
- info->vers->version[2] = tt->version[2];
- info->vers->next = 0;
- strcpy(info->vers->name, tt->name);
+ vers->next = (char *)info->vers - (char *)vers;
- info->old_vers = info->vers;
- info->vers = align_ptr((void *)(info->vers + 1) + strlen(tt->name) + 1);
+ vers->version[0] = tt->version[0];
+ vers->version[1] = tt->version[1];
+ vers->version[2] = tt->version[2];
+ memcpy(vers->name, tt->name, name_len);
}
static int __list_versions(struct dm_ioctl *param, size_t param_size, const char *name)
{
- size_t len, needed = 0;
+ size_t len;
struct dm_target_versions *vers;
struct vers_iter iter_info;
struct target_type *tt = NULL;
@@ -729,41 +724,31 @@ static int __list_versions(struct dm_ioctl *param, size_t param_size, const char
return -EINVAL;
}
- /*
- * Loop through all the devices working out how much
- * space we need.
- */
- if (!tt)
- dm_target_iterate(list_version_get_needed, &needed);
- else
- list_version_get_needed(tt, &needed);
-
/*
* Grab our output buffer.
*/
vers = get_result_buffer(param, param_size, &len);
- if (len < needed) {
- param->flags |= DM_BUFFER_FULL_FLAG;
- goto out;
- }
- param->data_size = param->data_start + needed;
- iter_info.param_size = param_size;
iter_info.old_vers = NULL;
iter_info.vers = vers;
- iter_info.flags = 0;
- iter_info.end = (char *)vers + needed;
+ iter_info.end = (char *)vers + len;
/*
- * Now loop through filling out the names & versions.
+ * Loop through filling out the names & versions.
*/
if (!tt)
dm_target_iterate(list_version_get_info, &iter_info);
else
list_version_get_info(tt, &iter_info);
- param->flags |= iter_info.flags;
- out:
+ if (iter_info.vers) {
+ if (iter_info.old_vers)
+ iter_info.old_vers->next = 0;
+ param->data_size = param->data_start + ((char *)iter_info.vers - (char *)vers);
+ } else {
+ param->flags |= DM_BUFFER_FULL_FLAG;
+ }
+
if (tt)
dm_put_target_type(tt);
return 0;
--
2.39.5
next prev parent reply other threads:[~2026-06-24 14:52 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-24 14:52 [PATCH 0/3] dm: simplify list ioctls David Laight
2026-06-24 14:52 ` David Laight [this message]
2026-06-24 14:52 ` [PATCH 2/3] dm: list_devices(): Only process devices once David Laight
2026-06-24 14:52 ` [PATCH 3/3] dm: lookup_ioctl(): Use designated array initialers David Laight
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=20260624145243.2736-2-david.laight.linux@gmail.com \
--to=david.laight.linux@gmail.com \
--cc=agk@redhat.com \
--cc=bmarzins@redhat.com \
--cc=bmr@redhat.com \
--cc=dm-devel@lists.linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=mpatocka@redhat.com \
--cc=snitzer@kernel.org \
--cc=tasleson@redhat.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox