All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled
@ 2023-06-01 12:06 Ilias Apalodimas
  2023-06-01 12:06 ` [PATCH 2/2] efi_selftest: check for deleted handles in the event notification list Ilias Apalodimas
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Ilias Apalodimas @ 2023-06-01 12:06 UTC (permalink / raw)
  To: u-boot; +Cc: Ilias Apalodimas, Heinrich Schuchardt

When a notification event is registered for a protocol the handle of the
protocol is added in our event notification list.  When all the protocols
of the handle are uninstalled we delete the handle but we do not remove
it from the event notification list.

Clean up the protocol removal functions and add a wrapper which
- Removes the to-be deleted handle from any lists it participates
- Remove the handle if no more protocols are present

It's worth noting that all our variants of efi_uninstall_protocol_*()
and uninstall_multiple_protocol_*() end up calling
efi_uninstall_protocol().  We could add the cleanup in that function
only,  however efi_reinstall_protocol_interface() expects the handle not
to be removed.

Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
 lib/efi_loader/efi_boottime.c | 45 +++++++++++++++++++++++++----------
 1 file changed, 33 insertions(+), 12 deletions(-)

diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index d5065f296aee..450524ddca2f 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -197,6 +197,35 @@ static bool efi_event_is_queued(struct efi_event *event)
 	return !!event->queue_link.next;
 }
 
+/**
+ * efi_handle_cleanup() - Clean the deleted handle from the various lists
+ * @handle: handle to remove
+ * @force:  force removal even if protocols are still installed on the handle
+ *
+ * Return: status code
+ */
+static void efi_handle_cleanup(efi_handle_t handle, bool force)
+{
+	struct efi_register_notify_event *item, *next;
+
+	if (!list_empty(&handle->protocols) || force)
+		return;
+	/* The handle is about to be freed. Remove it from events */
+	list_for_each_entry_safe(item, next, &efi_register_notify_events, link) {
+		struct efi_protocol_notification *hitem, *hnext;
+
+		list_for_each_entry_safe(hitem, hnext, &item->handles, link) {
+			if (handle == hitem->handle) {
+				list_del(&hitem->link);
+				free(hitem);
+			}
+		}
+	}
+	/* The last protocol has been removed, delete the handle. */
+	list_del(&handle->link);
+	free(handle);
+}
+
 /**
  * efi_process_event_queue() - process event queue
  */
@@ -627,8 +656,7 @@ void efi_delete_handle(efi_handle_t handle)
 		return;
 	}
 
-	list_del(&handle->link);
-	free(handle);
+	efi_handle_cleanup(handle, true);
 }
 
 /**
@@ -1396,11 +1424,8 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface
 	if (ret != EFI_SUCCESS)
 		goto out;
 
-	/* If the last protocol has been removed, delete the handle. */
-	if (list_empty(&handle->protocols)) {
-		list_del(&handle->link);
-		free(handle);
-	}
+	/* Check if we have to purge the handle from various lists */
+	efi_handle_cleanup(handle, false);
 out:
 	return EFI_EXIT(ret);
 }
@@ -2777,11 +2802,7 @@ efi_uninstall_multiple_protocol_interfaces_int(efi_handle_t handle,
 		i++;
 	}
 	if (ret == EFI_SUCCESS) {
-		/* If the last protocol has been removed, delete the handle. */
-		if (list_empty(&handle->protocols)) {
-			list_del(&handle->link);
-			free(handle);
-		}
+		efi_handle_cleanup(handle, false);
 		goto out;
 	}
 
-- 
2.39.2


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

* [PATCH 2/2] efi_selftest: check for deleted handles in the event notification list
  2023-06-01 12:06 [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled Ilias Apalodimas
@ 2023-06-01 12:06 ` Ilias Apalodimas
  2023-06-01 16:27   ` Heinrich Schuchardt
  2023-06-01 12:59 ` [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled Ilias Apalodimas
  2023-06-01 16:15 ` Heinrich Schuchardt
  2 siblings, 1 reply; 8+ messages in thread
From: Ilias Apalodimas @ 2023-06-01 12:06 UTC (permalink / raw)
  To: u-boot; +Cc: Ilias Apalodimas, Heinrich Schuchardt

A previous patch is fixing a problem where handles were added in
an event notification list, but were never deleted when the handle got
deleted.  Add a test case which calls
- RegisterProtocolNotify
- IstallMultipleProtocolInterface
- UnIstallMultipleProtocolInterface
- LocateHandleBuffer(ByRegisterNotify)
The last call should return EFI_NOT_FOUND

Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
Heinrich this is not rebased on top of
https://lore.kernel.org/u-boot/20230601070609.14977-1-heinrich.schuchardt@canonical.com/

 .../efi_selftest_register_notify.c            | 61 ++++++++++++++++++-
 1 file changed, 59 insertions(+), 2 deletions(-)

diff --git a/lib/efi_selftest/efi_selftest_register_notify.c b/lib/efi_selftest/efi_selftest_register_notify.c
index ad763dd6cb8b..d133c7c50b71 100644
--- a/lib/efi_selftest/efi_selftest_register_notify.c
+++ b/lib/efi_selftest/efi_selftest_register_notify.c
@@ -33,8 +33,14 @@ static efi_guid_t guid1 =
 static efi_guid_t guid2 =
 	EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77,
 		 0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f);
+static efi_guid_t guid3 =
+	EFI_GUID(0xfa09f2cb, 0x70a8, 0x0d77,
+		 0x9a, 0x2c, 0x31, 0x18, 0xca, 0x41, 0xa6, 0x6e);
+
 static struct context context;
 static struct efi_event *event;
+static struct efi_event *test_uninstall_event;
+static void *test_uninstall_key;

 /*
  * Notification function, increments the notification count if parameter
@@ -63,6 +69,17 @@ static void EFIAPI notify(struct efi_event *event, void *context)
 	}
 }

+/*
+ * Notification function, does nothing and is used to test UninstallProtocol
+ *
+ * @event	notified event
+ * @context	pointer to the notification count
+ */
+static void EFIAPI test_uninstall_notify(struct efi_event *event, void *context)
+{
+	return;
+}
+
 /*
  * Setup unit test.
  *
@@ -91,6 +108,21 @@ static int setup(const efi_handle_t img_handle,
 		return EFI_ST_FAILURE;
 	}

+	ret = boottime->create_event(EVT_NOTIFY_SIGNAL,
+				     TPL_CALLBACK, test_uninstall_notify, NULL,
+				     &test_uninstall_event);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("could not create event\n");
+		return EFI_ST_FAILURE;
+	}
+
+	ret = boottime->register_protocol_notify(&guid3, test_uninstall_event,
+						 &test_uninstall_key);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("could not register event\n");
+		return EFI_ST_FAILURE;
+	}
+
 	return EFI_ST_SUCCESS;
 }

@@ -121,8 +153,10 @@ static int teardown(void)
 static int execute(void)
 {
 	efi_status_t ret;
-	efi_handle_t handle1 = NULL, handle2 = NULL;
-	struct interface interface1, interface2;
+	efi_handle_t handle1 = NULL, handle2 = NULL, handle3 = NULL;
+	struct interface interface1, interface2, interface3;
+	efi_uintn_t handle_count;
+	efi_handle_t *handles;

 	ret = boottime->install_protocol_interface(&handle1, &guid1,
 						   EFI_NATIVE_INTERFACE,
@@ -224,6 +258,29 @@ static int execute(void)
 		return EFI_ST_FAILURE;
 	}

+	ret = boottime->install_protocol_interface(&handle3, &guid3,
+						   EFI_NATIVE_INTERFACE,
+						   &interface3);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("could not install interface\n");
+		return EFI_ST_FAILURE;
+	}
+
+	ret = boottime->uninstall_multiple_protocol_interfaces
+			(handle3, &guid3, &interface3, NULL);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
+		return EFI_ST_FAILURE;
+	}
+
+	ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL,
+					     test_uninstall_key,
+					     &handle_count, &handles);
+	if (ret != EFI_NOT_FOUND) {
+		efi_st_error("UninstallMultipleProtocolInterfaces failed to delete event handles\n");
+		return EFI_ST_FAILURE;
+	}
+
 	return EFI_ST_SUCCESS;
 }

--
2.39.2


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

* Re: [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled
  2023-06-01 12:06 [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled Ilias Apalodimas
  2023-06-01 12:06 ` [PATCH 2/2] efi_selftest: check for deleted handles in the event notification list Ilias Apalodimas
@ 2023-06-01 12:59 ` Ilias Apalodimas
  2023-06-01 16:15 ` Heinrich Schuchardt
  2 siblings, 0 replies; 8+ messages in thread
From: Ilias Apalodimas @ 2023-06-01 12:59 UTC (permalink / raw)
  To: u-boot; +Cc: Heinrich Schuchardt

Heinrich

[...]

>
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index d5065f296aee..450524ddca2f 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -197,6 +197,35 @@ static bool efi_event_is_queued(struct efi_event *event)
>         return !!event->queue_link.next;
>  }
>
> +/**
> + * efi_handle_cleanup() - Clean the deleted handle from the various lists
> + * @handle: handle to remove
> + * @force:  force removal even if protocols are still installed on the handle
> + *
> + * Return: status code
> + */
> +static void efi_handle_cleanup(efi_handle_t handle, bool force)
> +{
> +       struct efi_register_notify_event *item, *next;
> +
> +       if (!list_empty(&handle->protocols) || force)

This is obviously wrong, I'll send a v2 once you are fine with the rest. Sorry!


[...]

/Ilias

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

* Re: [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled
  2023-06-01 12:06 [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled Ilias Apalodimas
  2023-06-01 12:06 ` [PATCH 2/2] efi_selftest: check for deleted handles in the event notification list Ilias Apalodimas
  2023-06-01 12:59 ` [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled Ilias Apalodimas
@ 2023-06-01 16:15 ` Heinrich Schuchardt
  2023-06-01 19:44   ` Ilias Apalodimas
  2 siblings, 1 reply; 8+ messages in thread
From: Heinrich Schuchardt @ 2023-06-01 16:15 UTC (permalink / raw)
  To: Ilias Apalodimas; +Cc: u-boot

On 6/1/23 14:06, Ilias Apalodimas wrote:
> When a notification event is registered for a protocol the handle of the
> protocol is added in our event notification list.  When all the protocols
> of the handle are uninstalled we delete the handle but we do not remove
> it from the event notification list.
>
> Clean up the protocol removal functions and add a wrapper which
> - Removes the to-be deleted handle from any lists it participates
> - Remove the handle if no more protocols are present
>
> It's worth noting that all our variants of efi_uninstall_protocol_*()
> and uninstall_multiple_protocol_*() end up calling
> efi_uninstall_protocol().  We could add the cleanup in that function
> only,  however efi_reinstall_protocol_interface() expects the handle not
> to be removed.
>
> Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> ---
>   lib/efi_loader/efi_boottime.c | 45 +++++++++++++++++++++++++----------
>   1 file changed, 33 insertions(+), 12 deletions(-)
>
> diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
> index d5065f296aee..450524ddca2f 100644
> --- a/lib/efi_loader/efi_boottime.c
> +++ b/lib/efi_loader/efi_boottime.c
> @@ -197,6 +197,35 @@ static bool efi_event_is_queued(struct efi_event *event)
>   	return !!event->queue_link.next;
>   }
>
> +/**
> + * efi_handle_cleanup() - Clean the deleted handle from the various lists
> + * @handle: handle to remove
> + * @force:  force removal even if protocols are still installed on the handle
> + *
> + * Return: status code
> + */
> +static void efi_handle_cleanup(efi_handle_t handle, bool force)
> +{
> +	struct efi_register_notify_event *item, *next;
> +
> +	if (!list_empty(&handle->protocols) || force)

I guess the parameter force can be dropped from the interface.

> +		return;

Please, return a failure code.

> +	/* The handle is about to be freed. Remove it from events */
> +	list_for_each_entry_safe(item, next, &efi_register_notify_events, link) {
> +		struct efi_protocol_notification *hitem, *hnext;
> +
> +		list_for_each_entry_safe(hitem, hnext, &item->handles, link) {
> +			if (handle == hitem->handle) {
> +				list_del(&hitem->link);
> +				free(hitem);
> +			}
> +		}
> +	}
> +	/* The last protocol has been removed, delete the handle. */
> +	list_del(&handle->link);
> +	free(handle);
> +}
> +
>   /**
>    * efi_process_event_queue() - process event queue
>    */
> @@ -627,8 +656,7 @@ void efi_delete_handle(efi_handle_t handle)
>   		return;
>   	}

It would be safer to move the checks if a protocol interface can be
removed from efi_uninstall_protocol() to efi_remove_protocol(). That way
we are sure that no driver has attached to the protocols that we try to
remove.

>
> -	list_del(&handle->link);
> -	free(handle);
> +	efi_handle_cleanup(handle, true);

I don't think we should use a special treatment here. If the protocols
cannot be deleted, because a driver has attached we should not delete
the handle.

The function should return a status code. Then efi_disk_delete_raw() can
return an error for EVT_DM_PRE_REMOVE and stop the device from being
deleted.

Best regards

Heinrich

>   }
>
>   /**
> @@ -1396,11 +1424,8 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface
>   	if (ret != EFI_SUCCESS)
>   		goto out;
>
> -	/* If the last protocol has been removed, delete the handle. */
> -	if (list_empty(&handle->protocols)) {
> -		list_del(&handle->link);
> -		free(handle);
> -	}
> +	/* Check if we have to purge the handle from various lists */
> +	efi_handle_cleanup(handle, false);
>   out:
>   	return EFI_EXIT(ret);
>   }
> @@ -2777,11 +2802,7 @@ efi_uninstall_multiple_protocol_interfaces_int(efi_handle_t handle,
>   		i++;
>   	}
>   	if (ret == EFI_SUCCESS) {
> -		/* If the last protocol has been removed, delete the handle. */
> -		if (list_empty(&handle->protocols)) {
> -			list_del(&handle->link);
> -			free(handle);
> -		}
> +		efi_handle_cleanup(handle, false);
>   		goto out;
>   	}
>


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

