linux-integrity.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] tpm: Fix the timeout & use ktime
@ 2025-06-20 18:08 Orlov, Ivan
  2025-06-20 22:03 ` Orlov, Ivan
  2025-06-22 20:52 ` Jonathan McDowell
  0 siblings, 2 replies; 11+ messages in thread
From: Orlov, Ivan @ 2025-06-20 18:08 UTC (permalink / raw)
  To: peterhuewe@gmx.de, jarkko@kernel.org
  Cc: Orlov, Ivan, jgg@ziepe.ca, linux-integrity@vger.kernel.org,
	linux-kernel@vger.kernel.org, Woodhouse, David, noodles@earth.li

The current implementation of timeout detection works in the following
way:

1. Read completion status. If completed, return the data
2. Sleep for some time (usleep_range)
3. Check for timeout using current jiffies value. Return an error if
   timed out
4. Goto 1

usleep_range doesn't guarantee it's always going to wake up strictly in
(min, max) range, so such a situation is possible:

1. Driver reads completion status. No completion yet
2. Process sleeps indefinitely. In the meantime, TPM responds
3. We check for timeout without checking for the completion again.
   Result is lost.

Such a situation also happens for the guest VMs: if vCPU goes to sleep
and doesn't get scheduled for some time, the guest TPM driver will
timeout instantly after waking up without checking for the completion
(which may already be in place).

Perform the completion check once again after exiting the busy loop in
order to give the device the last chance to send us some data.

Since now we check for completion in two places, extract this check into
a separate function.

Signed-off-by: Ivan Orlov <iorlov@amazon.com>
---
V1 -> V2:
- Exclude the jiffies -> ktime change from the patch
- Instead of recording the time before checking for completion, check
  for completion once again after leaving the loop

 drivers/char/tpm/tpm-interface.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 8d7e4da6ed53..6960ee2798e1 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -82,6 +82,13 @@ static bool tpm_chip_req_canceled(struct tpm_chip *chip, u8 status)
 	return chip->ops->req_canceled(chip, status);
 }
 
+static bool tpm_transmit_completed(struct tpm_chip *chip)
+{
+	u8 status_masked = tpm_chip_status(chip) & chip->ops->req_complete_mask;
+
+	return status_masked == chip->ops->req_complete_val;
+}
+
 static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
 {
 	struct tpm_header *header = buf;
@@ -129,8 +136,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
 	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
 	do {
 		u8 status = tpm_chip_status(chip);
-		if ((status & chip->ops->req_complete_mask) ==
-		    chip->ops->req_complete_val)
+		if (tpm_transmit_completed(chip))
 			goto out_recv;
 
 		if (tpm_chip_req_canceled(chip, status)) {
@@ -142,6 +148,13 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
 		rmb();
 	} while (time_before(jiffies, stop));
 
+	/*
+	 * Check for completion one more time, just in case the device reported
+	 * it while the driver was sleeping in the busy loop above.
+	 */
+	if (tpm_transmit_completed(chip))
+		goto out_recv;
+
 	tpm_chip_cancel(chip);
 	dev_err(&chip->dev, "Operation Timed out\n");
 	return -ETIME;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] tpm: Fix the timeout & use ktime
  2025-06-20 18:08 [PATCH v2] tpm: Fix the timeout & use ktime Orlov, Ivan
@ 2025-06-20 22:03 ` Orlov, Ivan
  2025-06-22 20:52 ` Jonathan McDowell
  1 sibling, 0 replies; 11+ messages in thread
From: Orlov, Ivan @ 2025-06-20 22:03 UTC (permalink / raw)
  To: Orlov, Ivan, peterhuewe@gmx.de, jarkko@kernel.org
  Cc: jgg@ziepe.ca, linux-integrity@vger.kernel.org,
	linux-kernel@vger.kernel.org, Woodhouse, David, noodles@earth.li

On 20/06/2025 19:08, Orlov, Ivan wrote:
> The current implementation of timeout detection works in the following
> way:

Ah, I forgot to remove "& use ktime" from the commit title. If there are 
any comments regarding the patch content, I'll fix it in V3. Otherwise, 
I'd kindly ask to fix it when applying. Thanks!

--
Kind Regards,
Ivan Orlov

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] tpm: Fix the timeout & use ktime
  2025-06-20 18:08 [PATCH v2] tpm: Fix the timeout & use ktime Orlov, Ivan
  2025-06-20 22:03 ` Orlov, Ivan
@ 2025-06-22 20:52 ` Jonathan McDowell
  2025-06-25 16:43   ` Jarkko Sakkinen
  1 sibling, 1 reply; 11+ messages in thread
From: Jonathan McDowell @ 2025-06-22 20:52 UTC (permalink / raw)
  To: Orlov, Ivan
  Cc: peterhuewe@gmx.de, jarkko@kernel.org, jgg@ziepe.ca,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	Woodhouse, David

On Fri, Jun 20, 2025 at 06:08:31PM +0000, Orlov, Ivan wrote:
>The current implementation of timeout detection works in the following
>way:
>
>1. Read completion status. If completed, return the data
>2. Sleep for some time (usleep_range)
>3. Check for timeout using current jiffies value. Return an error if
>   timed out
>4. Goto 1
>
>usleep_range doesn't guarantee it's always going to wake up strictly in
>(min, max) range, so such a situation is possible:
>
>1. Driver reads completion status. No completion yet
>2. Process sleeps indefinitely. In the meantime, TPM responds
>3. We check for timeout without checking for the completion again.
>   Result is lost.
>
>Such a situation also happens for the guest VMs: if vCPU goes to sleep
>and doesn't get scheduled for some time, the guest TPM driver will
>timeout instantly after waking up without checking for the completion
>(which may already be in place).
>
>Perform the completion check once again after exiting the busy loop in
>order to give the device the last chance to send us some data.
>
>Since now we check for completion in two places, extract this check into
>a separate function.
>
>Signed-off-by: Ivan Orlov <iorlov@amazon.com>
>---
>V1 -> V2:
>- Exclude the jiffies -> ktime change from the patch
>- Instead of recording the time before checking for completion, check
>  for completion once again after leaving the loop
>
> drivers/char/tpm/tpm-interface.c | 17 +++++++++++++++--
> 1 file changed, 15 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
>index 8d7e4da6ed53..6960ee2798e1 100644
>--- a/drivers/char/tpm/tpm-interface.c
>+++ b/drivers/char/tpm/tpm-interface.c
>@@ -82,6 +82,13 @@ static bool tpm_chip_req_canceled(struct tpm_chip *chip, u8 status)
> 	return chip->ops->req_canceled(chip, status);
> }
>
>+static bool tpm_transmit_completed(struct tpm_chip *chip)
>+{
>+	u8 status_masked = tpm_chip_status(chip) & chip->ops->req_complete_mask;
>+
>+	return status_masked == chip->ops->req_complete_val;
>+}
>+
> static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> {
> 	struct tpm_header *header = buf;
>@@ -129,8 +136,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> 	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> 	do {
> 		u8 status = tpm_chip_status(chip);
>-		if ((status & chip->ops->req_complete_mask) ==
>-		    chip->ops->req_complete_val)
>+		if (tpm_transmit_completed(chip))
> 			goto out_recv;

The only thing I'd point out here is we end up doing a double status 
read one after the other (once here, once in tpm_transmit_completed), 
and I'm pretty sure I've seen instances where that caused a problem.

> 		if (tpm_chip_req_canceled(chip, status)) {
>@@ -142,6 +148,13 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> 		rmb();
> 	} while (time_before(jiffies, stop));
>
>+	/*
>+	 * Check for completion one more time, just in case the device reported
>+	 * it while the driver was sleeping in the busy loop above.
>+	 */
>+	if (tpm_transmit_completed(chip))
>+		goto out_recv;
>+
> 	tpm_chip_cancel(chip);
> 	dev_err(&chip->dev, "Operation Timed out\n");
> 	return -ETIME;

J.

-- 
She's the one for me. She's all I really need, oh yeah.
This .sig brought to you by the letter K and the number  3
Product of the Republic of HuggieTag

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] tpm: Fix the timeout & use ktime
  2025-06-22 20:52 ` Jonathan McDowell
