summaryrefslogtreecommitdiffstats
path: root/fs/devfs-core.c
diff options
context:
space:
mode:
authorPhilipp Zabel <p.zabel@pengutronix.de>2017-06-01 12:37:29 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2017-06-06 09:16:23 +0200
commitf3cd5b1bbcb27108496eb572ae2ff7cd526ddc55 (patch)
tree4a0e5586df03dd50f6190525c5cb71db34128113 /fs/devfs-core.c
parent7bcbc91a5eb2c3fbb3a6d67103ca0ff8fc8e4412 (diff)
downloadbarebox-f3cd5b1bbcb27108496eb572ae2ff7cd526ddc55.tar.gz
barebox-f3cd5b1bbcb27108496eb572ae2ff7cd526ddc55.tar.xz
fs: add cdev_create_loop and cdev_remove_loop for loop mount option
Allow to create a loopback cdev from a file. Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Fixed up with: fs: Makefile: Add parseopt to all builds parseopt.h was included to fs.c with commit 9248b, but parseopt.o has a dependency to CONFIG_FS_NFS. Moved parseopt.o to the default build to eliminate build failures. Signed-off-by: Daniel Schultz <d.schultz@phytec.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'fs/devfs-core.c')
-rw-r--r--fs/devfs-core.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index 26fffbb6c2..3368d3ed68 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -20,11 +20,14 @@
#include <complete.h>
#include <driver.h>
#include <errno.h>
+#include <fcntl.h>
#include <malloc.h>
#include <ioctl.h>
#include <nand.h>
#include <linux/err.h>
+#include <linux/fs.h>
#include <linux/mtd/mtd.h>
+#include <unistd.h>
LIST_HEAD(cdev_list);
@@ -409,3 +412,90 @@ int devfs_create_partitions(const char *devname,
return 0;
}
+
+struct loop_priv {
+ int fd;
+};
+
+static ssize_t loop_read(struct cdev *cdev, void *buf, size_t count,
+ loff_t offset, ulong flags)
+{
+ struct loop_priv *priv = cdev->priv;
+ loff_t ofs;
+
+ ofs = lseek(priv->fd, offset, SEEK_SET);
+ if (ofs < 0)
+ return ofs;
+
+ return read(priv->fd, buf, count);
+}
+
+static ssize_t loop_write(struct cdev *cdev, const void *buf, size_t count,
+ loff_t offset, ulong flags)
+{
+ struct loop_priv *priv = cdev->priv;
+ loff_t ofs;
+
+ ofs = lseek(priv->fd, offset, SEEK_SET);
+ if (ofs < 0)
+ return ofs;
+
+ return write(priv->fd, buf, count);
+}
+
+static const struct file_operations loop_ops = {
+ .read = loop_read,
+ .write = loop_write,
+ .memmap = generic_memmap_rw,
+ .lseek = dev_lseek_default,
+};
+
+struct cdev *cdev_create_loop(const char *path, ulong flags)
+{
+ struct cdev *new;
+ struct loop_priv *priv;
+ static int loopno;
+ loff_t ofs;
+
+ priv = xzalloc(sizeof(*priv));
+
+ priv->fd = open(path, flags);
+ if (priv->fd < 0) {
+ free(priv);
+ return NULL;
+ }
+
+ new = xzalloc(sizeof(*new));
+
+ new->ops = &loop_ops;
+ new->name = basprintf("loop%u", loopno++);
+ new->priv = priv;
+
+ ofs = lseek(priv->fd, 0, SEEK_END);
+ if (ofs < 0) {
+ free(new);
+ free(priv);
+ return NULL;
+ }
+ lseek(priv->fd, 0, SEEK_SET);
+
+ new->size = ofs;
+ new->offset = 0;
+ new->dev = NULL;
+ new->flags = 0;
+
+ devfs_create(new);
+
+ return new;
+}
+
+void cdev_remove_loop(struct cdev *cdev)
+{
+ struct loop_priv *priv = cdev->priv;
+
+ devfs_remove(cdev);
+ close(priv->fd);
+ free(priv);
+ free(cdev->name);
+ free(cdev);
+}