[PATCH 15/21] block: add lightweight ramdisk support

Ahmad Fatoum a.fatoum at pengutronix.de
Thu Jun 5 04:35:24 PDT 2025


The partitions code in barebox expects a block device to operate on and
not raw memory buffers. Add an abstraction that wraps a raw memory
buffer as block device in a very lightweight manner as not to impede
fuzzing speed.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/block/Kconfig   |   6 ++
 drivers/block/Makefile  |   1 +
 drivers/block/ramdisk.c | 178 ++++++++++++++++++++++++++++++++++++++++
 include/ramdisk.h       |  24 ++++++
 4 files changed, 209 insertions(+)
 create mode 100644 drivers/block/ramdisk.c
 create mode 100644 include/ramdisk.h

diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index bf8dfdbd5c12..5b1b7789171c 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -26,3 +26,9 @@ config EFI_BLK_SEPARATE_USBDISK
 	  for your disk and checking against it with
 
 	    devlookup -v $bootguid /dev/disk$bootsource_instance guid
+
+config RAMDISK_BLK
+        bool
+        help
+	  This symbol is selected by testing code that requires lightweight
+	  creation of anonymous block devices backed fully by memory buffers.
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index a4e14a559cf7..6066b35c313e 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_EFI_BLK) += efi-block-io.o
 obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
