summaryrefslogtreecommitdiffstats
path: root/arch/sandbox
diff options
context:
space:
mode:
authorAhmad Fatoum <a.fatoum@pengutronix.de>2020-09-14 15:37:48 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2020-09-15 14:42:49 +0200
commita1f6b4dbcdfd85c82e7ccd1e6be82264d16019ee (patch)
tree8464a69c8021c68531241594a499618bef894026 /arch/sandbox
parentc8773d5c22a2d6ded9bb3060842f1f62bc5dd945 (diff)
downloadbarebox-a1f6b4dbcdfd85c82e7ccd1e6be82264d16019ee.tar.gz
barebox-a1f6b4dbcdfd85c82e7ccd1e6be82264d16019ee.tar.xz
sandbox: hostfile: support registering images as barebox block devices
While we can mount file systems on cdevs in barebox, partition table parsing only works for block devices. Allow for --image=argument,blkdev to try to mount an image as block device. This will fail for files that aren't of a multiple of the 512 byte block size. Host OS block devices are suitable for use as barebox block devices always, so that's the default unless overridden with a ,cdev suffix. The initcall level has been changed to occur after fs initcall level. This is required, because we can't have automounts without / mounted. Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/sandbox')
-rw-r--r--arch/sandbox/Kconfig3
-rw-r--r--arch/sandbox/board/hostfile.c116
-rw-r--r--arch/sandbox/mach-sandbox/include/mach/hostfile.h1
-rw-r--r--arch/sandbox/os/common.c15
4 files changed, 109 insertions, 26 deletions
diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index b5213c662b..26011720df 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -7,6 +7,9 @@ config SANDBOX
select ARCH_HAS_UBSAN_SANITIZE_ALL
select HAVE_ARCH_KASAN
select HAS_DMA
+ select BLOCK
+ select BLOCK_WRITE
+ select PARTITION_DISK
default y
config ARCH_TEXT_BASE
diff --git a/arch/sandbox/board/hostfile.c b/arch/sandbox/board/hostfile.c
index 07287fc0b4..63530bd25e 100644
--- a/arch/sandbox/board/hostfile.c
+++ b/arch/sandbox/board/hostfile.c
@@ -16,6 +16,8 @@
#include <common.h>
#include <driver.h>
+#include <block.h>
+#include <disks.h>
#include <malloc.h>
#include <mach/linux.h>
#include <init.h>
@@ -27,14 +29,16 @@
#include <linux/err.h>
struct hf_priv {
- struct cdev cdev;
+ union {
+ struct block_device blk;
+ struct cdev cdev;
+ };
const char *filename;
int fd;
};
-static ssize_t hf_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags)
+static ssize_t hf_read(struct hf_priv *priv, void *buf, size_t count, loff_t offset, ulong flags)
{
- struct hf_priv *priv= cdev->priv;
int fd = priv->fd;
if (linux_lseek(fd, offset) != offset)
@@ -43,9 +47,8 @@ static ssize_t hf_read(struct cdev *cdev, void *buf, size_t count, loff_t offset
return linux_read(fd, buf, count);
}
-static ssize_t hf_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags)
+static ssize_t hf_write(struct hf_priv *priv, const void *buf, size_t count, loff_t offset, ulong flags)
{
- struct hf_priv *priv = cdev->priv;
int fd = priv->fd;
if (linux_lseek(fd, offset) != offset)
@@ -54,6 +57,40 @@ static ssize_t hf_write(struct cdev *cdev, const void *buf, size_t count, loff_t
return linux_write(fd, buf, count);
}
+static ssize_t hf_cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags)
+{
+ return hf_read(cdev->priv, buf, count, offset, flags);
+}
+
+static ssize_t hf_cdev_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags)
+{
+ return hf_write(cdev->priv, buf, count, offset, flags);
+}
+
+static struct cdev_operations hf_cdev_ops = {
+ .read = hf_cdev_read,
+ .write = hf_cdev_write,
+};
+
+static int hf_blk_read(struct block_device *blk, void *buf, int block, int num_blocks)
+{
+ ssize_t ret = hf_read(container_of(blk, struct hf_priv, blk), buf,
+ num_blocks << SECTOR_SHIFT, block << SECTOR_SHIFT, 0);
+ return ret > 0 ? 0 : ret;
+}
+
+static int hf_blk_write(struct block_device *blk, const void *buf, int block, int num_blocks)
+{
+ ssize_t ret = hf_write(container_of(blk, struct hf_priv, blk), buf,
+ num_blocks << SECTOR_SHIFT, block << SECTOR_SHIFT, 0);
+ return ret > 0 ? 0 : ret;
+}
+
+static struct block_device_ops hf_blk_ops = {
+ .read = hf_blk_read,
+ .write = hf_blk_write,
+};
+
static void hf_info(struct device_d *dev)
{
struct hf_priv *priv = dev->priv;
@@ -61,29 +98,28 @@ static void hf_info(struct device_d *dev)
printf("file: %s\n", priv->filename);
}
-static struct cdev_operations hf_fops = {
- .read = hf_read,
- .write = hf_write,
-};
-
static int hf_probe(struct device_d *dev)
{
+ struct device_node *np = dev->device_node;
struct hf_priv *priv = xzalloc(sizeof(*priv));
struct resource *res;
+ struct cdev *cdev;
+ bool is_blockdev;
+ resource_size_t size;
int err;
res = dev_get_resource(dev, IORESOURCE_MEM, 0);
if (IS_ERR(res))
return PTR_ERR(res);
- priv->cdev.size = resource_size(res);
+ size = resource_size(res);
- if (!dev->device_node)
+ if (!np)
return -ENODEV;
- of_property_read_u32(dev->device_node, "barebox,fd", &priv->fd);
+ of_property_read_u32(np, "barebox,fd", &priv->fd);
- err = of_property_read_string(dev->device_node, "barebox,filename",
+ err = of_property_read_string(np, "barebox,filename",
&priv->filename);
if (err)
return err;
@@ -94,20 +130,47 @@ static int hf_probe(struct device_d *dev)
if (priv->fd < 0)
return priv->fd;
- priv->cdev.name = dev->device_node->name;
- priv->cdev.dev = dev;
- priv->cdev.ops = &hf_fops;
- priv->cdev.priv = priv;
-
dev->info = hf_info;
dev->priv = priv;
- err = devfs_create(&priv->cdev);
- if (err)
- return err;
+ is_blockdev = of_property_read_bool(np, "barebox,blockdev");
+
+ cdev = is_blockdev ? &priv->blk.cdev : &priv->cdev;
+
+ cdev->device_node = np;
- of_parse_partitions(&priv->cdev, dev->device_node);
- of_partitions_register_fixup(&priv->cdev);
+ if (is_blockdev) {
+ cdev->name = np->name;
+ priv->blk.dev = dev;
+ priv->blk.ops = &hf_blk_ops;
+ priv->blk.blockbits = SECTOR_SHIFT;
+ priv->blk.num_blocks = size / SECTOR_SIZE;
+
+ err = blockdevice_register(&priv->blk);
+ if (err)
+ return err;
+
+ err = parse_partition_table(&priv->blk);
+ if (err)
+ dev_warn(dev, "No partition table found\n");
+
+ dev_info(dev, "registered as block device\n");
+ } else {
+ cdev->name = np->name;
+ cdev->dev = dev;
+ cdev->ops = &hf_cdev_ops;
+ cdev->size = size;
+ cdev->priv = priv;
+
+ err = devfs_create(cdev);
+ if (err)
+ return err;
+
+ dev_info(dev, "registered as character device\n");
+ }
+
+ of_parse_partitions(cdev, np);
+ of_partitions_register_fixup(cdev);
return 0;
}
@@ -125,7 +188,7 @@ static struct driver_d hf_drv = {
.of_compatible = DRV_OF_COMPAT(hostfile_dt_ids),
.probe = hf_probe,
};
-coredevice_platform_driver(hf_drv);
+device_platform_driver(hf_drv);
static int of_hostfile_fixup(struct device_node *root, void *ctx)
{
@@ -155,6 +218,9 @@ static int of_hostfile_fixup(struct device_node *root, void *ctx)
ret = of_property_write_string(node, "barebox,filename", hf->filename);
+ if (hf->is_blockdev)
+ ret = of_property_write_bool(node, "barebox,blockdev", true);
+
return ret;
}
diff --git a/arch/sandbox/mach-sandbox/include/mach/hostfile.h b/arch/sandbox/mach-sandbox/include/mach/hostfile.h
index e2f44c4f7b..c3f9af97c4 100644
--- a/arch/sandbox/mach-sandbox/include/mach/hostfile.h
+++ b/arch/sandbox/mach-sandbox/include/mach/hostfile.h
@@ -7,6 +7,7 @@ struct hf_info {
unsigned long long size;
const char *devname;
const char *filename;
+ unsigned int is_blockdev:1;
};
int barebox_register_filedev(struct hf_info *hf);
diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c
index 9d59418136..d0addef5af 100644
--- a/arch/sandbox/os/common.c
+++ b/arch/sandbox/os/common.c
@@ -252,7 +252,7 @@ static int add_image(const char *_str, char *devname_template, int *devname_numb
struct hf_info *hf = malloc(sizeof(struct hf_info));
char *str, *filename, *devname;
char tmp[16];
- int readonly = 0;
+ int readonly = 0, cdev = 0, blkdev = 0;
struct stat s;
char *opt;
int fd, ret;
@@ -266,6 +266,10 @@ static int add_image(const char *_str, char *devname_template, int *devname_numb
while ((opt = strsep_unescaped(&str, ","))) {
if (!strcmp(opt, "ro"))
readonly = 1;
+ if (!strcmp(opt, "cdev"))
+ cdev = 1;
+ if (!strcmp(opt, "blkdev"))
+ blkdev = 1;
}
/* parses: "devname=filename" */
@@ -284,6 +288,7 @@ static int add_image(const char *_str, char *devname_template, int *devname_numb
fd = open(filename, (readonly ? O_RDONLY : O_RDWR) | O_CLOEXEC);
hf->fd = fd;
hf->filename = filename;
+ hf->is_blockdev = blkdev;
if (fd < 0) {
perror("open");
@@ -303,6 +308,8 @@ static int add_image(const char *_str, char *devname_template, int *devname_numb
perror("ioctl");
goto err_out;
}
+ if (!cdev)
+ hf->is_blockdev = 1;
}
if (hf->size <= SIZE_MAX)
hf->base = (unsigned long)mmap(NULL, hf->size,
@@ -314,6 +321,12 @@ static int add_image(const char *_str, char *devname_template, int *devname_numb
if (hf->base == (unsigned long)MAP_FAILED)
printf("warning: mmapping %s failed: %s\n", filename, strerror(errno));
+ if (blkdev && hf->size % 512 != 0) {
+ printf("warning: registering %s as block device failed: invalid block size\n",
+ filename);
+ return -EINVAL;
+ }
+
ret = barebox_register_filedev(hf);
if (ret)
goto err_out;