mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
e5e7d8bbcf
This error path should return -EINVAL instead of success.
Fixes: e261fbf347
("blk: host_dev: Sanity check on the size of host backing file")
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
149 lines
3.1 KiB
C
149 lines
3.1 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Driver for sandbox host interface, used to access files on the host which
|
|
* contain partitions and filesystem
|
|
*
|
|
* Copyright 2022 Google LLC
|
|
* Written by Simon Glass <sjg@chromium.org>
|
|
*/
|
|
|
|
#define LOG_CATEGORY UCLASS_HOST
|
|
|
|
#include <common.h>
|
|
#include <blk.h>
|
|
#include <bootdev.h>
|
|
#include <dm.h>
|
|
#include <log.h>
|
|
#include <malloc.h>
|
|
#include <os.h>
|
|
#include <sandbox_host.h>
|
|
#include <dm/device-internal.h>
|
|
|
|
static int host_sb_attach_file(struct udevice *dev, const char *filename)
|
|
{
|
|
struct host_sb_plat *plat = dev_get_plat(dev);
|
|
struct blk_desc *desc;
|
|
struct udevice *blk;
|
|
int ret, fd;
|
|
off_t size;
|
|
char *fname;
|
|
|
|
if (!filename)
|
|
return -EINVAL;
|
|
|
|
if (plat->fd)
|
|
return log_msg_ret("fd", -EEXIST);
|
|
|
|
/* Sanity check that host_sb_bind() has been used */
|
|
ret = blk_find_from_parent(dev, &blk);
|
|
if (ret)
|
|
return ret;
|
|
|
|
fd = os_open(filename, OS_O_RDWR);
|
|
if (fd == -1) {
|
|
printf("Failed to access host backing file '%s', trying read-only\n",
|
|
filename);
|
|
fd = os_open(filename, OS_O_RDONLY);
|
|
if (fd == -1) {
|
|
printf("- still failed\n");
|
|
return log_msg_ret("open", -ENOENT);
|
|
}
|
|
}
|
|
|
|
fname = strdup(filename);
|
|
if (!fname) {
|
|
ret = -ENOMEM;
|
|
goto err_fname;
|
|
}
|
|
|
|
size = os_filesize(fd);
|
|
desc = dev_get_uclass_plat(blk);
|
|
if (size % desc->blksz) {
|
|
printf("The size of host backing file '%s' is not multiple of "
|
|
"the device block size\n", filename);
|
|
ret = -EINVAL;
|
|
goto err_fname;
|
|
}
|
|
desc->lba = size / desc->blksz;
|
|
|
|
/* write this in last, when nothing can go wrong */
|
|
plat = dev_get_plat(dev);
|
|
plat->fd = fd;
|
|
plat->filename = fname;
|
|
|
|
return 0;
|
|
|
|
err_fname:
|
|
os_close(fd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int host_sb_detach_file(struct udevice *dev)
|
|
{
|
|
struct host_sb_plat *plat = dev_get_plat(dev);
|
|
int ret;
|
|
|
|
if (!plat->fd)
|
|
return log_msg_ret("fd", -ENOENT);
|
|
|
|
ret = device_remove(dev, DM_REMOVE_NORMAL);
|
|
if (ret)
|
|
return log_msg_ret("rem", ret);
|
|
|
|
/* Unbind all children */
|
|
ret = device_chld_unbind(dev, NULL);
|
|
if (ret)
|
|
return log_msg_ret("unb", ret);
|
|
|
|
os_close(plat->fd);
|
|
plat->fd = 0;
|
|
free(plat->filename);
|
|
free(plat->label);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int host_sb_bind(struct udevice *dev)
|
|
{
|
|
struct udevice *blk, *bdev;
|
|
struct blk_desc *desc;
|
|
int ret;
|
|
|
|
ret = blk_create_devicef(dev, "sandbox_host_blk", "blk", UCLASS_HOST,
|
|
dev_seq(dev), DEFAULT_BLKSZ, 0, &blk);
|
|
if (ret)
|
|
return log_msg_ret("blk", ret);
|
|
|
|
desc = dev_get_uclass_plat(blk);
|
|
snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot");
|
|
snprintf(desc->product, BLK_PRD_SIZE, "hostfile");
|
|
snprintf(desc->revision, BLK_REV_SIZE, "1.0");
|
|
|
|
if (CONFIG_IS_ENABLED(BOOTSTD)) {
|
|
ret = bootdev_bind(dev, "host_bootdev", "bootdev", &bdev);
|
|
if (ret)
|
|
return log_msg_ret("bd", ret);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct host_ops host_sb_ops = {
|
|
.attach_file = host_sb_attach_file,
|
|
.detach_file = host_sb_detach_file,
|
|
};
|
|
|
|
static const struct udevice_id host_ids[] = {
|
|
{ .compatible = "sandbox,host" },
|
|
{ }
|
|
};
|
|
|
|
U_BOOT_DRIVER(host_sb_drv) = {
|
|
.name = "host_sb_drv",
|
|
.id = UCLASS_HOST,
|
|
.of_match = host_ids,
|
|
.ops = &host_sb_ops,
|
|
.bind = host_sb_bind,
|
|
.plat_auto = sizeof(struct host_sb_plat),
|
|
};
|