* Re: [PATCH 2/2] efi_selftest: check for deleted handles in the event notification list
  2023-06-01 12:06 ` [PATCH 2/2] efi_selftest: check for deleted handles in the event notification list Ilias Apalodimas
@ 2023-06-01 16:27   ` Heinrich Schuchardt
  2023-06-01 19:32     ` Ilias Apalodimas
  0 siblings, 1 reply; 8+ messages in thread
From: Heinrich Schuchardt @ 2023-06-01 16:27 UTC (permalink / raw)
  To: Ilias Apalodimas; +Cc: u-boot

On 6/1/23 14:06, Ilias Apalodimas wrote:
> A previous patch is fixing a problem where handles were added in
> an event notification list, but were never deleted when the handle got
> deleted.  Add a test case which calls
> - RegisterProtocolNotify
> - IstallMultipleProtocolInterface
> - UnIstallMultipleProtocolInterface
> - LocateHandleBuffer(ByRegisterNotify)
> The last call should return EFI_NOT_FOUND
>
> Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> ---
> Heinrich this is not rebased on top of
> https://lore.kernel.org/u-boot/20230601070609.14977-1-heinrich.schuchardt@canonical.com/
>
>   .../efi_selftest_register_notify.c            | 61 ++++++++++++++++++-
>   1 file changed, 59 insertions(+), 2 deletions(-)
>
> diff --git a/lib/efi_selftest/efi_selftest_register_notify.c b/lib/efi_selftest/efi_selftest_register_notify.c
> index ad763dd6cb8b..d133c7c50b71 100644
> --- a/lib/efi_selftest/efi_selftest_register_notify.c
> +++ b/lib/efi_selftest/efi_selftest_register_notify.c
> @@ -33,8 +33,14 @@ static efi_guid_t guid1 =
>   static efi_guid_t guid2 =
>   	EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77,
>   		 0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f);
> +static efi_guid_t guid3 =
> +	EFI_GUID(0xfa09f2cb, 0x70a8, 0x0d77,
> +		 0x9a, 0x2c, 0x31, 0x18, 0xca, 0x41, 0xa6, 0x6e);
> +
>   static struct context context;
>   static struct efi_event *event;
> +static struct efi_event *test_uninstall_event;
> +static void *test_uninstall_key;
>
>   /*
>    * Notification function, increments the notification count if parameter
> @@ -63,6 +69,17 @@ static void EFIAPI notify(struct efi_event *event, void *context)
>   	}
>   }
>
> +/*
> + * Notification function, does nothing and is used to test UninstallProtocol
> + *
> + * @event	notified event
> + * @context	pointer to the notification count
> + */
> +static void EFIAPI test_uninstall_notify(struct efi_event *event, void *context)
> +{
> +	return;
> +}
> +
>   /*
>    * Setup unit test.
>    *
> @@ -91,6 +108,21 @@ static int setup(const efi_handle_t img_handle,
>   		return EFI_ST_FAILURE;
>   	}
>
> +	ret = boottime->create_event(EVT_NOTIFY_SIGNAL,

You could use the existing notify function.

> +				     TPL_CALLBACK, test_uninstall_notify, NULL,
> +				     &test_uninstall_event);
> +	if (ret != EFI_SUCCESS) {
> +		efi_st_error("could not create event\n");
> +		return EFI_ST_FAILURE;
> +	}
> +
> +	ret = boottime->register_protocol_notify(&guid3, test_uninstall_event,
> +						 &test_uninstall_key);

I would prefer to use the same guid1 protocol. Deleting one handle
should not remove the other handle from the handle queue if both have
the same protocol installed.

> +	if (ret != EFI_SUCCESS) {
> +		efi_st_error("could not register event\n");
> +		return EFI_ST_FAILURE;
> +	}
> +
>   	return EFI_ST_SUCCESS;
>   }
>
> @@ -121,8 +153,10 @@ static int teardown(void)
>   static int execute(void)
>   {
>   	efi_status_t ret;
> -	efi_handle_t handle1 = NULL, handle2 = NULL;
> -	struct interface interface1, interface2;
> +	efi_handle_t handle1 = NULL, handle2 = NULL, handle3 = NULL;
> +	struct interface interface1, interface2, interface3;
> +	efi_uintn_t handle_count;
> +	efi_handle_t *handles;
>
>   	ret = boottime->install_protocol_interface(&handle1, &guid1,
>   						   EFI_NATIVE_INTERFACE,
> @@ -224,6 +258,29 @@ static int execute(void)
>   		return EFI_ST_FAILURE;
>   	}
>
> +	ret = boottime->install_protocol_interface(&handle3, &guid3,
> +						   EFI_NATIVE_INTERFACE,
> +						   &interface3);
> +	if (ret != EFI_SUCCESS) {
> +		efi_st_error("could not install interface\n");
> +		return EFI_ST_FAILURE;
> +	}

Please, check the number of invocations of the notify function.

> +
> +	ret = boottime->uninstall_multiple_protocol_interfaces
> +			(handle3, &guid3, &interface3, NULL);
> +	if (ret != EFI_SUCCESS) {
> +		efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
> +		return EFI_ST_FAILURE;
> +	}

And here again. We don't expect UninstallMultipleProtocolInterfaces() to
trigger the event.

Best regards

Heinrich

> +
> +	ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL,
> +					     test_uninstall_key,
> +					     &handle_count, &handles);
> +	if (ret != EFI_NOT_FOUND) {
> +		efi_st_error("UninstallMultipleProtocolInterfaces failed to delete event handles\n");
> +		return EFI_ST_FAILURE;
> +	}
> +
>   	return EFI_ST_SUCCESS;
>   }
>
> --
> 2.39.2
>


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

* Re: [PATCH 2/2] efi_selftest: check for deleted handles in the event notification list
  2023-06-01 16:27   ` Heinrich Schuchardt
