[PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl

Stefan Hajnoczi posted 4 patches 5 days, 5 hours ago
There is a newer version of this series
[PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
Posted by Stefan Hajnoczi 5 days, 5 hours ago
Add a Persistent Reservations ioctl to read the list of currently
registered reservation keys. This calls the pr_ops->read_keys() function
that was previously added in commit c787f1baa503 ("block: Add PR
callouts for read keys and reservation") but was only used by the
in-kernel SCSI target so far.

The IOC_PR_READ_KEYS ioctl is necessary so that userspace applications
that rely on Persistent Reservations ioctls have a way of inspecting the
current state. Cluster managers and validation tests need this
functionality.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 include/uapi/linux/pr.h |  7 ++++++
 block/ioctl.c           | 51 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/include/uapi/linux/pr.h b/include/uapi/linux/pr.h
index d8126415966f3..fcb74eab92c80 100644
--- a/include/uapi/linux/pr.h
+++ b/include/uapi/linux/pr.h
@@ -56,6 +56,12 @@ struct pr_clear {
 	__u32	__pad;
 };
 
+struct pr_read_keys {
+	__u32	generation;
+	__u32	num_keys;
+	__u64	keys_ptr;
+};
+
 #define PR_FL_IGNORE_KEY	(1 << 0)	/* ignore existing key */
 
 #define IOC_PR_REGISTER		_IOW('p', 200, struct pr_registration)
@@ -64,5 +70,6 @@ struct pr_clear {
 #define IOC_PR_PREEMPT		_IOW('p', 203, struct pr_preempt)
 #define IOC_PR_PREEMPT_ABORT	_IOW('p', 204, struct pr_preempt)
 #define IOC_PR_CLEAR		_IOW('p', 205, struct pr_clear)
+#define IOC_PR_READ_KEYS	_IOWR('p', 206, struct pr_read_keys)
 
 #endif /* _UAPI_PR_H */
diff --git a/block/ioctl.c b/block/ioctl.c
index d7489a56b33c3..e87c424c15ae9 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/capability.h>
+#include <linux/cleanup.h>
 #include <linux/compat.h>
 #include <linux/blkdev.h>
 #include <linux/export.h>
@@ -423,6 +424,54 @@ static int blkdev_pr_clear(struct block_device *bdev, blk_mode_t mode,
 	return ops->pr_clear(bdev, c.key);
 }
 
+static int blkdev_pr_read_keys(struct block_device *bdev, blk_mode_t mode,
+		struct pr_read_keys __user *arg)
+{
+	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
+	struct pr_keys *keys_info __free(kfree) = NULL;
+	struct pr_read_keys inout;
+	int ret;
+
+	if (!blkdev_pr_allowed(bdev, mode))
+		return -EPERM;
+	if (!ops || !ops->pr_read_keys)
+		return -EOPNOTSUPP;
+
+	if (copy_from_user(&inout, arg, sizeof(inout)))
+		return -EFAULT;
+
+	if (inout.num_keys > -sizeof(*keys_info) / sizeof(keys_info->keys[0]))
+		return -EINVAL;
+
+	size_t keys_info_len = struct_size(keys_info, keys, inout.num_keys);
+
+	keys_info = kzalloc(keys_info_len, GFP_KERNEL);
+	if (!keys_info)
+		return -ENOMEM;
+
+	keys_info->num_keys = inout.num_keys;
+
+	ret = ops->pr_read_keys(bdev, keys_info);
+	if (ret)
+		return ret;
+
+	/* Copy out individual keys */
+	u64 __user *keys_ptr = u64_to_user_ptr(inout.keys_ptr);
+	u32 num_copy_keys = min(inout.num_keys, keys_info->num_keys);
+	size_t keys_copy_len = num_copy_keys * sizeof(keys_info->keys[0]);
+
+	if (copy_to_user(keys_ptr, keys_info->keys, keys_copy_len))
+		return -EFAULT;
+
+	/* Copy out the arg struct */
+	inout.generation = keys_info->generation;
+	inout.num_keys = keys_info->num_keys;
+
+	if (copy_to_user(arg, &inout, sizeof(inout)))
+		return -EFAULT;
+	return ret;
+}
+
 static int blkdev_flushbuf(struct block_device *bdev, unsigned cmd,
 		unsigned long arg)
 {
@@ -644,6 +693,8 @@ static int blkdev_common_ioctl(struct block_device *bdev, blk_mode_t mode,
 		return blkdev_pr_preempt(bdev, mode, argp, true);
 	case IOC_PR_CLEAR:
 		return blkdev_pr_clear(bdev, mode, argp);
+	case IOC_PR_READ_KEYS:
+		return blkdev_pr_read_keys(bdev, mode, argp);
 	default:
 		return blk_get_meta_cap(bdev, cmd, argp);
 	}
-- 
2.52.0
Re: [PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
Posted by Krzysztof Kozlowski 2 days, 8 hours ago
On 26/11/2025 17:35, Stefan Hajnoczi wrote:
> +
>  #define PR_FL_IGNORE_KEY	(1 << 0)	/* ignore existing key */
>  
>  #define IOC_PR_REGISTER		_IOW('p', 200, struct pr_registration)
> @@ -64,5 +70,6 @@ struct pr_clear {
>  #define IOC_PR_PREEMPT		_IOW('p', 203, struct pr_preempt)
>  #define IOC_PR_PREEMPT_ABORT	_IOW('p', 204, struct pr_preempt)
>  #define IOC_PR_CLEAR		_IOW('p', 205, struct pr_clear)
> +#define IOC_PR_READ_KEYS	_IOWR('p', 206, struct pr_read_keys)
>  
>  #endif /* _UAPI_PR_H */
> diff --git a/block/ioctl.c b/block/ioctl.c
> index d7489a56b33c3..e87c424c15ae9 100644
> --- a/block/ioctl.c
> +++ b/block/ioctl.c
> @@ -1,5 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0
>  #include <linux/capability.h>
> +#include <linux/cleanup.h>
>  #include <linux/compat.h>
>  #include <linux/blkdev.h>
>  #include <linux/export.h>
> @@ -423,6 +424,54 @@ static int blkdev_pr_clear(struct block_device *bdev, blk_mode_t mode,
>  	return ops->pr_clear(bdev, c.key);
>  }
>  
> +static int blkdev_pr_read_keys(struct block_device *bdev, blk_mode_t mode,
> +		struct pr_read_keys __user *arg)
> +{
> +	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
> +	struct pr_keys *keys_info __free(kfree) = NULL;


This is an undesired syntax explicitly documented as one to avoid. You
need here proper assignment, not NULL. Please don't use cleanup.h if you
do not intend to follow it because it does not make the code simpler.



Best regards,
Krzysztof
Re: [PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
Posted by Hannes Reinecke 4 days, 15 hours ago
On 11/26/25 17:35, Stefan Hajnoczi wrote:
> Add a Persistent Reservations ioctl to read the list of currently
> registered reservation keys. This calls the pr_ops->read_keys() function
> that was previously added in commit c787f1baa503 ("block: Add PR
> callouts for read keys and reservation") but was only used by the
> in-kernel SCSI target so far.
> 
> The IOC_PR_READ_KEYS ioctl is necessary so that userspace applications
> that rely on Persistent Reservations ioctls have a way of inspecting the
> current state. Cluster managers and validation tests need this
> functionality.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>   include/uapi/linux/pr.h |  7 ++++++
>   block/ioctl.c           | 51 +++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 58 insertions(+)
> 
> diff --git a/include/uapi/linux/pr.h b/include/uapi/linux/pr.h
> index d8126415966f3..fcb74eab92c80 100644
> --- a/include/uapi/linux/pr.h
> +++ b/include/uapi/linux/pr.h
> @@ -56,6 +56,12 @@ struct pr_clear {
>   	__u32	__pad;
>   };
>   
> +struct pr_read_keys {
> +	__u32	generation;
> +	__u32	num_keys;
> +	__u64	keys_ptr;
> +};
> +
>   #define PR_FL_IGNORE_KEY	(1 << 0)	/* ignore existing key */
>   
>   #define IOC_PR_REGISTER		_IOW('p', 200, struct pr_registration)
> @@ -64,5 +70,6 @@ struct pr_clear {
>   #define IOC_PR_PREEMPT		_IOW('p', 203, struct pr_preempt)
>   #define IOC_PR_PREEMPT_ABORT	_IOW('p', 204, struct pr_preempt)
>   #define IOC_PR_CLEAR		_IOW('p', 205, struct pr_clear)
> +#define IOC_PR_READ_KEYS	_IOWR('p', 206, struct pr_read_keys)
>   
>   #endif /* _UAPI_PR_H */
> diff --git a/block/ioctl.c b/block/ioctl.c
> index d7489a56b33c3..e87c424c15ae9 100644
> --- a/block/ioctl.c
> +++ b/block/ioctl.c
> @@ -1,5 +1,6 @@
>   // SPDX-License-Identifier: GPL-2.0
>   #include <linux/capability.h>
> +#include <linux/cleanup.h>
>   #include <linux/compat.h>
>   #include <linux/blkdev.h>
>   #include <linux/export.h>
> @@ -423,6 +424,54 @@ static int blkdev_pr_clear(struct block_device *bdev, blk_mode_t mode,
>   	return ops->pr_clear(bdev, c.key);
>   }
>   
> +static int blkdev_pr_read_keys(struct block_device *bdev, blk_mode_t mode,
> +		struct pr_read_keys __user *arg)
> +{
> +	const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
> +	struct pr_keys *keys_info __free(kfree) = NULL;
> +	struct pr_read_keys inout;
> +	int ret;
> +
> +	if (!blkdev_pr_allowed(bdev, mode))
> +		return -EPERM;
> +	if (!ops || !ops->pr_read_keys)
> +		return -EOPNOTSUPP;
> +
> +	if (copy_from_user(&inout, arg, sizeof(inout)))
> +		return -EFAULT;
> +
> +	if (inout.num_keys > -sizeof(*keys_info) / sizeof(keys_info->keys[0]))
> +		return -EINVAL;
> +

0-sizeof()? What's that supposed to achieve? Plus inout.numkeys is 
unsigned (as the kbuild robot indicated).

> +	size_t keys_info_len = struct_size(keys_info, keys, inout.num_keys);
> +
> +	keys_info = kzalloc(keys_info_len, GFP_KERNEL);
> +	if (!keys_info)
> +		return -ENOMEM;
> +
> +	keys_info->num_keys = inout.num_keys;
> +
> +	ret = ops->pr_read_keys(bdev, keys_info);
> +	if (ret)
> +		return ret;
> +
> +	/* Copy out individual keys */
> +	u64 __user *keys_ptr = u64_to_user_ptr(inout.keys_ptr);
> +	u32 num_copy_keys = min(inout.num_keys, keys_info->num_keys);
> +	size_t keys_copy_len = num_copy_keys * sizeof(keys_info->keys[0]);

We just had the discussion about variable declarations on the ksummit 
lists; I really would prefer to have all declarations at the start of 
the scope (read: at the start of the function here).

> +
> +	if (copy_to_user(keys_ptr, keys_info->keys, keys_copy_len))
> +		return -EFAULT;
> +
> +	/* Copy out the arg struct */
> +	inout.generation = keys_info->generation;
> +	inout.num_keys = keys_info->num_keys;
> +
> +	if (copy_to_user(arg, &inout, sizeof(inout)))
> +		return -EFAULT;
> +	return ret;
> +}
> +
>   static int blkdev_flushbuf(struct block_device *bdev, unsigned cmd,
>   		unsigned long arg)
>   {
> @@ -644,6 +693,8 @@ static int blkdev_common_ioctl(struct block_device *bdev, blk_mode_t mode,
>   		return blkdev_pr_preempt(bdev, mode, argp, true);
>   	case IOC_PR_CLEAR:
>   		return blkdev_pr_clear(bdev, mode, argp);
> +	case IOC_PR_READ_KEYS:
> +		return blkdev_pr_read_keys(bdev, mode, argp);
>   	default:
>   		return blk_get_meta_cap(bdev, cmd, argp);
>   	Cheers,Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.de                                +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich
Re: [PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
Posted by Krzysztof Kozlowski 2 days, 8 hours ago
On 27/11/2025 08:07, Hannes Reinecke wrote:
> 
>> +	size_t keys_info_len = struct_size(keys_info, keys, inout.num_keys);
>> +
>> +	keys_info = kzalloc(keys_info_len, GFP_KERNEL);
>> +	if (!keys_info)
>> +		return -ENOMEM;
>> +
>> +	keys_info->num_keys = inout.num_keys;
>> +
>> +	ret = ops->pr_read_keys(bdev, keys_info);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* Copy out individual keys */
>> +	u64 __user *keys_ptr = u64_to_user_ptr(inout.keys_ptr);
>> +	u32 num_copy_keys = min(inout.num_keys, keys_info->num_keys);
>> +	size_t keys_copy_len = num_copy_keys * sizeof(keys_info->keys[0]);
> 
> We just had the discussion about variable declarations on the ksummit 
> lists; I really would prefer to have all declarations at the start of 
> the scope (read: at the start of the function here).

Then also cleanup.h should not be used here.

Best regards,
Krzysztof
Re: [PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
Posted by Stefan Hajnoczi 7 hours ago
On Sat, Nov 29, 2025 at 03:32:35PM +0100, Krzysztof Kozlowski wrote:
> On 27/11/2025 08:07, Hannes Reinecke wrote:
> > 
> >> +	size_t keys_info_len = struct_size(keys_info, keys, inout.num_keys);
> >> +
> >> +	keys_info = kzalloc(keys_info_len, GFP_KERNEL);
> >> +	if (!keys_info)
> >> +		return -ENOMEM;
> >> +
> >> +	keys_info->num_keys = inout.num_keys;
> >> +
> >> +	ret = ops->pr_read_keys(bdev, keys_info);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	/* Copy out individual keys */
> >> +	u64 __user *keys_ptr = u64_to_user_ptr(inout.keys_ptr);
> >> +	u32 num_copy_keys = min(inout.num_keys, keys_info->num_keys);
> >> +	size_t keys_copy_len = num_copy_keys * sizeof(keys_info->keys[0]);
> > 
> > We just had the discussion about variable declarations on the ksummit 
> > lists; I really would prefer to have all declarations at the start of 
> > the scope (read: at the start of the function here).
> 
> Then also cleanup.h should not be used here.

Hi Krzysztof,
Christoph Hellwig replied to the v2 series, also against using __free().
Regardless of the reply I just sent to you about whether cleanup.h may
or may not be used in code that forbids declarations midway through a
scope, I will be dropping it in v3.

Thanks,
Stefan
Re: [PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
Posted by Krzysztof Kozlowski 6 hours ago
On 01/12/2025 16:14, Stefan Hajnoczi wrote:
> On Sat, Nov 29, 2025 at 03:32:35PM +0100, Krzysztof Kozlowski wrote:
>> On 27/11/2025 08:07, Hannes Reinecke wrote:
>>>
>>>> +	size_t keys_info_len = struct_size(keys_info, keys, inout.num_keys);
>>>> +
>>>> +	keys_info = kzalloc(keys_info_len, GFP_KERNEL);
>>>> +	if (!keys_info)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	keys_info->num_keys = inout.num_keys;
>>>> +
>>>> +	ret = ops->pr_read_keys(bdev, keys_info);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	/* Copy out individual keys */
>>>> +	u64 __user *keys_ptr = u64_to_user_ptr(inout.keys_ptr);
>>>> +	u32 num_copy_keys = min(inout.num_keys, keys_info->num_keys);
>>>> +	size_t keys_copy_len = num_copy_keys * sizeof(keys_info->keys[0]);
>>>
>>> We just had the discussion about variable declarations on the ksummit 
>>> lists; I really would prefer to have all declarations at the start of 
>>> the scope (read: at the start of the function here).
>>
>> Then also cleanup.h should not be used here.
> 
> Hi Krzysztof,
> Christoph Hellwig replied to the v2 series, also against using __free().

That's perfectly fine to dislike cleanup.h. It's fair. What is not fine
is using it against its recommendations. Either you take entire
cleanup.h with its oddities or don't use it.

> Regardless of the reply I just sent to you about whether cleanup.h may
> or may not be used in code that forbids declarations midway through a
> scope, I will be dropping it in v3.
> 

Best regards,
Krzysztof
Re: [PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
Posted by Stefan Hajnoczi 7 hours ago
On Sat, Nov 29, 2025 at 03:32:35PM +0100, Krzysztof Kozlowski wrote:
> On 27/11/2025 08:07, Hannes Reinecke wrote:
> > 
> >> +	size_t keys_info_len = struct_size(keys_info, keys, inout.num_keys);
> >> +
> >> +	keys_info = kzalloc(keys_info_len, GFP_KERNEL);
> >> +	if (!keys_info)
> >> +		return -ENOMEM;
> >> +
> >> +	keys_info->num_keys = inout.num_keys;
> >> +
> >> +	ret = ops->pr_read_keys(bdev, keys_info);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	/* Copy out individual keys */
> >> +	u64 __user *keys_ptr = u64_to_user_ptr(inout.keys_ptr);
> >> +	u32 num_copy_keys = min(inout.num_keys, keys_info->num_keys);
> >> +	size_t keys_copy_len = num_copy_keys * sizeof(keys_info->keys[0]);
> > 
> > We just had the discussion about variable declarations on the ksummit 
> > lists; I really would prefer to have all declarations at the start of 
> > the scope (read: at the start of the function here).
> 
> Then also cleanup.h should not be used here.

Hi Krzysztof,
The documentation in cleanup.h says:

 * Given that the "__free(...) = NULL" pattern for variables defined at
 * the top of the function poses this potential interdependency problem
 * the recommendation is to always define and assign variables in one
       ^^^^^^^^^^^^^^
 * statement and not group variable definitions at the top of the
 * function when __free() is used.

This is a recommendation, not mandatory. It is also describing a
scenario that does not apply here.

There are many examples of existing users of __free() initialized to
NULL:

  $ git grep '__free(' | grep ' = NULL' | wc -l
  491

To me it seems like it is okay to use cleanup.h in this fashion. Did I
miss something?

Thanks,
Stefan
Re: [PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
Posted by Krzysztof Kozlowski 6 hours ago
On 01/12/2025 16:06, Stefan Hajnoczi wrote:
> On Sat, Nov 29, 2025 at 03:32:35PM +0100, Krzysztof Kozlowski wrote:
>> On 27/11/2025 08:07, Hannes Reinecke wrote:
>>>
>>>> +	size_t keys_info_len = struct_size(keys_info, keys, inout.num_keys);
>>>> +
>>>> +	keys_info = kzalloc(keys_info_len, GFP_KERNEL);
>>>> +	if (!keys_info)
>>>> +		return -ENOMEM;
>>>> +
>>>> +	keys_info->num_keys = inout.num_keys;
>>>> +
>>>> +	ret = ops->pr_read_keys(bdev, keys_info);
>>>> +	if (ret)
>>>> +		return ret;
>>>> +
>>>> +	/* Copy out individual keys */
>>>> +	u64 __user *keys_ptr = u64_to_user_ptr(inout.keys_ptr);
>>>> +	u32 num_copy_keys = min(inout.num_keys, keys_info->num_keys);
>>>> +	size_t keys_copy_len = num_copy_keys * sizeof(keys_info->keys[0]);
>>>
>>> We just had the discussion about variable declarations on the ksummit 
>>> lists; I really would prefer to have all declarations at the start of 
>>> the scope (read: at the start of the function here).
>>
>> Then also cleanup.h should not be used here.
> 
> Hi Krzysztof,
> The documentation in cleanup.h says:
> 
>  * Given that the "__free(...) = NULL" pattern for variables defined at
>  * the top of the function poses this potential interdependency problem
>  * the recommendation is to always define and assign variables in one
>        ^^^^^^^^^^^^^^
>  * statement and not group variable definitions at the top of the
>  * function when __free() is used.
> 
> This is a recommendation, not mandatory. It is also describing a
> scenario that does not apply here.

If you have actual argument, so allocation in some if branch, the of course.

> 
> There are many examples of existing users of __free() initialized to
> NULL:
> 
>   $ git grep '__free(' | grep ' = NULL' | wc -l
>   491
> 

There is tons of incorrect usage, some I started already fixing.
Maintainers were changing when applying the correct code (correct patch)
into incorrect declaration without constructor and separate assignment.

Then contributors started adding patches at least making NULL
assignment, but still not following recommendation.

Then contributors started adding patches mixing cleanup.h with gotos,
also clearly discouraged.

Sorry, but please never use that argument. People did not read cleanup.h
and produced poor code. Maintainers did not read cleanup.h and changed
correct code into poor code.

Existing poor code, just its existence, is never the actual argument in
discussion.

> To me it seems like it is okay to use cleanup.h in this fashion. Did I
> miss something?



Best regards,
Krzysztof
Re: [PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
Posted by Stefan Hajnoczi 3 hours ago
On Mon, Dec 01, 2025 at 05:26:27PM +0100, Krzysztof Kozlowski wrote:
> On 01/12/2025 16:06, Stefan Hajnoczi wrote:
> > On Sat, Nov 29, 2025 at 03:32:35PM +0100, Krzysztof Kozlowski wrote:
> >> On 27/11/2025 08:07, Hannes Reinecke wrote:
> >>>
> >>>> +	size_t keys_info_len = struct_size(keys_info, keys, inout.num_keys);
> >>>> +
> >>>> +	keys_info = kzalloc(keys_info_len, GFP_KERNEL);
> >>>> +	if (!keys_info)
> >>>> +		return -ENOMEM;
> >>>> +
> >>>> +	keys_info->num_keys = inout.num_keys;
> >>>> +
> >>>> +	ret = ops->pr_read_keys(bdev, keys_info);
> >>>> +	if (ret)
> >>>> +		return ret;
> >>>> +
> >>>> +	/* Copy out individual keys */
> >>>> +	u64 __user *keys_ptr = u64_to_user_ptr(inout.keys_ptr);
> >>>> +	u32 num_copy_keys = min(inout.num_keys, keys_info->num_keys);
> >>>> +	size_t keys_copy_len = num_copy_keys * sizeof(keys_info->keys[0]);
> >>>
> >>> We just had the discussion about variable declarations on the ksummit 
> >>> lists; I really would prefer to have all declarations at the start of 
> >>> the scope (read: at the start of the function here).
> >>
> >> Then also cleanup.h should not be used here.
> > 
> > Hi Krzysztof,
> > The documentation in cleanup.h says:
> > 
> >  * Given that the "__free(...) = NULL" pattern for variables defined at
> >  * the top of the function poses this potential interdependency problem
> >  * the recommendation is to always define and assign variables in one
> >        ^^^^^^^^^^^^^^
> >  * statement and not group variable definitions at the top of the
> >  * function when __free() is used.
> > 
> > This is a recommendation, not mandatory. It is also describing a
> > scenario that does not apply here.
> 
> If you have actual argument, so allocation in some if branch, the of course.

I'm pointing out that the documentation uses the word "recommendation",
which is usually not considered mandatory but a suggestion.

Please update the documentation to clarify that __free() _must_ be
assigned the real value (no NULL initialization) so that it's clear this
is not a suggestion but mandatory.

Stefan
Re: [PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
Posted by kernel test robot 5 days, 4 hours ago
Hi Stefan,

kernel test robot noticed the following build warnings:

[auto build test WARNING on mkp-scsi/for-next]
[also build test WARNING on axboe/for-next jejb-scsi/for-next linus/master v6.18-rc7 next-20251126]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Stefan-Hajnoczi/scsi-sd-reject-invalid-pr_read_keys-num_keys-values/20251127-003756
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next
patch link:    https://lore.kernel.org/r/20251126163600.583036-4-stefanha%40redhat.com
patch subject: [PATCH 3/4] block: add IOC_PR_READ_KEYS ioctl
config: loongarch-allnoconfig (https://download.01.org/0day-ci/archive/20251127/202511270125.CJ6M2RHv-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9e9fe08b16ea2c4d9867fb4974edf2a3776d6ece)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251127/202511270125.CJ6M2RHv-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202511270125.CJ6M2RHv-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> block/ioctl.c:443:21: warning: result of comparison of constant 2305843009213693951 with expression of type '__u32' (aka 'unsigned int') is always false [-Wtautological-constant-out-of-range-compare]
     443 |         if (inout.num_keys > -sizeof(*keys_info) / sizeof(keys_info->keys[0]))
         |             ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   1 warning generated.


vim +443 block/ioctl.c

   426	
   427	static int blkdev_pr_read_keys(struct block_device *bdev, blk_mode_t mode,
   428			struct pr_read_keys __user *arg)
   429	{
   430		const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
   431		struct pr_keys *keys_info __free(kfree) = NULL;
   432		struct pr_read_keys inout;
   433		int ret;
   434	
   435		if (!blkdev_pr_allowed(bdev, mode))
   436			return -EPERM;
   437		if (!ops || !ops->pr_read_keys)
   438			return -EOPNOTSUPP;
   439	
   440		if (copy_from_user(&inout, arg, sizeof(inout)))
   441			return -EFAULT;
   442	
 > 443		if (inout.num_keys > -sizeof(*keys_info) / sizeof(keys_info->keys[0]))
   444			return -EINVAL;
   445	
   446		size_t keys_info_len = struct_size(keys_info, keys, inout.num_keys);
   447	
   448		keys_info = kzalloc(keys_info_len, GFP_KERNEL);
   449		if (!keys_info)
   450			return -ENOMEM;
   451	
   452		keys_info->num_keys = inout.num_keys;
   453	
   454		ret = ops->pr_read_keys(bdev, keys_info);
   455		if (ret)
   456			return ret;
   457	
   458		/* Copy out individual keys */
   459		u64 __user *keys_ptr = u64_to_user_ptr(inout.keys_ptr);
   460		u32 num_copy_keys = min(inout.num_keys, keys_info->num_keys);
   461		size_t keys_copy_len = num_copy_keys * sizeof(keys_info->keys[0]);
   462	
   463		if (copy_to_user(keys_ptr, keys_info->keys, keys_copy_len))
   464			return -EFAULT;
   465	
   466		/* Copy out the arg struct */
   467		inout.generation = keys_info->generation;
   468		inout.num_keys = keys_info->num_keys;
   469	
   470		if (copy_to_user(arg, &inout, sizeof(inout)))
   471			return -EFAULT;
   472		return ret;
   473	}
   474	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki