[PATCH 3/8] fs: Add RATP fs support

Sascha Hauer s.hauer at pengutronix.de
Fri Jan 8 03:13:50 PST 2016


From: Jan Luebbe <jlu at pengutronix.de>

This adds file transfer support over RATP. The host can export a
directory using the bbremote tool which can then be mounted under
barebox as a filesystem.

Signed-off-by: Jan Luebbe <jlu at pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 fs/Kconfig  |   8 +
 fs/Makefile |   2 +-
 fs/ratpfs.c | 476 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 485 insertions(+), 1 deletion(-)
 create mode 100644 fs/ratpfs.c

diff --git a/fs/Kconfig b/fs/Kconfig
index 9217bc8..9cfeb37 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -89,4 +89,12 @@ config FS_SMHFS
 	  located on a debugging host connected to the target running
 	  Barebox
 
+config FS_RATP
+	bool
+	depends on CONSOLE_RATP
+	prompt "RATP filesystem support"
+	help
+	  This enables support for transferring files over RATP. A host can
+	  export a directory which can then be mounted under barebox.
+
 endmenu
diff --git a/fs/Makefile b/fs/Makefile
index befbdf2..714acb4 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -14,4 +14,4 @@ obj-$(CONFIG_FS_UIMAGEFS)	+= uimagefs.o
 obj-$(CONFIG_FS_EFI)	 += efi.o
 obj-$(CONFIG_FS_EFIVARFS) += efivarfs.o
 obj-$(CONFIG_FS_SMHFS) += smhfs.o