@ 2023-06-01 19:32     ` Ilias Apalodimas
  2023-06-01 21:59       ` Heinrich Schuchardt
  0 siblings, 1 reply; 8+ messages in thread
From: Ilias Apalodimas @ 2023-06-01 19:32 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot

Hi Heinrich, 

[...]
> > + * @event	notified event
> > + * @context	pointer to the notification count
> > + */
> > +static void EFIAPI test_uninstall_notify(struct efi_event *event, void *context)
> > +{
> > +	return;
> > +}
> > +
> >   /*
> >    * Setup unit test.
> >    *
> > @@ -91,6 +108,21 @@ static int setup(const efi_handle_t img_handle,
> >   		return EFI_ST_FAILURE;
> >   	}
> > 
> > +	ret = boottime->create_event(EVT_NOTIFY_SIGNAL,
> 
> You could use the existing notify function.
> 

The reason I created a new one is that the current one calls
locate_handle_buffer().  See below 

> > +				     TPL_CALLBACK, test_uninstall_notify, NULL,
> > +				     &test_uninstall_event);
> > +	if (ret != EFI_SUCCESS) {
> > +		efi_st_error("could not create event\n");
> > +		return EFI_ST_FAILURE;
> > +	}
> > +
> > +	ret = boottime->register_protocol_notify(&guid3, test_uninstall_event,
> > +						 &test_uninstall_key);
> 
> I would prefer to use the same guid1 protocol. Deleting one handle
> should not remove the other handle from the handle queue if both have
> the same protocol installed.
> 

Unless I am missing something, that would not work. The notifier function
will call locate_handle_buffer and will retrieve all handles.  As a result
the subsequent call will return EFI_NOT_FOUND.  You've already sent a ptch
covering that, the purpose of this one is check that the handler will be
clearer from the events list if the protocol gets uninstalled. 
We could use guid2 but I do prefer habing distinct protocols for every
test.

> > +	if (ret != EFI_SUCCESS) {
> > +		efi_st_error("could not register event\n");
> > +		return EFI_ST_FAILURE;
> > +	}
> > +
> >   	return EFI_ST_SUCCESS;
> >   }
> > 
> > @@ -121,8 +153,10 @@ static int teardown(void)
> >   static int execute(void)
> >   {
> >   	efi_status_t ret;
> > -	efi_handle_t handle1 = NULL, handle2 = NULL;
> > -	struct interface interface1, interface2;
> > +	efi_handle_t handle1 = NULL, handle2 = NULL, handle3 = NULL;
> > +	struct interface interface1, interface2, interface3;
> > +	efi_uintn_t handle_count;
> > +	efi_handle_t *handles;
> > 
> >   	ret = boottime->install_protocol_interface(&handle1, &guid1,
> >   						   EFI_NATIVE_INTERFACE,
> > @@ -224,6 +258,29 @@ static int execute(void)
> >   		return EFI_ST_FAILURE;
> >   	}
> > 
> > +	ret = boottime->install_protocol_interface(&handle3, &guid3,
> > +						   EFI_NATIVE_INTERFACE,
> > +						   &interface3);
> > +	if (ret != EFI_SUCCESS) {
> > +		efi_st_error("could not install interface\n");
> > +		return EFI_ST_FAILURE;
> > +	}
> 
> Please, check the number of invocations of the notify function.
> 

I can add that, but the tests already check that case in detail. 

> > +
> > +	ret = boottime->uninstall_multiple_protocol_interfaces
> > +			(handle3, &guid3, &interface3, NULL);
> > +	if (ret != EFI_SUCCESS) {
> > +		efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
> > +		return EFI_ST_FAILURE;
> > +	}
> 
> And here again. We don't expect UninstallMultipleProtocolInterfaces() to
> trigger the event.
> 

ditto

Thanks
/Ilias
> Best regards
> 
> Heinrich
> 
> > +
> > +	ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL,
> > +					     test_uninstall_key,
> > +					     &handle_count, &handles);
> > +	if (ret != EFI_NOT_FOUND) {
> > +		efi_st_error("UninstallMultipleProtocolInterfaces failed to delete event handles\n");
> > +		return EFI_ST_FAILURE;
> > +	}
> > +
> >   	return EFI_ST_SUCCESS;
> >   }
> > 
> > --
> > 2.39.2
> > 
> 

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

* Re: [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled
  2023-06-01 16:15 ` Heinrich Schuchardt
@ 2023-06-01 19:44   ` Ilias Apalodimas
  0 siblings, 0 replies; 8+ messages in thread
From: Ilias Apalodimas @ 2023-06-01 19:44 UTC (permalink / raw)
  To: Heinrich Schuchardt; +Cc: u-boot


[...]
> > 
> > +/**
> > + * efi_handle_cleanup() - Clean the deleted handle from the various lists
> > + * @handle: handle to remove
> > + * @force:  force removal even if protocols are still installed on the handle
> > + *
> > + * Return: status code
> > + */
> > +static void efi_handle_cleanup(efi_handle_t handle, bool force)
> > +{
> > +	struct efi_register_notify_event *item, *next;
> > +
> > +	if (!list_empty(&handle->protocols) || force)
> 
> I guess the parameter force can be dropped from the interface.
> 

'force' is here for a reason(see below), although the if is wrong.

The correct one is obviously
if (!list_empty(&handle->protocols) && !force)
    ....

> > +		return;
> 
> Please, return a failure code.

I am not sure why you want that, but I'll have a closer look 

> 
> > +	/* The handle is about to be freed. Remove it from events */
> > +	list_for_each_entry_safe(item, next, &efi_register_notify_events, link) {
> > +		struct efi_protocol_notification *hitem, *hnext;
> > +
> > +		list_for_each_entry_safe(hitem, hnext, &item->handles, link) {
> > +			if (handle == hitem->handle) {
> > +				list_del(&hitem->link);
> > +				free(hitem);
> > +			}
> > +		}
> > +	}
> > +	/* The last protocol has been removed, delete the handle. */
> > +	list_del(&handle->link);
> > +	free(handle);
> > +}
> > +
> >   /**
> >    * efi_process_event_queue() - process event queue
> >    */
> > @@ -627,8 +656,7 @@ void efi_delete_handle(efi_handle_t handle)
> >   		return;
> >   	}
> 
> It would be safer to move the checks if a protocol interface can be
> removed from efi_uninstall_protocol() to efi_remove_protocol(). That way
> we are sure that no driver has attached to the protocols that we try to
> remove.
> 