@ 2025-06-25 16:43   ` Jarkko Sakkinen
  2025-06-25 16:49     ` Jarkko Sakkinen
  2025-07-04  9:02     ` Jonathan McDowell
  0 siblings, 2 replies; 11+ messages in thread
From: Jarkko Sakkinen @ 2025-06-25 16:43 UTC (permalink / raw)
  To: Jonathan McDowell
  Cc: Orlov, Ivan, peterhuewe@gmx.de, jgg@ziepe.ca,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	Woodhouse, David

On Sun, Jun 22, 2025 at 09:52:58PM +0100, Jonathan McDowell wrote:
> On Fri, Jun 20, 2025 at 06:08:31PM +0000, Orlov, Ivan wrote:
> > The current implementation of timeout detection works in the following
> > way:
> > 
> > 1. Read completion status. If completed, return the data
> > 2. Sleep for some time (usleep_range)
> > 3. Check for timeout using current jiffies value. Return an error if
> >   timed out
> > 4. Goto 1
> > 
> > usleep_range doesn't guarantee it's always going to wake up strictly in
> > (min, max) range, so such a situation is possible:
> > 
> > 1. Driver reads completion status. No completion yet
> > 2. Process sleeps indefinitely. In the meantime, TPM responds
> > 3. We check for timeout without checking for the completion again.
> >   Result is lost.
> > 
> > Such a situation also happens for the guest VMs: if vCPU goes to sleep
> > and doesn't get scheduled for some time, the guest TPM driver will
> > timeout instantly after waking up without checking for the completion
> > (which may already be in place).
> > 
> > Perform the completion check once again after exiting the busy loop in
> > order to give the device the last chance to send us some data.
> > 
> > Since now we check for completion in two places, extract this check into
> > a separate function.
> > 
> > Signed-off-by: Ivan Orlov <iorlov@amazon.com>
> > ---
> > V1 -> V2:
> > - Exclude the jiffies -> ktime change from the patch
> > - Instead of recording the time before checking for completion, check
> >  for completion once again after leaving the loop
> > 
> > drivers/char/tpm/tpm-interface.c | 17 +++++++++++++++--
> > 1 file changed, 15 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> > index 8d7e4da6ed53..6960ee2798e1 100644
> > --- a/drivers/char/tpm/tpm-interface.c
> > +++ b/drivers/char/tpm/tpm-interface.c
> > @@ -82,6 +82,13 @@ static bool tpm_chip_req_canceled(struct tpm_chip *chip, u8 status)
> > 	return chip->ops->req_canceled(chip, status);
> > }
> > 
> > +static bool tpm_transmit_completed(struct tpm_chip *chip)
> > +{
> > +	u8 status_masked = tpm_chip_status(chip) & chip->ops->req_complete_mask;
> > +
> > +	return status_masked == chip->ops->req_complete_val;
> > +}
> > +
> > static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> > {
> > 	struct tpm_header *header = buf;
> > @@ -129,8 +136,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> > 	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> > 	do {
> > 		u8 status = tpm_chip_status(chip);
> > -		if ((status & chip->ops->req_complete_mask) ==
> > -		    chip->ops->req_complete_val)
> > +		if (tpm_transmit_completed(chip))
> > 			goto out_recv;
> 
> The only thing I'd point out here is we end up doing a double status read
> one after the other (once here, once in tpm_transmit_completed), and I'm
> pretty sure I've seen instances where that caused a problem.

It would be easy to to prevent at least double reads after completion
e.g., in tpm_chip_status():

/*
 * Read the chip status bitmask. After completion, the returned will mask will
 * return value cached at the point of completion up until the next transmit.
 */
static u8 tpm_chip_status(struct tpm_chip *chip)
{
	u8 status_masked = chip->status & chip->ops_req_complete_mask;

	if (status_masked == chip->ops->req_complete_val)
		return chip->status;

	chip->status = tpm_chip_status(chip);

	return chip->status;
}

I think tpm_chip_status() should be the gatekeeper for such event, or
like the correct layer of abstraction here ...

Then just reset chip->status to zero at the beginning of tpm_try_transmit().

BR, Jarkko

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] tpm: Fix the timeout & use ktime
  2025-06-25 16:43   ` Jarkko Sakkinen