-obj-$(CONFIG_RATP)	+= ratpfs.o
+obj-$(CONFIG_FS_RATP)	+= ratpfs.o
diff --git a/fs/ratpfs.c b/fs/ratpfs.c
new file mode 100644
index 0000000..902289b
--- /dev/null
+++ b/fs/ratpfs.c
@@ -0,0 +1,476 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "barebox-ratpfs: " fmt
+
+#include <common.h>
+#include <command.h>
+#include <init.h>
+#include <malloc.h>
+#include <fs.h>
+#include <errno.h>
+#include <linux/stat.h>
+#include <asm/unaligned.h>
+#include <ratp_bb.h>
+
+#define RATPFS_TYPE_MOUNT_CALL       1
+#define RATPFS_TYPE_MOUNT_RETURN     2
+#define RATPFS_TYPE_READDIR_CALL     3
+#define RATPFS_TYPE_READDIR_RETURN   4
+#define RATPFS_TYPE_STAT_CALL        5
+#define RATPFS_TYPE_STAT_RETURN      6
+#define RATPFS_TYPE_OPEN_CALL        7
+#define RATPFS_TYPE_OPEN_RETURN      8
+#define RATPFS_TYPE_READ_CALL        9
+#define RATPFS_TYPE_READ_RETURN     10
+#define RATPFS_TYPE_WRITE_CALL      11
+#define RATPFS_TYPE_WRITE_RETURN    12
+#define RATPFS_TYPE_CLOSE_CALL      13
+#define RATPFS_TYPE_CLOSE_RETURN    14
+#define RATPFS_TYPE_TRUNCATE_CALL   15
+#define RATPFS_TYPE_TRUNCATE_RETURN 16
+
+struct ratpfs_file {
+	uint32_t handle;
+};
+
+struct ratpfs_dir {
+	char *entries;
+	int len, off;
+	DIR dir;
+};
+
+static int ratpfs_create(struct device_d __always_unused *dev,
+			const char __always_unused *pathname,
+			mode_t __always_unused mode)
+{
+	pr_debug("%s\n", __func__);
+
+	return 0;
+}
+
+static int ratpfs_mkdir(struct device_d __always_unused *dev,
+		       const char __always_unused *pathname)
+{
+	pr_debug("%s\n", __func__);
+
+	return -ENOSYS;
+}
+
+static int ratpfs_rm(struct device_d __always_unused *dev,
+		    const char *pathname)
+{
+	pr_debug("%s\n", __func__);
+
+	/* Get rid of leading '/' */
+	pathname = &pathname[1];
+
+	return 0;
+}
+
+static int ratpfs_truncate(struct device_d __always_unused *dev,
+			  FILE *f, ulong size)
+{
+	int len_tx = 1 /* type */
+		+ 4 /* handle */
+		+ 4 /* size */;
+	struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx)+len_tx);
+	struct ratp_bb_pkt *pkt_rx = NULL;
+	struct ratpfs_file *rfile = f->priv;
+	int ret;
+
+	pr_debug("%s: len_tx=%i handle=%i size=%i\n", __func__,
+		 len_tx, rfile->handle, (int)size);
+
+	pkt_tx->len = len_tx;
+	pkt_tx->data[0] = RATPFS_TYPE_TRUNCATE_CALL;
+	put_unaligned_be32(rfile->handle, &pkt_tx->data[1]);
+	put_unaligned_be32(size, &pkt_tx->data[5]);
+
+	ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx);
+	if (ret) {
+		ret = -EIO;
+		goto out;
+	}
+
+	pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len);
+
+	if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_TRUNCATE_RETURN) {
+		pr_err("invalid truncate response\n");
+		ret = -EIO;
+		goto out;
+	}
+
+out:
+	free(pkt_rx);
+	return ret;
+}
+
+static int ratpfs_open(struct device_d __always_unused *dev,
+		      FILE *file, const char *filename)
+{
+	int len_name = strlen(filename);
+	int len_tx = 1 /* type */
+		+ 4 /* flags */
+		+ len_name /* path */;
+	struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx);
+	struct ratp_bb_pkt *pkt_rx = NULL;
+	struct ratpfs_file *rfile = xzalloc(sizeof(*rfile));
+	int ret;
+
+	pr_debug("%s: len_tx=%i filename='%s'\n", __func__, len_tx, filename);
+
+	pkt_tx->len = len_tx;
+	pkt_tx->data[0] = RATPFS_TYPE_OPEN_CALL;
+	put_unaligned_be32(file->flags, &pkt_tx->data[1]);
+	memcpy(&pkt_tx->data[5], filename, len_name);
+
+	ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx);
+	if (ret) {
+		ret = -EIO;
+		goto err;
+	}
+
+	pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len);
+	if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_OPEN_RETURN) {
+		pr_err("invalid open response\n");
+		ret = -EIO;
+		goto err;
+	}
+	rfile->handle = get_unaligned_be32(&pkt_rx->data[1]);
+	if (rfile->handle == 0) {
+		ret = -get_unaligned_be32(&pkt_rx->data[5]); /* errno */
+		goto err;
+	}
+	file->priv = rfile;
+	file->size = get_unaligned_be32(&pkt_rx->data[5]);
+
+	goto out;
+
+err:
+	file->priv = NULL;
+	free(rfile);
+out:
+	free(pkt_rx);
+	return ret;
+}
+
+static int ratpfs_close(struct device_d __always_unused *dev,
+			FILE *f)
+{
+	int len_tx = 1 /* type */
+		+ 4 /* handle */;
+	struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx);
+	struct ratp_bb_pkt *pkt_rx = NULL;
+	struct ratpfs_file *rfile = f->priv;
+	int ret;
+
+	pr_debug("%s: len_tx=%i handle=%i\n", __func__,
+		 len_tx, rfile->handle);
+
+	pkt_tx->len = len_tx;
+	pkt_tx->data[0] = RATPFS_TYPE_CLOSE_CALL;
+	put_unaligned_be32(rfile->handle, &pkt_tx->data[1]);
+
+	ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx);
+	if (ret) {
+		ret = -EIO;
+		goto out;
+	}
+
+	pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len);
+
+	if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_CLOSE_RETURN) {
+		pr_err("invalid close response\n");
+		goto out;
+	}
+
+out:
+	free(pkt_rx);
+	return ret;
+}
+
+static int ratpfs_write(struct device_d __always_unused *dev,
+			FILE *f, const void *buf, size_t orig_size)
+{
+	int size = min((int)orig_size, 4096);
+	int len_tx = 1 /* type */
+		+ 4 /* handle */
+		+ 4 /* pos */
+		+ size /* data */;
+	struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx);
+	struct ratp_bb_pkt *pkt_rx = NULL;
+	struct ratpfs_file *rfile = f->priv;
+	int ret;
+
+	pr_debug("%s: len_tx=%i handle=%i pos=%i size=%i\n", __func__,
+		 len_tx, rfile->handle, (int)f->pos, size);
+
+	pkt_tx->len = len_tx;
+	pkt_tx->data[0] = RATPFS_TYPE_WRITE_CALL;
+	put_unaligned_be32(rfile->handle, &pkt_tx->data[1]);
+	put_unaligned_be32(f->pos, &pkt_tx->data[5]);
+	memcpy(&pkt_tx->data[9], buf, size);
+
+	ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx);
+	if (ret) {
+		ret = -EIO;
+		goto out;
+	}
+
+	pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len);
+
+	if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_WRITE_RETURN) {
+		pr_err("invalid write response\n");
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = size;
+out:
+	free(pkt_rx);
+
+	return ret;
+}
+
+static int ratpfs_read(struct device_d __always_unused *dev,
+		       FILE *f, void *buf, size_t orig_size)
+{
+	int size = min((int)orig_size, 4096);
+	int len_tx = 1 /* type */
+		+ 4 /* handle */
+		+ 4 /* pos */
+		+ 4 /* size */;
+	struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx);
+	struct ratp_bb_pkt *pkt_rx = NULL;
+	struct ratpfs_file *rfile = f->priv;
+	int ret;
+
+	pr_debug("%s: len_tx=%i handle=%i pos=%i size=%i\n", __func__,
+		 len_tx, rfile->handle, (int)f->pos, size);
+
+	pkt_tx->len = len_tx;
+	pkt_tx->data[0] = RATPFS_TYPE_READ_CALL;
+	put_unaligned_be32(rfile->handle, &pkt_tx->data[1]);
+	put_unaligned_be32(f->pos, &pkt_tx->data[5]);
+	put_unaligned_be32(size, &pkt_tx->data[9]);
+
+	ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx);
+	if (ret) {
+		ret = -EIO;
+		goto out;
+	}
+
+	pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len);
+	if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_READ_RETURN) {
+		pr_err("invalid read response\n");
+		ret = -EIO;
+		goto out;
+	}
+	size = pkt_rx->len - 1;
+	memcpy(buf, &pkt_rx->data[1], size);
+	ret = size;
+
+out:
+	free(pkt_rx);
+	return ret;
+}
+
+static loff_t ratpfs_lseek(struct device_d __always_unused *dev,
+			  FILE *f, loff_t pos)
+{
+	pr_debug("%s\n", __func__);
+	f->pos = pos;
+	return f->pos;
+}
+
+static DIR* ratpfs_opendir(struct device_d __always_unused *dev,
+			  const char *pathname)
+{
+	int len_name = strlen(pathname);
+	int len_tx = 1 /* type */
+		+ len_name /* path */;
+	struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx)+len_tx);
+	struct ratp_bb_pkt *pkt_rx = NULL;
+	struct ratpfs_dir *rdir = xzalloc(sizeof(*rdir));
+	int ret;
+
+	pr_debug("%s: len_tx=%i pathname='%s'\n", __func__, len_tx, pathname);
+
+	pkt_tx->len = len_tx;
+	pkt_tx->data[0] = RATPFS_TYPE_READDIR_CALL;
+	memcpy(&pkt_tx->data[1], pathname, len_name);
+
+	ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx);
+	if (!ret) {
+		pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len);
+		if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_READDIR_RETURN) {
+			pr_err("invalid readdir response\n");
+			free(pkt_rx);
+			return NULL;
+		}
+		rdir->len = pkt_rx->len - 1;
+		rdir->entries = xmemdup(&pkt_rx->data[1], rdir->len);
+		free(pkt_rx);
+		return &rdir->dir;
+	} else {
+		return NULL;
+	}
+}
+
+static struct dirent *ratpfs_readdir(struct device_d *dev, DIR *dir)
+{
+	struct ratpfs_dir *rdir = container_of(dir, struct ratpfs_dir, dir);
+	int i;
+
+	pr_debug("%s\n", __func__);
+
+	if (rdir->len <= rdir->off)
+		return NULL;
+
+	for (i = 0; rdir->off < rdir->len; rdir->off++, i++) {
+		dir->d.d_name[i] = rdir->entries[rdir->off];
+		if (dir->d.d_name[i] == 0)
+			break;
+	}
+	rdir->off++;
+
+	return &dir->d;
+}
+
+static int ratpfs_closedir(struct device_d *dev, DIR *dir)
+{
+	struct ratpfs_dir *rdir = container_of(dir, struct ratpfs_dir, dir);
+
+	pr_debug("%s\n", __func__);
+
+	free(rdir->entries);
+	free(rdir);
+
+	return 0;
+}
+
+static int ratpfs_stat(struct device_d __always_unused *dev,
+		      const char *filename, struct stat *s)
+{
+	int len_name = strlen(filename);
+	int len_tx = 1 /* type */
+		+ len_name; /* path */
+	struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx);
+	struct ratp_bb_pkt *pkt_rx = NULL;
+	int ret;
+
+	pr_debug("%s: len_tx=%i filename='%s'\n", __func__, len_tx, filename);
+
+	pkt_tx->len = len_tx;
+	pkt_tx->data[0] = RATPFS_TYPE_STAT_CALL;
+	memcpy(&pkt_tx->data[1], filename, len_name);
+
+	ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx);
+	if (ret) {
+		ret = -EIO;
+		goto out;
+	}
+
+	pr_debug("%s: len_rx=%i\n", __func__, pkt_rx->len);
+	if (pkt_rx->len < 6 || pkt_rx->data[0] != RATPFS_TYPE_STAT_RETURN) {
+		pr_err("invalid stat response\n");
+		goto out;
+	}
+	switch (pkt_rx->data[1]) {
+	case 0:
+		ret = -ENOENT;
+		break;
+	case 1:
+		s->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
+		break;
+	case 2:
+		s->st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
+		break;
+	}
+	s->st_size = get_unaligned_be32(&pkt_rx->data[2]);
+
+out:
+	free(pkt_rx);
+	return ret;
+}
+
+static int ratpfs_probe(struct device_d *dev)
+{
+	int len_tx = 1; /* type */
+	struct ratp_bb_pkt *pkt_tx = xzalloc(sizeof(*pkt_tx) + len_tx);
+	struct ratp_bb_pkt *pkt_rx = NULL;
+	int ret;
+	struct fs_device_d *fsdev = dev_to_fs_device(dev);
+
+	pr_debug("%s\n", __func__);
+
+	ret = barebox_ratp_fs_mount(fsdev->path);
+	if (ret)
+		return ret;
+
+	pkt_tx->len = len_tx;
+	pkt_tx->data[0] = RATPFS_TYPE_MOUNT_CALL;
+
+	ret = barebox_ratp_fs_call(pkt_tx, &pkt_rx);
+	if (ret)
+		goto out;
+
+	if (pkt_rx->len < 1 || pkt_rx->data[0] != RATPFS_TYPE_MOUNT_RETURN) {
+		pr_err("invalid mount response\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+out:
+	free(pkt_rx);
+
+	if (ret)
+		barebox_ratp_fs_mount(NULL);
+
+	return ret;
+}
+
+static void ratpfs_remove(struct device_d __always_unused *dev)
+{
+	pr_debug("%s\n", __func__);
+
+	barebox_ratp_fs_mount(NULL);
+}
+
+static struct fs_driver_d ratpfs_driver = {
+	.open      = ratpfs_open,
+	.close     = ratpfs_close,
+	.read      = ratpfs_read,
+	.lseek     = ratpfs_lseek,
+	.opendir   = ratpfs_opendir,
+	.readdir   = ratpfs_readdir,
+	.closedir  = ratpfs_closedir,
+	.stat      = ratpfs_stat,
+	.create    = ratpfs_create,
+	.unlink    = ratpfs_rm,
+	.mkdir     = ratpfs_mkdir,
+	.rmdir     = ratpfs_rm,
+	.write     = ratpfs_write,
+	.truncate  = ratpfs_truncate,
+	.flags     = FS_DRIVER_NO_DEV,
+	.drv = {
+		.probe  = ratpfs_probe,
+		.remove = ratpfs_remove,
+		.name = "ratpfs",
+	}
+};
+
+static int ratpfs_init(void)
+{
+	return register_fs_driver(&ratpfs_driver);
+}
+coredevice_initcall(ratpfs_init);
\ No newline at end of file
-- 
2.6.4




More information about the barebox mailing list