From a1f6b4dbcdfd85c82e7ccd1e6be82264d16019ee Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 14 Sep 2020 15:37:48 +0200 Subject: 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 Signed-off-by: Sascha Hauer --- arch/sandbox/Kconfig | 3 + arch/sandbox/board/hostfile.c | 116 +++++++++++++++++----- arch/sandbox/mach-sandbox/include/mach/hostfile.h | 1 + arch/sandbox/os/common.c | 15 ++- 4 files changed, 109 insertions(+), 26 deletions(-) (limited to 'arch/sandbox') 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 #include +#include +#include #include #include #include @@ -27,14 +29,16 @@ #include 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; -- cgit v1.2.3