summaryrefslogtreecommitdiffstats
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
parent7bcbc91a5eb2c3fbb3a6d67103ca0ff8fc8e4412 (diff)
downloadbarebox-f3cd5b1bbcb27108496eb572ae2ff7cd526ddc55.tar.gz
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>
-rw-r--r--fs/Makefile4
-rw-r--r--fs/devfs-core.c90
-rw-r--r--fs/fs.c22
-rw-r--r--include/driver.h2
-rw-r--r--include/fs.h1
5 files changed, 113 insertions, 6 deletions
diff --git a/fs/Makefile b/fs/Makefile
index f2bb702..b3f929f 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -4,11 +4,11 @@ obj-$(CONFIG_FS_RAMFS) += ramfs.o
obj-y += devfs-core.o
obj-$(CONFIG_FS_DEVFS) += devfs.o
obj-$(CONFIG_FS_FAT) += fat/
-obj-y += fs.o
+obj-y += fs.o parseopt.o
obj-$(CONFIG_FS_UBIFS) += ubifs/
obj-$(CONFIG_FS_TFTP) += tftp.o
obj-$(CONFIG_FS_OMAP4_USBBOOT) += omap4_usbbootfs.o
-obj-$(CONFIG_FS_NFS) += nfs.o parseopt.o
+obj-$(CONFIG_FS_NFS) += nfs.o
obj-$(CONFIG_FS_BPKFS) += bpkfs.o
obj-$(CONFIG_FS_UIMAGEFS) += uimagefs.o
obj-$(CONFIG_FS_EFI) += efi.o
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index 26fffbb..3368d3e 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);
+}
diff --git a/fs/fs.c b/fs/fs.c
index 9a5887f..6081596 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -36,6 +36,8 @@
#include <block.h>
#include <libfile.h>
+#include "parseopt.h"
+
char *mkmodestr(unsigned long mode, char *str)
{
static const char *l = "xwr";
@@ -1210,6 +1212,9 @@ static void fs_remove(struct device_d *dev)
if (fsdev->cdev)
cdev_close(fsdev->cdev);
+ if (fsdev->loop)
+ cdev_remove_loop(fsdev->cdev);
+
free(fsdev->backingstore);
free(fsdev);
}
@@ -1236,13 +1241,18 @@ int register_fs_driver(struct fs_driver_d *fsdrv)
}
EXPORT_SYMBOL(register_fs_driver);
-static const char *detect_fs(const char *filename)
+static const char *detect_fs(const char *filename, const char *fsoptions)
{
enum filetype type;
struct driver_d *drv;
struct fs_driver_d *fdrv;
+ bool loop;
- type = cdev_detect_type(filename);
+ parseopt_b(fsoptions, "loop", &loop);
+ if (loop)
+ type = file_name_detect_type(filename);
+ else
+ type = cdev_detect_type(filename);
if (type == filetype_unknown)
return NULL;
@@ -1259,7 +1269,11 @@ static const char *detect_fs(const char *filename)
int fsdev_open_cdev(struct fs_device_d *fsdev)
{
- fsdev->cdev = cdev_open(fsdev->backingstore, O_RDWR);
+ parseopt_b(fsdev->options, "loop", &fsdev->loop);
+ if (fsdev->loop)
+ fsdev->cdev = cdev_create_loop(fsdev->backingstore, O_RDWR);
+ else
+ fsdev->cdev = cdev_open(fsdev->backingstore, O_RDWR);
if (!fsdev->cdev)
return -EINVAL;
@@ -1306,7 +1320,7 @@ int mount(const char *device, const char *fsname, const char *_path,
}
if (!fsname)
- fsname = detect_fs(device);
+ fsname = detect_fs(device, fsoptions);
if (!fsname)
return -ENOENT;
diff --git a/include/driver.h b/include/driver.h
index 1edc157..3d701f2 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -473,6 +473,8 @@ struct cdev *lcdev_by_name(const char *filename);
struct cdev *cdev_readlink(struct cdev *cdev);
struct cdev *cdev_by_device_node(struct device_node *node);
struct cdev *cdev_open(const char *name, unsigned long flags);
+struct cdev *cdev_create_loop(const char *path, ulong flags);
+void cdev_remove_loop(struct cdev *cdev);
int cdev_do_open(struct cdev *, unsigned long flags);
void cdev_close(struct cdev *cdev);
int cdev_flush(struct cdev *cdev);
diff --git a/include/fs.h b/include/fs.h
index 6a59289..1b40ff5 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -92,6 +92,7 @@ struct fs_device_d {
struct fs_driver_d *driver;
struct cdev *cdev;
+ bool loop;
char *path;
struct device_d *parent_device;
struct list_head list;