Yes it would, in fact I tried this on my initial patches and I mention it
on the patch description .  However the selftests started failing.  The reason
is that efi_reinstall_protocol_interface() does not remove the handle and we have
specific selftests for that.  I don't really know or remember why that was
done like that,  does the EFI spec describe this?  I thought
UninstallProtocolInterface was always supposed to delete the handle if it
had no more protocols

> > 
> > -	list_del(&handle->link);
> > -	free(handle);
> > +	efi_handle_cleanup(handle, true);
> 
> I don't think we should use a special treatment here. If the protocols
> cannot be deleted, because a driver has attached we should not delete
> the handle.
> 
> The function should return a status code. Then efi_disk_delete_raw() can
> return an error for EVT_DM_PRE_REMOVE and stop the device from being
> deleted.
> 

We agree again, but I am not trying to fix that atm.  The reason for the
special check and the force flag is that efi_delete_handle() is already
doing something similar, which is cwnot optimal, but that's the current
state. It bails out only if the *handle* doesn't exist and doesn't care
if the protocols got removed.  If you prefer having a bigger cleanup + fixes 
let me know.

Thanks
/Ilias
> Best regards
> 
> Heinrich
> 
> >   }
> > 
> >   /**
> > @@ -1396,11 +1424,8 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface
> >   	if (ret != EFI_SUCCESS)
> >   		goto out;
> > 
> > -	/* If the last protocol has been removed, delete the handle. */
> > -	if (list_empty(&handle->protocols)) {
> > -		list_del(&handle->link);
> > -		free(handle);
> > -	}
> > +	/* Check if we have to purge the handle from various lists */
> > +	efi_handle_cleanup(handle, false);
> >   out:
> >   	return EFI_EXIT(ret);
> >   }
> > @@ -2777,11 +2802,7 @@ efi_uninstall_multiple_protocol_interfaces_int(efi_handle_t handle,
> >   		i++;
> >   	}
> >   	if (ret == EFI_SUCCESS) {
> > -		/* If the last protocol has been removed, delete the handle. */
> > -		if (list_empty(&handle->protocols)) {
> > -			list_del(&handle->link);
> > -			free(handle);
> > -		}
> > +		efi_handle_cleanup(handle, false);
> >   		goto out;
> >   	}
> > 
> 

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