+obj-$(CONFIG_RAMDISK_BLK) += ramdisk.o
diff --git a/drivers/block/ramdisk.c b/drivers/block/ramdisk.c
new file mode 100644
index 000000000000..6f3c9348058a
--- /dev/null
+++ b/drivers/block/ramdisk.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// lightweight anonymous block device wrapper around memory buffers
+
+#include <ramdisk.h>
+#include <block.h>
+#include <driver.h>
+#include <fs.h>
+#include <string.h>
+#include <xfuncs.h>
+#include <linux/align.h>
+#include <linux/log2.h>
+
+struct ramdisk {
+	struct block_device blk;
+	struct device dev;
+	union {
+		void *base_rw;
+		const void *base_ro;
+	};
+	size_t size;
+	bool ro;
+};
+
+static int ramdisk_check_read(const struct ramdisk *ramdisk)
+{
+	return ramdisk->base_ro ? 1 : 0;
+}
+
+static ssize_t ramdisk_read(struct cdev *cdev, void *buf, size_t count,
+			    loff_t offset, unsigned long flags)
+{
+	struct ramdisk *ramdisk = cdev->priv;
+	size_t cpy_count, pad_count;
+	int ret;
+
+	ret = ramdisk_check_read(ramdisk);
+	if (ret < 1)
+		return ret;
+
+	if (size_add(offset, count) > ramdisk->size)
+		return -ENXIO;
+
+	cpy_count = min_t(size_t, count, ramdisk->size - offset);
+	buf = mempcpy(buf, ramdisk->base_ro + offset, cpy_count);
+
+	pad_count = min_t(size_t, count, cdev->size - offset) - cpy_count;
+
+	memset(buf, 0x00, pad_count);
+
+	pr_vdebug("read %zu bytes\n", cpy_count + pad_count);
+
+	return cpy_count + pad_count;
+}
+
+static int ramdisk_check_write(const struct ramdisk *ramdisk)
+{
+	if (!ramdisk->base_rw)
+		return -EPERM;
+	if (ramdisk->ro)
+		return -EACCES;
+	return 1;
+}
+
+static ssize_t ramdisk_write(struct cdev *cdev, const void *buf, size_t count,
+		  loff_t offset, unsigned long flags)
+{
+	struct ramdisk *ramdisk = cdev->priv;
+	int ret;
+
+	ret = ramdisk_check_write(ramdisk);
+	if (ret < 1)
+		return ret;
+	if (size_add(offset, count) > ramdisk->size)
+		return -ENXIO;
+
+	memcpy(ramdisk->base_rw + offset, buf,
+	       min_t(size_t, count, ramdisk->size - offset));
+
+	return count;
+}
+
+static int ramdisk_memmap(struct cdev *cdev, void **map, int flags)
+{
+	struct ramdisk *ramdisk = cdev->priv;
+	int ret;
+
+	ret = flags & PROT_WRITE ? ramdisk_check_write(ramdisk)
+			         : ramdisk_check_read(ramdisk);
+	if (ret < 1)
+		return ret;
+
+	*map = ramdisk->base_rw;
+	return 0;
+}
+
+static struct cdev_operations ramdisk_ops = {
+	.read  = ramdisk_read,
+	.write = ramdisk_write,
+	.memmap = ramdisk_memmap,
+};
+
+struct ramdisk *ramdisk_init(int sector_size)
+{
+	struct ramdisk *ramdisk;
+	struct block_device *blk;
+	int ret;
+
+	ramdisk = xzalloc(sizeof(*ramdisk));
+
+	dev_set_name(&ramdisk->dev, "ramdisk");
+	ramdisk->dev.id = DEVICE_ID_DYNAMIC;
+
+	ret = register_device(&ramdisk->dev);
+	if (ret)
+		return NULL;
+
+	blk = &ramdisk->blk;
+	blk->dev = &ramdisk->dev;
+	blk->type = BLK_TYPE_VIRTUAL;
+
+	blk->cdev.size = 0;
+	blk->cdev.name = xstrdup(dev_name(&ramdisk->dev));
+	blk->cdev.dev = blk->dev;
+	blk->cdev.ops = &ramdisk_ops;
+	blk->cdev.priv = ramdisk;
+	blk->cdev.flags |= DEVFS_IS_BLOCK_DEV;
+	blk->blockbits = ilog2(sector_size);
+
+	ret = devfs_create(&blk->cdev);
+	if (ret)
+		return NULL;
+
+	INIT_LIST_HEAD(&blk->buffered_blocks);
+	INIT_LIST_HEAD(&blk->idle_blocks);
+
+	return ramdisk;
+}
+
+struct block_device *ramdisk_get_block_device(struct ramdisk *ramdisk)
+{
+	return &ramdisk->blk;
+}
+
+void ramdisk_free(struct ramdisk *ramdisk)
+{
+	devfs_remove(&ramdisk->blk.cdev);
+	unregister_device(&ramdisk->dev);
+	free(ramdisk);
+}
+
+static void ramdisk_setup_size(struct ramdisk *ramdisk, size_t size)
+{
+	ramdisk->size = size;
+	ramdisk->blk.cdev.size = ALIGN(size, 1 << ramdisk->blk.blockbits);
+}
+
+void ramdisk_setup_ro(struct ramdisk *ramdisk, const void *data, size_t size)
+{
+	ramdisk->ro = true;
+	ramdisk->base_ro = data;
+	ramdisk_setup_size(ramdisk, size);
+}
+
+const void *ramdisk_mmap(struct ramdisk *ramdisk, loff_t offset,
+			 size_t size)
+{
+	if (size_add(offset, size) > ramdisk->size)
+		return NULL;
+
+	return ramdisk->base_ro + offset;
+}
+
+void ramdisk_setup_rw(struct ramdisk *ramdisk, void *data, size_t size)
+{
+	ramdisk->ro = false;
+	ramdisk->base_rw = data;
+	ramdisk_setup_size(ramdisk, size);
+}
diff --git a/include/ramdisk.h b/include/ramdisk.h
new file mode 100644
index 000000000000..b256a9c12ca7
--- /dev/null
+++ b/include/ramdisk.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __RAMDISK_H_
+#define __RAMDISK_H_
+
+#include <linux/types.h>
+
+struct ramdisk;
+struct block_device;
+
+struct ramdisk *ramdisk_init(int sector_size);
+void ramdisk_free(struct ramdisk *ramdisk);
+
+struct block_device *ramdisk_get_block_device(struct ramdisk *ramdisk);
+
+void ramdisk_setup_ro(struct ramdisk *ramdisk, const void *data, size_t size);
+void ramdisk_setup_rw(struct ramdisk *ramdisk, void *data, size_t size);
+
+const void *ramdisk_mmap(struct ramdisk *ramdisk, loff_t offset, size_t size);
+static inline void ramdisk_munmap(struct ramdisk *ramdisk,
+				  void *ptr, loff_t offset,
+				  size_t size) {}
+
+#endif
-- 
2.39.5




More information about the barebox mailing list