From ae3d2a171fe2f091adf4d084962df7415a6845e8 Mon Sep 17 00:00:00 2001
From: Alexey Makhalov <amakhalov@vmware.com>
Date: Fri, 22 Dec 2017 15:13:17 -0800
Subject: [PATCH] vsock transport for 9p

This second and correct implementation of 9p support over vsock.
Second implementation addresses the issue, described in PR 2007859.

Author: Adrian Drzewiecki <adriand@vmware.com>

Here's a patch which adds a new transport type instead, following the
methods that are used for others. That is, instead of doing

$ mount -t9p -ovsock=1234 fubar /mnt

One would do:

$ mount -t9p -otrans=vsock 1234 /mnt
---
 net/9p/trans_fd.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 985046ae..322a6bc8 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -37,6 +37,8 @@
 #include <linux/un.h>
 #include <linux/uaccess.h>
 #include <linux/inet.h>
+#include <linux/vmw_vmci_defs.h>
+#include <uapi/linux/vm_sockets.h>
 #include <linux/idr.h>
 #include <linux/file.h>
 #include <linux/parser.h>
@@ -938,6 +940,59 @@ static int p9_bind_privport(struct socket *sock)
 	return err;
 }
 
+static int
+p9_fd_create_vsock(struct p9_client *client, const char *addr, char *args)
+{
+	int err;
+	struct socket *csocket;
+	struct sockaddr_vm vsock_server;
+	struct p9_fd_opts opts;
+
+	err = parse_opts(args, &opts);
+	if (err < 0)
+		return err;
+
+	csocket = NULL;
+
+	memset(&vsock_server, 0, sizeof(struct sockaddr_vm));
+	vsock_server.svm_family = AF_VSOCK;
+	vsock_server.svm_port = opts.port;
+
+	err = kstrtou32(addr, 0, &vsock_server.svm_cid);
+	if (err < 0)
+		return err;
+
+	err = __sock_create(current->nsproxy->net_ns, PF_VSOCK,
+			    SOCK_STREAM, 0, &csocket, 1);
+	if (err) {
+		pr_err("%s (%d): problem creating socket\n",
+		       __func__, task_pid_nr(current));
+		return err;
+	}
+
+	/* XXX: applicable? */
+	if (opts.privport) {
+		err = p9_bind_privport(csocket);
+		if (err < 0) {
+			pr_err("%s (%d): problem binding to privport\n",
+			       __func__, task_pid_nr(current));
+			sock_release(csocket);
+			return err;
+		}
+	}
+
+	err = csocket->ops->connect(csocket,
+				    (struct sockaddr *)&vsock_server,
+				    sizeof(struct sockaddr_vm), 0);
+	if (err < 0) {
+		pr_err("%s (%d): problem connecting vmware vsock addr %s\n",
+		       __func__, task_pid_nr(current), addr);
+		sock_release(csocket);
+		return err;
+	}
+
+	return p9_socket_open(client, csocket);
+}
 
 static int
 p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
@@ -1053,6 +1108,18 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args)
 	return 0;
 }
 
+static struct p9_trans_module p9_vsock_trans = {
+	.name = "vsock",
+	.maxsize = MAX_SOCK_BUF,
+	.def = 0,
+	.create = p9_fd_create_vsock,
+	.close = p9_fd_close,
+	.request = p9_fd_request,
+	.cancel = p9_fd_cancel,
+	.cancelled = p9_fd_cancelled,
+	.owner = THIS_MODULE,
+};
+
 static struct p9_trans_module p9_tcp_trans = {
 	.name = "tcp",
 	.maxsize = MAX_SOCK_BUF,
@@ -1126,6 +1193,7 @@ static void p9_poll_workfn(struct work_struct *work)
 
 int p9_trans_fd_init(void)
 {
+	v9fs_register_trans(&p9_vsock_trans);
 	v9fs_register_trans(&p9_tcp_trans);
 	v9fs_register_trans(&p9_unix_trans);
 	v9fs_register_trans(&p9_fd_trans);
-- 
2.11.0