@ 2025-06-25 16:49     ` Jarkko Sakkinen
  2025-07-04  9:02     ` Jonathan McDowell
  1 sibling, 0 replies; 11+ messages in thread
From: Jarkko Sakkinen @ 2025-06-25 16:49 UTC (permalink / raw)
  To: Jonathan McDowell
  Cc: Orlov, Ivan, peterhuewe@gmx.de, jgg@ziepe.ca,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	Woodhouse, David

On Wed, Jun 25, 2025 at 07:43:11PM +0300, Jarkko Sakkinen wrote:
> On Sun, Jun 22, 2025 at 09:52:58PM +0100, Jonathan McDowell wrote:
> > On Fri, Jun 20, 2025 at 06:08:31PM +0000, Orlov, Ivan wrote:
> > > The current implementation of timeout detection works in the following
> > > way:
> > > 
> > > 1. Read completion status. If completed, return the data
> > > 2. Sleep for some time (usleep_range)
> > > 3. Check for timeout using current jiffies value. Return an error if
> > >   timed out
> > > 4. Goto 1
> > > 
> > > usleep_range doesn't guarantee it's always going to wake up strictly in
> > > (min, max) range, so such a situation is possible:
> > > 
> > > 1. Driver reads completion status. No completion yet
> > > 2. Process sleeps indefinitely. In the meantime, TPM responds
> > > 3. We check for timeout without checking for the completion again.
> > >   Result is lost.
> > > 
> > > Such a situation also happens for the guest VMs: if vCPU goes to sleep
> > > and doesn't get scheduled for some time, the guest TPM driver will
> > > timeout instantly after waking up without checking for the completion
> > > (which may already be in place).
> > > 
> > > Perform the completion check once again after exiting the busy loop in
> > > order to give the device the last chance to send us some data.
> > > 
> > > Since now we check for completion in two places, extract this check into
> > > a separate function.
> > > 
> > > Signed-off-by: Ivan Orlov <iorlov@amazon.com>
> > > ---
> > > V1 -> V2:
> > > - Exclude the jiffies -> ktime change from the patch
> > > - Instead of recording the time before checking for completion, check
> > >  for completion once again after leaving the loop
> > > 
> > > drivers/char/tpm/tpm-interface.c | 17 +++++++++++++++--
> > > 1 file changed, 15 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> > > index 8d7e4da6ed53..6960ee2798e1 100644
> > > --- a/drivers/char/tpm/tpm-interface.c
> > > +++ b/drivers/char/tpm/tpm-interface.c
> > > @@ -82,6 +82,13 @@ static bool tpm_chip_req_canceled(struct tpm_chip *chip, u8 status)
> > > 	return chip->ops->req_canceled(chip, status);
> > > }
> > > 
> > > +static bool tpm_transmit_completed(struct tpm_chip *chip)
> > > +{
> > > +	u8 status_masked = tpm_chip_status(chip) & chip->ops->req_complete_mask;
> > > +
> > > +	return status_masked == chip->ops->req_complete_val;
> > > +}
> > > +
> > > static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> > > {
> > > 	struct tpm_header *header = buf;
> > > @@ -129,8 +136,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> > > 	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> > > 	do {
> > > 		u8 status = tpm_chip_status(chip);
> > > -		if ((status & chip->ops->req_complete_mask) ==
> > > -		    chip->ops->req_complete_val)
> > > +		if (tpm_transmit_completed(chip))
> > > 			goto out_recv;
> > 
> > The only thing I'd point out here is we end up doing a double status read
> > one after the other (once here, once in tpm_transmit_completed), and I'm
> > pretty sure I've seen instances where that caused a problem.
> 
> It would be easy to to prevent at least double reads after completion
> e.g., in tpm_chip_status():
> 
> /*
>  * Read the chip status bitmask. After completion, the returned will mask will
>  * return value cached at the point of completion up until the next transmit.
>  */
> static u8 tpm_chip_status(struct tpm_chip *chip)
> {
> 	u8 status_masked = chip->status & chip->ops_req_complete_mask;
> 
> 	if (status_masked == chip->ops->req_complete_val)
> 		return chip->status;
> 
> 	chip->status = tpm_chip_status(chip);

OOPS:

	chip->status = chip->ops->status(chip);

Couple of additional constraints:

1. tpm_chip_alloc() should initialize chip->status to chip->ops->req_complete_mask.
2. tpm_try_transmit() should reset the value to chip->ops->req_complete_mask on
   failure paths.

With these constraints there is framework where chip->ops->status() is
only invoked when it actually makes sense i.e., only during the course
of tpm_try_trasmit().

BR, Jarkko

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] tpm: Fix the timeout & use ktime
  2025-06-25 16:43   ` Jarkko Sakkinen
  2025-06-25 16:49     ` Jarkko Sakkinen
@ 2025-07-04  9:02     ` Jonathan McDowell
  2025-07-04 15:16       ` Jarkko Sakkinen
  1 sibling, 1 reply; 11+ messages in thread
From: Jonathan McDowell @ 2025-07-04  9:02 UTC (permalink / raw)
  To: Jarkko Sakkinen
  Cc: Orlov, Ivan, peterhuewe@gmx.de, jgg@ziepe.ca,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	Woodhouse, David

On Wed, Jun 25, 2025 at 07:43:07PM +0300, Jarkko Sakkinen wrote:
>On Sun, Jun 22, 2025 at 09:52:58PM +0100, Jonathan McDowell wrote:
>> On Fri, Jun 20, 2025 at 06:08:31PM +0000, Orlov, Ivan wrote:
>> > The current implementation of timeout detection works in the following
>> > way:
>> >
>> > 1. Read completion status. If completed, return the data
>> > 2. Sleep for some time (usleep_range)
>> > 3. Check for timeout using current jiffies value. Return an error if
>> >   timed out
>> > 4. Goto 1
>> >
>> > usleep_range doesn't guarantee it's always going to wake up strictly in
>> > (min, max) range, so such a situation is possible:
>> >
>> > 1. Driver reads completion status. No completion yet
>> > 2. Process sleeps indefinitely. In the meantime, TPM responds
>> > 3. We check for timeout without checking for the completion again.
>> >   Result is lost.
>> >
>> > Such a situation also happens for the guest VMs: if vCPU goes to sleep
>> > and doesn't get scheduled for some time, the guest TPM driver will
>> > timeout instantly after waking up without checking for the completion
>> > (which may already be in place).
>> >
>> > Perform the completion check once again after exiting the busy loop in
>> > order to give the device the last chance to send us some data.
>> >
>> > Since now we check for completion in two places, extract this check into
>> > a separate function.
>> >
>> > Signed-off-by: Ivan Orlov <iorlov@amazon.com>
>> > ---
>> > V1 -> V2:
>> > - Exclude the jiffies -> ktime change from the patch
>> > - Instead of recording the time before checking for completion, check
>> >  for completion once again after leaving the loop
>> >
>> > drivers/char/tpm/tpm-interface.c | 17 +++++++++++++++--
>> > 1 file changed, 15 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
>> > index 8d7e4da6ed53..6960ee2798e1 100644
>> > --- a/drivers/char/tpm/tpm-interface.c
>> > +++ b/drivers/char/tpm/tpm-interface.c
>> > @@ -82,6 +82,13 @@ static bool tpm_chip_req_canceled(struct tpm_chip *chip, u8 status)
>> > 	return chip->ops->req_canceled(chip, status);
>> > }
>> >
>> > +static bool tpm_transmit_completed(struct tpm_chip *chip)
>> > +{
>> > +	u8 status_masked = tpm_chip_status(chip) & chip->ops->req_complete_mask;
>> > +
>> > +	return status_masked == chip->ops->req_complete_val;
>> > +}
>> > +
>> > static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
>> > {
>> > 	struct tpm_header *header = buf;
>> > @@ -129,8 +136,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
>> > 	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
>> > 	do {
>> > 		u8 status = tpm_chip_status(chip);
>> > -		if ((status & chip->ops->req_complete_mask) ==
>> > -		    chip->ops->req_complete_val)
>> > +		if (tpm_transmit_completed(chip))
>> > 			goto out_recv;
>>
>> The only thing I'd point out here is we end up doing a double status read
>> one after the other (once here, once in tpm_transmit_completed), and I'm
>> pretty sure I've seen instances where that caused a problem.
>
>It would be easy to to prevent at least double reads after completion
>e.g., in tpm_chip_status():

Or just take the simple approach and make the check after the while 
loop:

	if ((tpm_chip_status(chip) & chip->ops->req_complete_mask) ==
	    chip->ops->req_complete_val)
		goto out_recv;

There might be potential for a longer term cleanup using chip->status to 
cache things, but I'm little concerned that's going to open paths where 
we might not correctly update it, so I think it should be a separate 
piece.

(I'm motivated by the fact we've started to see the "Operation Canceled" 
error and I'd like us to close on the best way to fix it. :) )

J.

-- 
I am afraid of the dark.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] tpm: Fix the timeout & use ktime
  2025-07-04  9:02     ` Jonathan McDowell
@ 2025-07-04 15:16       ` Jarkko Sakkinen
  2025-07-04 15:39         ` Orlov, Ivan
  0 siblings, 1 reply; 11+ messages in thread
From: Jarkko Sakkinen @ 2025-07-04 15:16 UTC (permalink / raw)
  To: Jonathan McDowell
  Cc: Orlov, Ivan, peterhuewe@gmx.de, jgg@ziepe.ca,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	Woodhouse, David

On Fri, Jul 04, 2025 at 10:02:33AM +0100, Jonathan McDowell wrote:
> On Wed, Jun 25, 2025 at 07:43:07PM +0300, Jarkko Sakkinen wrote:
> > On Sun, Jun 22, 2025 at 09:52:58PM +0100, Jonathan McDowell wrote:
> > > On Fri, Jun 20, 2025 at 06:08:31PM +0000, Orlov, Ivan wrote:
> > > > The current implementation of timeout detection works in the following
> > > > way:
> > > >
> > > > 1. Read completion status. If completed, return the data
> > > > 2. Sleep for some time (usleep_range)
> > > > 3. Check for timeout using current jiffies value. Return an error if
> > > >   timed out
> > > > 4. Goto 1
> > > >
> > > > usleep_range doesn't guarantee it's always going to wake up strictly in
> > > > (min, max) range, so such a situation is possible:
> > > >
> > > > 1. Driver reads completion status. No completion yet
> > > > 2. Process sleeps indefinitely. In the meantime, TPM responds
> > > > 3. We check for timeout without checking for the completion again.
> > > >   Result is lost.
> > > >
> > > > Such a situation also happens for the guest VMs: if vCPU goes to sleep
> > > > and doesn't get scheduled for some time, the guest TPM driver will
> > > > timeout instantly after waking up without checking for the completion
> > > > (which may already be in place).
> > > >
> > > > Perform the completion check once again after exiting the busy loop in
> > > > order to give the device the last chance to send us some data.
> > > >
> > > > Since now we check for completion in two places, extract this check into
> > > > a separate function.
> > > >
> > > > Signed-off-by: Ivan Orlov <iorlov@amazon.com>
> > > > ---
> > > > V1 -> V2:
> > > > - Exclude the jiffies -> ktime change from the patch
> > > > - Instead of recording the time before checking for completion, check
> > > >  for completion once again after leaving the loop
> > > >
> > > > drivers/char/tpm/tpm-interface.c | 17 +++++++++++++++--
> > > > 1 file changed, 15 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> > > > index 8d7e4da6ed53..6960ee2798e1 100644
> > > > --- a/drivers/char/tpm/tpm-interface.c
> > > > +++ b/drivers/char/tpm/tpm-interface.c
> > > > @@ -82,6 +82,13 @@ static bool tpm_chip_req_canceled(struct tpm_chip *chip, u8 status)
> > > > 	return chip->ops->req_canceled(chip, status);
> > > > }
> > > >
> > > > +static bool tpm_transmit_completed(struct tpm_chip *chip)
> > > > +{
> > > > +	u8 status_masked = tpm_chip_status(chip) & chip->ops->req_complete_mask;
> > > > +
> > > > +	return status_masked == chip->ops->req_complete_val;
> > > > +}
> > > > +
> > > > static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> > > > {
> > > > 	struct tpm_header *header = buf;
> > > > @@ -129,8 +136,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> > > > 	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> > > > 	do {
> > > > 		u8 status = tpm_chip_status(chip);
> > > > -		if ((status & chip->ops->req_complete_mask) ==
> > > > -		    chip->ops->req_complete_val)
> > > > +		if (tpm_transmit_completed(chip))
> > > > 			goto out_recv;
> > > 
> > > The only thing I'd point out here is we end up doing a double status read
> > > one after the other (once here, once in tpm_transmit_completed), and I'm
> > > pretty sure I've seen instances where that caused a problem.
> > 
> > It would be easy to to prevent at least double reads after completion
> > e.g., in tpm_chip_status():
> 
> Or just take the simple approach and make the check after the while loop:
> 
> 	if ((tpm_chip_status(chip) & chip->ops->req_complete_mask) ==
> 	    chip->ops->req_complete_val)
> 		goto out_recv;
> 
> There might be potential for a longer term cleanup using chip->status to
> cache things, but I'm little concerned that's going to open paths where we
> might not correctly update it, so I think it should be a separate piece.
> 
> (I'm motivated by the fact we've started to see the "Operation Canceled"
> error and I'd like us to close on the best way to fix it. :) )

This would work for me too!

Please send a new version if you feel like it but next week I won't be
reviewing that as I'm on holiday.

> 
> J.
> -- 
> I am afraid of the dark.

BR, Jarkko

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] tpm: Fix the timeout & use ktime
  2025-07-04 15:16       ` Jarkko Sakkinen
@ 2025-07-04 15:39         ` Orlov, Ivan
  2025-07-04 15:51           ` Jonathan McDowell
  2025-07-19 11:37           ` Jarkko Sakkinen
  0 siblings, 2 replies; 11+ messages in thread
From: Orlov, Ivan @ 2025-07-04 15:39 UTC (permalink / raw)
  To: Jarkko Sakkinen, Jonathan McDowell
  Cc: Orlov, Ivan, peterhuewe@gmx.de, jgg@ziepe.ca,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	Woodhouse, David

On 04/07/2025 16:16, Jarkko Sakkinen wrote:
> On Fri, Jul 04, 2025 at 10:02:33AM +0100, Jonathan McDowell wrote:
>> On Wed, Jun 25, 2025 at 07:43:07PM +0300, Jarkko Sakkinen wrote:
>>> On Sun, Jun 22, 2025 at 09:52:58PM +0100, Jonathan McDowell wrote:
>>>> On Fri, Jun 20, 2025 at 06:08:31PM +0000, Orlov, Ivan wrote:
>>>>> The current implementation of timeout detection works in the following
>>>>> way:
>>>>>
>>>>> 1. Read completion status. If completed, return the data
>>>>> 2. Sleep for some time (usleep_range)
>>>>> 3. Check for timeout using current jiffies value. Return an error if
>>>>>    timed out
>>>>> 4. Goto 1
>>>>>
>>>>> usleep_range doesn't guarantee it's always going to wake up strictly in
>>>>> (min, max) range, so such a situation is possible:
>>>>>
>>>>> 1. Driver reads completion status. No completion yet
>>>>> 2. Process sleeps indefinitely. In the meantime, TPM responds
>>>>> 3. We check for timeout without checking for the completion again.
>>>>>    Result is lost.
>>>>>
>>>>> Such a situation also happens for the guest VMs: if vCPU goes to sleep
>>>>> and doesn't get scheduled for some time, the guest TPM driver will
>>>>> timeout instantly after waking up without checking for the completion
>>>>> (which may already be in place).
>>>>>
>>>>> Perform the completion check once again after exiting the busy loop in
>>>>> order to give the device the last chance to send us some data.
>>>>>
>>>>> Since now we check for completion in two places, extract this check into
>>>>> a separate function.
>>>>>
>>>>> Signed-off-by: Ivan Orlov <iorlov@amazon.com>
>>>>> ---
>>>>> V1 -> V2:
>>>>> - Exclude the jiffies -> ktime change from the patch
>>>>> - Instead of recording the time before checking for completion, check
>>>>>   for completion once again after leaving the loop
>>>>>
>>>>> drivers/char/tpm/tpm-interface.c | 17 +++++++++++++++--
>>>>> 1 file changed, 15 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
>>>>> index 8d7e4da6ed53..6960ee2798e1 100644
>>>>> --- a/drivers/char/tpm/tpm-interface.c
>>>>> +++ b/drivers/char/tpm/tpm-interface.c
>>>>> @@ -82,6 +82,13 @@ static bool tpm_chip_req_canceled(struct tpm_chip *chip, u8 status)
>>>>> 	return chip->ops->req_canceled(chip, status);
>>>>> }
>>>>>
>>>>> +static bool tpm_transmit_completed(struct tpm_chip *chip)
>>>>> +{
>>>>> +	u8 status_masked = tpm_chip_status(chip) & chip->ops->req_complete_mask;
>>>>> +
>>>>> +	return status_masked == chip->ops->req_complete_val;
>>>>> +}
>>>>> +
>>>>> static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
>>>>> {
>>>>> 	struct tpm_header *header = buf;
>>>>> @@ -129,8 +136,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
>>>>> 	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
>>>>> 	do {
>>>>> 		u8 status = tpm_chip_status(chip);
>>>>> -		if ((status & chip->ops->req_complete_mask) ==
>>>>> -		    chip->ops->req_complete_val)
>>>>> +		if (tpm_transmit_completed(chip))
>>>>> 			goto out_recv;
>>>>
>>>> The only thing I'd point out here is we end up doing a double status read
>>>> one after the other (once here, once in tpm_transmit_completed), and I'm
>>>> pretty sure I've seen instances where that caused a problem.
>>>
>>> It would be easy to to prevent at least double reads after completion
>>> e.g., in tpm_chip_status():
>>
>> Or just take the simple approach and make the check after the while loop:
>>
>> 	if ((tpm_chip_status(chip) & chip->ops->req_complete_mask) ==
>> 	    chip->ops->req_complete_val)
>> 		goto out_recv;
>>
>> There might be potential for a longer term cleanup using chip->status to
>> cache things, but I'm little concerned that's going to open paths where we
>> might not correctly update it, so I think it should be a separate piece.
>>
>> (I'm motivated by the fact we've started to see the "Operation Canceled"
>> error and I'd like us to close on the best way to fix it. :) )
> 
> This would work for me too!
> 

Hi, and sorry for the late reply :(

I believe this option would work for us as well. Please let me know 
whether you'd like me to send V3 or you feel free to send it yourself if 
you want.

--
Kind regards,
Ivan Orlov

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] tpm: Fix the timeout & use ktime
  2025-07-04 15:39         ` Orlov, Ivan
@ 2025-07-04 15:51           ` Jonathan McDowell
  2025-07-19 11:37           ` Jarkko Sakkinen
  1 sibling, 0 replies; 11+ messages in thread
From: Jonathan McDowell @ 2025-07-04 15:51 UTC (permalink / raw)
  To: Orlov, Ivan
  Cc: Jarkko Sakkinen, Orlov, Ivan, peterhuewe@gmx.de, jgg@ziepe.ca,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	Woodhouse, David

On Fri, Jul 04, 2025 at 04:39:20PM +0100, Orlov, Ivan wrote:
>On 04/07/2025 16:16, Jarkko Sakkinen wrote:
>>On Fri, Jul 04, 2025 at 10:02:33AM +0100, Jonathan McDowell wrote:
>>>On Wed, Jun 25, 2025 at 07:43:07PM +0300, Jarkko Sakkinen wrote:
>>>>On Sun, Jun 22, 2025 at 09:52:58PM +0100, Jonathan McDowell wrote:
>>>>>On Fri, Jun 20, 2025 at 06:08:31PM +0000, Orlov, Ivan wrote:
>>>>>>The current implementation of timeout detection works in the following
>>>>>>way:
>>>>>>
>>>>>>1. Read completion status. If completed, return the data
>>>>>>2. Sleep for some time (usleep_range)
>>>>>>3. Check for timeout using current jiffies value. Return an error if
>>>>>>   timed out
>>>>>>4. Goto 1
>>>>>>
>>>>>>usleep_range doesn't guarantee it's always going to wake up strictly in
>>>>>>(min, max) range, so such a situation is possible:
>>>>>>
>>>>>>1. Driver reads completion status. No completion yet
>>>>>>2. Process sleeps indefinitely. In the meantime, TPM responds
>>>>>>3. We check for timeout without checking for the completion again.
>>>>>>   Result is lost.
>>>>>>
>>>>>>Such a situation also happens for the guest VMs: if vCPU goes to sleep
>>>>>>and doesn't get scheduled for some time, the guest TPM driver will
>>>>>>timeout instantly after waking up without checking for the completion
>>>>>>(which may already be in place).
>>>>>>
>>>>>>Perform the completion check once again after exiting the busy loop in
>>>>>>order to give the device the last chance to send us some data.
>>>>>>
>>>>>>Since now we check for completion in two places, extract this check into
>>>>>>a separate function.
>>>>>>
>>>>>>Signed-off-by: Ivan Orlov <iorlov@amazon.com>
>>>>>>---
>>>>>>V1 -> V2:
>>>>>>- Exclude the jiffies -> ktime change from the patch
>>>>>>- Instead of recording the time before checking for completion, check
>>>>>>  for completion once again after leaving the loop
>>>>>>
>>>>>>drivers/char/tpm/tpm-interface.c | 17 +++++++++++++++--
>>>>>>1 file changed, 15 insertions(+), 2 deletions(-)
>>>>>>
>>>>>>diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
>>>>>>index 8d7e4da6ed53..6960ee2798e1 100644
>>>>>>--- a/drivers/char/tpm/tpm-interface.c
>>>>>>+++ b/drivers/char/tpm/tpm-interface.c
>>>>>>@@ -82,6 +82,13 @@ static bool tpm_chip_req_canceled(struct tpm_chip *chip, u8 status)
>>>>>>	return chip->ops->req_canceled(chip, status);
>>>>>>}
>>>>>>
>>>>>>+static bool tpm_transmit_completed(struct tpm_chip *chip)
>>>>>>+{
>>>>>>+	u8 status_masked = tpm_chip_status(chip) & chip->ops->req_complete_mask;
>>>>>>+
>>>>>>+	return status_masked == chip->ops->req_complete_val;
>>>>>>+}
>>>>>>+
>>>>>>static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
>>>>>>{
>>>>>>	struct tpm_header *header = buf;
>>>>>>@@ -129,8 +136,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
>>>>>>	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
>>>>>>	do {
>>>>>>		u8 status = tpm_chip_status(chip);
>>>>>>-		if ((status & chip->ops->req_complete_mask) ==
>>>>>>-		    chip->ops->req_complete_val)
>>>>>>+		if (tpm_transmit_completed(chip))
>>>>>>			goto out_recv;
>>>>>
>>>>>The only thing I'd point out here is we end up doing a double status read
>>>>>one after the other (once here, once in tpm_transmit_completed), and I'm
>>>>>pretty sure I've seen instances where that caused a problem.
>>>>
>>>>It would be easy to to prevent at least double reads after completion
>>>>e.g., in tpm_chip_status():
>>>
>>>Or just take the simple approach and make the check after the while loop:
>>>
>>>	if ((tpm_chip_status(chip) & chip->ops->req_complete_mask) ==
>>>	    chip->ops->req_complete_val)
>>>		goto out_recv;
>>>
>>>There might be potential for a longer term cleanup using chip->status to
>>>cache things, but I'm little concerned that's going to open paths where we
>>>might not correctly update it, so I think it should be a separate piece.
>>>
>>>(I'm motivated by the fact we've started to see the "Operation Canceled"
>>>error and I'd like us to close on the best way to fix it. :) )
>>
>>This would work for me too!
>>
>
>Hi, and sorry for the late reply :(
>
>I believe this option would work for us as well. Please let me know 
>whether you'd like me to send V3 or you feel free to send it yourself 
>if you want.

As far as I'm concerned it's something you found, and your patch. You 
send a new version, I'll test + review it. :)

J.

-- 
  What have you got in your pocket? |  .''`.  Debian GNU/Linux Developer
                                    | : :' :  Happy to accept PGP signed
                                    | `. `'   or encrypted mail - RSA
                                    |   `-    key on the keyservers.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] tpm: Fix the timeout & use ktime
  2025-07-04 15:39         ` Orlov, Ivan
  2025-07-04 15:51           ` Jonathan McDowell
@ 2025-07-19 11:37           ` Jarkko Sakkinen
  2025-07-19 20:19             ` Orlov, Ivan
  1 sibling, 1 reply; 11+ messages in thread
From: Jarkko Sakkinen @ 2025-07-19 11:37 UTC (permalink / raw)
  To: Orlov, Ivan
  Cc: Jonathan McDowell, Orlov, Ivan, peterhuewe@gmx.de, jgg@ziepe.ca,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	Woodhouse, David

On Fri, Jul 04, 2025 at 04:39:20PM +0100, Orlov, Ivan wrote:
> On 04/07/2025 16:16, Jarkko Sakkinen wrote:
> > On Fri, Jul 04, 2025 at 10:02:33AM +0100, Jonathan McDowell wrote:
> > > On Wed, Jun 25, 2025 at 07:43:07PM +0300, Jarkko Sakkinen wrote:
> > > > On Sun, Jun 22, 2025 at 09:52:58PM +0100, Jonathan McDowell wrote:
> > > > > On Fri, Jun 20, 2025 at 06:08:31PM +0000, Orlov, Ivan wrote:
> > > > > > The current implementation of timeout detection works in the following
> > > > > > way:
> > > > > > 
> > > > > > 1. Read completion status. If completed, return the data
> > > > > > 2. Sleep for some time (usleep_range)
> > > > > > 3. Check for timeout using current jiffies value. Return an error if
> > > > > >    timed out
> > > > > > 4. Goto 1
> > > > > > 
> > > > > > usleep_range doesn't guarantee it's always going to wake up strictly in
> > > > > > (min, max) range, so such a situation is possible:
> > > > > > 
> > > > > > 1. Driver reads completion status. No completion yet
> > > > > > 2. Process sleeps indefinitely. In the meantime, TPM responds
> > > > > > 3. We check for timeout without checking for the completion again.
> > > > > >    Result is lost.
> > > > > > 
> > > > > > Such a situation also happens for the guest VMs: if vCPU goes to sleep
> > > > > > and doesn't get scheduled for some time, the guest TPM driver will
> > > > > > timeout instantly after waking up without checking for the completion
> > > > > > (which may already be in place).
> > > > > > 
> > > > > > Perform the completion check once again after exiting the busy loop in
> > > > > > order to give the device the last chance to send us some data.
> > > > > > 
> > > > > > Since now we check for completion in two places, extract this check into
> > > > > > a separate function.
> > > > > > 
> > > > > > Signed-off-by: Ivan Orlov <iorlov@amazon.com>
> > > > > > ---
> > > > > > V1 -> V2:
> > > > > > - Exclude the jiffies -> ktime change from the patch
> > > > > > - Instead of recording the time before checking for completion, check
> > > > > >   for completion once again after leaving the loop
> > > > > > 
> > > > > > drivers/char/tpm/tpm-interface.c | 17 +++++++++++++++--
> > > > > > 1 file changed, 15 insertions(+), 2 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> > > > > > index 8d7e4da6ed53..6960ee2798e1 100644
> > > > > > --- a/drivers/char/tpm/tpm-interface.c
> > > > > > +++ b/drivers/char/tpm/tpm-interface.c
> > > > > > @@ -82,6 +82,13 @@ static bool tpm_chip_req_canceled(struct tpm_chip *chip, u8 status)
> > > > > > 	return chip->ops->req_canceled(chip, status);
> > > > > > }
> > > > > > 
> > > > > > +static bool tpm_transmit_completed(struct tpm_chip *chip)
> > > > > > +{
> > > > > > +	u8 status_masked = tpm_chip_status(chip) & chip->ops->req_complete_mask;
> > > > > > +
> > > > > > +	return status_masked == chip->ops->req_complete_val;
> > > > > > +}
> > > > > > +
> > > > > > static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> > > > > > {
> > > > > > 	struct tpm_header *header = buf;
> > > > > > @@ -129,8 +136,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, void *buf, size_t bufsiz)
> > > > > > 	stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
> > > > > > 	do {
> > > > > > 		u8 status = tpm_chip_status(chip);
> > > > > > -		if ((status & chip->ops->req_complete_mask) ==
> > > > > > -		    chip->ops->req_complete_val)
> > > > > > +		if (tpm_transmit_completed(chip))
> > > > > > 			goto out_recv;
> > > > > 
> > > > > The only thing I'd point out here is we end up doing a double status read
> > > > > one after the other (once here, once in tpm_transmit_completed), and I'm
> > > > > pretty sure I've seen instances where that caused a problem.
> > > > 
> > > > It would be easy to to prevent at least double reads after completion
> > > > e.g., in tpm_chip_status():
> > > 
> > > Or just take the simple approach and make the check after the while loop:
> > > 
> > > 	if ((tpm_chip_status(chip) & chip->ops->req_complete_mask) ==
> > > 	    chip->ops->req_complete_val)
> > > 		goto out_recv;
> > > 
> > > There might be potential for a longer term cleanup using chip->status to
> > > cache things, but I'm little concerned that's going to open paths where we
> > > might not correctly update it, so I think it should be a separate piece.
> > > 
> > > (I'm motivated by the fact we've started to see the "Operation Canceled"
> > > error and I'd like us to close on the best way to fix it. :) )
> > 
> > This would work for me too!
> > 
> 
> Hi, and sorry for the late reply :(
> 
> I believe this option would work for us as well. Please let me know whether
> you'd like me to send V3 or you feel free to send it yourself if you want.

Please send one more patch. I just came from holiday and now have
hands full backtracking last two weeks.

> 
> --
> Kind regards,
> Ivan Orlov

BR, Jarkko

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2] tpm: Fix the timeout & use ktime
  2025-07-19 11:37           ` Jarkko Sakkinen
@ 2025-07-19 20:19             ` Orlov, Ivan
  0 siblings, 0 replies; 11+ messages in thread
From: Orlov, Ivan @ 2025-07-19 20:19 UTC (permalink / raw)
  To: Jarkko Sakkinen
  Cc: Jonathan McDowell, Orlov, Ivan, peterhuewe@gmx.de, jgg@ziepe.ca,
	linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org,
	Woodhouse, David

On 19/07/2025 12:37, Jarkko Sakkinen wrote:
>> I believe this option would work for us as well. Please let me know whether
>> you'd like me to send V3 or you feel free to send it yourself if you want.
> 
> Please send one more patch. I just came from holiday and now have
> hands full backtracking last two weeks.

Hi,

I've just sent a V3. Sorry for the delay, these were busy 2 weeks :(

--
Kind regards,
Ivan Orlov

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2025-07-19 20:19 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-20 18:08 [PATCH v2] tpm: Fix the timeout & use ktime Orlov, Ivan
2025-06-20 22:03 ` Orlov, Ivan
2025-06-22 20:52 ` Jonathan McDowell
2025-06-25 16:43   ` Jarkko Sakkinen
2025-06-25 16:49     ` Jarkko Sakkinen
2025-07-04  9:02     ` Jonathan McDowell
2025-07-04 15:16       ` Jarkko Sakkinen
2025-07-04 15:39         ` Orlov, Ivan
2025-07-04 15:51           ` Jonathan McDowell
2025-07-19 11:37           ` Jarkko Sakkinen
2025-07-19 20:19             ` Orlov, Ivan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).