efi_driver: fix error handling

If creating the block device fails,

* delete all created objects and references
* close the protocol interface on the controller

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
This commit is contained in:
Heinrich Schuchardt 2022-10-03 10:35:35 +02:00
parent 16b27b67c5
commit 43a5891c66
3 changed files with 45 additions and 38 deletions

View file

@ -25,7 +25,7 @@
struct efi_driver_ops { struct efi_driver_ops {
const efi_guid_t *protocol; const efi_guid_t *protocol;
const efi_guid_t *child_protocol; const efi_guid_t *child_protocol;
int (*bind)(efi_handle_t handle, void *interface); efi_status_t (*bind)(efi_handle_t handle, void *interface);
}; };
/* /*

View file

@ -112,12 +112,13 @@ static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
* *
* @handle: handle * @handle: handle
* @interface: block io protocol * @interface: block io protocol
* Return: 0 = success * Return: status code
*/ */
static int efi_bl_bind(efi_handle_t handle, void *interface) static efi_status_t efi_bl_bind(efi_handle_t handle, void *interface)
{ {
struct udevice *bdev, *parent = dm_root(); struct udevice *bdev = NULL, *parent = dm_root();
int ret, devnum; efi_status_t ret;
int devnum;
char *name; char *name;
struct efi_object *obj = efi_search_obj(handle); struct efi_object *obj = efi_search_obj(handle);
struct efi_block_io *io = interface; struct efi_block_io *io = interface;
@ -125,28 +126,28 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io); EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io);
if (!obj) if (!obj || !interface)
return -ENOENT; return EFI_INVALID_PARAMETER;
devnum = blk_find_max_devnum(UCLASS_EFI_LOADER); devnum = blk_find_max_devnum(UCLASS_EFI_LOADER);
if (devnum == -ENODEV) if (devnum == -ENODEV)
devnum = 0; devnum = 0;
else if (devnum < 0) else if (devnum < 0)
return devnum; return EFI_OUT_OF_RESOURCES;
name = calloc(1, 18); /* strlen("efiblk#2147483648") + 1 */ name = calloc(1, 18); /* strlen("efiblk#2147483648") + 1 */
if (!name) if (!name)
return -ENOMEM; return EFI_OUT_OF_RESOURCES;
sprintf(name, "efiblk#%d", devnum); sprintf(name, "efiblk#%d", devnum);
/* Create driver model udevice for the EFI block io device */ /* Create driver model udevice for the EFI block io device */
ret = blk_create_device(parent, "efi_blk", name, UCLASS_EFI_LOADER, if (blk_create_device(parent, "efi_blk", name, UCLASS_EFI_LOADER,
devnum, io->media->block_size, devnum, io->media->block_size,
(lbaint_t)io->media->last_block, &bdev); (lbaint_t)io->media->last_block, &bdev)) {
if (ret) ret = EFI_OUT_OF_RESOURCES;
return ret; free(name);
if (!bdev) goto err;
return -ENOENT; }
/* Set the DM_FLAG_NAME_ALLOCED flag to avoid a memory leak */ /* Set the DM_FLAG_NAME_ALLOCED flag to avoid a memory leak */
device_set_name_alloced(bdev); device_set_name_alloced(bdev);
@ -154,20 +155,25 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
plat->handle = handle; plat->handle = handle;
plat->io = interface; plat->io = interface;
/* if (efi_link_dev(handle, bdev)) {
* FIXME: necessary because we won't do almost nothing in ret = EFI_OUT_OF_RESOURCES;
* efi_disk_create() when called from device_probe(). goto err;
*/ }
if (efi_link_dev(handle, bdev))
/* FIXME: cleanup for bdev */
return ret;
ret = device_probe(bdev); if (device_probe(bdev)) {
if (ret) ret = EFI_DEVICE_ERROR;
return ret; goto err;
}
EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name); EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name);
return 0; return EFI_SUCCESS;
err:
efi_unlink_dev(handle);
if (bdev)
device_unbind(bdev);
return ret;
} }
/* Block device driver operators */ /* Block device driver operators */

View file

@ -11,7 +11,7 @@
* The uclass provides the bind, start, and stop entry points for the driver * The uclass provides the bind, start, and stop entry points for the driver
* binding protocol. * binding protocol.
* *
* In bind() and stop() it checks if the controller implements the protocol * In supported() and bind() it checks if the controller implements the protocol
* supported by the EFI driver. In the start() function it calls the bind() * supported by the EFI driver. In the start() function it calls the bind()
* function of the EFI driver. In the stop() function it destroys the child * function of the EFI driver. In the stop() function it destroys the child
* controllers. * controllers.
@ -144,18 +144,19 @@ static efi_status_t EFIAPI efi_uc_start(
goto out; goto out;
} }
ret = check_node_type(controller_handle); ret = check_node_type(controller_handle);
if (ret != EFI_SUCCESS) { if (ret != EFI_SUCCESS)
r = EFI_CALL(systab.boottime->close_protocol( goto err;
controller_handle, bp->ops->protocol, ret = bp->ops->bind(controller_handle, interface);
this->driver_binding_handle, if (ret == EFI_SUCCESS)
controller_handle));
if (r != EFI_SUCCESS)
EFI_PRINT("Failure to close handle\n");
goto out; goto out;
}
/* TODO: driver specific stuff */ err:
bp->ops->bind(controller_handle, interface); r = EFI_CALL(systab.boottime->close_protocol(
controller_handle, bp->ops->protocol,
this->driver_binding_handle,
controller_handle));
if (r != EFI_SUCCESS)
EFI_PRINT("Failure to close handle\n");
out: out:
return EFI_EXIT(ret); return EFI_EXIT(ret);