* Re: [PATCH 2/2] efi_selftest: check for deleted handles in the event notification list
  2023-06-01 19:32     ` Ilias Apalodimas
@ 2023-06-01 21:59       ` Heinrich Schuchardt
  0 siblings, 0 replies; 8+ messages in thread
From: Heinrich Schuchardt @ 2023-06-01 21:59 UTC (permalink / raw)
  To: Ilias Apalodimas; +Cc: u-boot



Am 1. Juni 2023 21:32:04 MESZ schrieb Ilias Apalodimas <ilias.apalodimas@linaro.org>:
>Hi Heinrich, 
>
>[...]
>> > + * @event	notified event
>> > + * @context	pointer to the notification count
>> > + */
>> > +static void EFIAPI test_uninstall_notify(struct efi_event *event, void *context)
>> > +{
>> > +	return;
>> > +}
>> > +
>> >   /*
>> >    * Setup unit test.
>> >    *
>> > @@ -91,6 +108,21 @@ static int setup(const efi_handle_t img_handle,
>> >   		return EFI_ST_FAILURE;
>> >   	}
>> > 
>> > +	ret = boottime->create_event(EVT_NOTIFY_SIGNAL,
>> 
>> You could use the existing notify function.
>> 
>
>The reason I created a new one is that the current one calls
>locate_handle_buffer().  See below 
>
>> > +				     TPL_CALLBACK, test_uninstall_notify, NULL,
>> > +				     &test_uninstall_event);
>> > +	if (ret != EFI_SUCCESS) {
>> > +		efi_st_error("could not create event\n");
>> > +		return EFI_ST_FAILURE;
>> > +	}
>> > +
>> > +	ret = boottime->register_protocol_notify(&guid3, test_uninstall_event,
>> > +						 &test_uninstall_key);
>> 
>> I would prefer to use the same guid1 protocol. Deleting one handle
>> should not remove the other handle from the handle queue if both have
>> the same protocol installed.
>> 
>
>Unless I am missing something, that would not work. The notifier function
>will call locate_handle_buffer and will retrieve all handles.  As a result

This would not match the specification.

LocateHandle(ByRegistrationKey) must only retrieve at maximum a single handle per call irrespective of the queue size. LocateHandleBuffer() should do the same.

Regards

Heinrich 

>the subsequent call will return EFI_NOT_FOUND.  You've already sent a ptch
>covering that, the purpose of this one is check that the handler will be
>clearer from the events list if the protocol gets uninstalled. 
>We could use guid2 but I do prefer habing distinct protocols for every
>test.
>
>> > +	if (ret != EFI_SUCCESS) {
>> > +		efi_st_error("could not register event\n");
>> > +		return EFI_ST_FAILURE;
>> > +	}
>> > +
>> >   	return EFI_ST_SUCCESS;
>> >   }
>> > 
>> > @@ -121,8 +153,10 @@ static int teardown(void)
>> >   static int execute(void)
>> >   {
>> >   	efi_status_t ret;
>> > -	efi_handle_t handle1 = NULL, handle2 = NULL;
>> > -	struct interface interface1, interface2;
>> > +	efi_handle_t handle1 = NULL, handle2 = NULL, handle3 = NULL;
>> > +	struct interface interface1, interface2, interface3;
>> > +	efi_uintn_t handle_count;
>> > +	efi_handle_t *handles;
>> > 
>> >   	ret = boottime->install_protocol_interface(&handle1, &guid1,
>> >   						   EFI_NATIVE_INTERFACE,
>> > @@ -224,6 +258,29 @@ static int execute(void)
>> >   		return EFI_ST_FAILURE;
>> >   	}
>> > 
>> > +	ret = boottime->install_protocol_interface(&handle3, &guid3,
>> > +						   EFI_NATIVE_INTERFACE,
>> > +						   &interface3);
>> > +	if (ret != EFI_SUCCESS) {
>> > +		efi_st_error("could not install interface\n");
>> > +		return EFI_ST_FAILURE;
>> > +	}
>> 
>> Please, check the number of invocations of the notify function.
>> 
>
>I can add that, but the tests already check that case in detail. 
>
>> > +
>> > +	ret = boottime->uninstall_multiple_protocol_interfaces
>> > +			(handle3, &guid3, &interface3, NULL);
>> > +	if (ret != EFI_SUCCESS) {
>> > +		efi_st_error("UninstallMultipleProtocolInterfaces failed\n");
>> > +		return EFI_ST_FAILURE;
>> > +	}
>> 
>> And here again. We don't expect UninstallMultipleProtocolInterfaces() to
>> trigger the event.
>> 
>
>ditto
>
>Thanks
>/Ilias
>> Best regards
>> 
>> Heinrich
>> 
>> > +
>> > +	ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL,
>> > +					     test_uninstall_key,
>> > +					     &handle_count, &handles);
>> > +	if (ret != EFI_NOT_FOUND) {
>> > +		efi_st_error("UninstallMultipleProtocolInterfaces failed to delete event handles\n");
>> > +		return EFI_ST_FAILURE;
>> > +	}
>> > +
>> >   	return EFI_ST_SUCCESS;
>> >   }
>> > 
>> > --
>> > 2.39.2
>> > 
>> 

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

end of thread, other threads:[~2023-06-01 21:59 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-01 12:06 [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled Ilias Apalodimas
2023-06-01 12:06 ` [PATCH 2/2] efi_selftest: check for deleted handles in the event notification list Ilias Apalodimas
2023-06-01 16:27   ` Heinrich Schuchardt
2023-06-01 19:32     ` Ilias Apalodimas
2023-06-01 21:59       ` Heinrich Schuchardt
2023-06-01 12:59 ` [PATCH 1/2] efi_loader: delete handle from events when a protocol is uninstalled Ilias Apalodimas
2023-06-01 16:15 ` Heinrich Schuchardt
2023-06-01 19:44   ` Ilias Apalodimas

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.