[sheepdog] [PATCH v4 RESEND 3/8] sheepdev: add connect.c for network operations
levin li
levin108 at gmail.com
Wed Jan 23 09:16:12 CET 2013
From: levin li <xingke.lwp at taobao.com>
Signed-off-by: levin li <xingke.lwp at taobao.com>
---
sheepdev/Kbuild | 3 +-
sheepdev/connect.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++
sheepdev/sheepdev.h | 7 +++
3 files changed, 187 insertions(+), 1 deletion(-)
create mode 100644 sheepdev/connect.c
diff --git a/sheepdev/Kbuild b/sheepdev/Kbuild
index 0a2c060..16bac26 100644
--- a/sheepdev/Kbuild
+++ b/sheepdev/Kbuild
@@ -5,7 +5,8 @@ ccflags-y := -I$(PWD)/../include
obj-m := $(MODULE_NAME).o
-sheepdev-objs := device.o proc.o
+sheepdev-objs := device.o proc.o connect.o
device.o : sheepdev.h sheepdog_proto.h
proc.o : sheepdev.h
+connect.o : sheepdev.h sheepdog_proto.h
diff --git a/sheepdev/connect.c b/sheepdev/connect.c
new file mode 100644
index 0000000..62138b4
--- /dev/null
+++ b/sheepdev/connect.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2013 Taobao Inc.
+ *
+ * Levin Li <xingke.lwp at taobao.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sheepdev.h"
+#include "sheepdog_proto.h"
+
+int connect_to(struct socket **sock, const char *ip_addr, int port)
+{
+ int ret;
+ struct sockaddr_in addr;
+
+ ret = sock_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, sock);
+ if (ret) {
+ DBPRT("fail to create socket\n");
+ return ret;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = in_aton(ip_addr);
+
+ ret = (*sock)->ops->connect(*sock, (struct sockaddr *)&addr,
+ sizeof(addr), 0);
+
+ if (!ret)
+ DBPRT("connected to %s:%d\n", ip_addr, port);
+
+ return ret;
+}
+
+int do_read(struct socket *sock, char *buf, const size_t length)
+{
+ struct msghdr msg;
+ struct iovec iov;
+ int ret = 0, received = 0, left = length;
+ mm_segment_t oldmm;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ while (left > 0) {
+ msg.msg_iov->iov_base = buf + received;
+ msg.msg_iov->iov_len = left;
+ oldmm = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sock_recvmsg(sock, &msg, left, MSG_WAITALL);
+ set_fs(oldmm);
+ if (ret <= 0)
+ break;
+ left -= ret;
+ received += ret;
+ }
+
+ return ret;
+}
+
+static void forward_iov(struct msghdr *msg, int len)
+{
+ while (msg->msg_iov->iov_len <= len) {
+ len -= msg->msg_iov->iov_len;
+ msg->msg_iov++;
+ msg->msg_iovlen--;
+ }
+
+ msg->msg_iov->iov_base = (char *) msg->msg_iov->iov_base + len;
+ msg->msg_iov->iov_len -= len;
+}
+
+
+static int do_write(struct socket *sock, struct msghdr *msg, int len)
+{
+ int ret;
+ mm_segment_t oldmm;
+
+rewrite:
+ oldmm = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sock_sendmsg(sock, msg, len);
+ set_fs(oldmm);
+
+ if (ret < 0) {
+ if (ret == -EINTR)
+ goto rewrite;
+ if (ret == -EBUSY) {
+ DBPRT("busy\n");
+ goto rewrite;
+ }
+ DBPRT("failed to write to socket: %d\n", ret);
+ return -EFAULT;
+ }
+
+ len -= ret;
+ if (len) {
+ forward_iov(msg, ret);
+ goto rewrite;
+ }
+
+ return 0;
+}
+
+int send_req(struct socket *sock, struct sd_req *hdr, void *data,
+ unsigned int wlen)
+{
+ int ret;
+ struct msghdr msg;
+ struct iovec iov[2];
+
+ memset(&msg, 0, sizeof(msg));
+
+ msg.msg_iov = iov;
+
+ msg.msg_iovlen = 1;
+ iov[0].iov_base = hdr;
+ iov[0].iov_len = sizeof(*hdr);
+
+ if (wlen) {
+ msg.msg_iovlen++;
+ iov[1].iov_base = data;
+ iov[1].iov_len = wlen;
+ }
+
+ ret = do_write(sock, &msg, sizeof(*hdr) + wlen);
+ if (ret) {
+ DBPRT("failed to send request %x, %d\n", hdr->opcode, wlen);
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+int exec_req(struct socket *sock, struct sd_req *hdr, void *data)
+{
+ int ret;
+ struct sd_rsp *rsp = (struct sd_rsp *)hdr;
+ unsigned int wlen, rlen;
+
+ if (hdr->flags & SD_FLAG_CMD_WRITE) {
+ wlen = hdr->data_length;
+ rlen = 0;
+ } else {
+ wlen = 0;
+ rlen = hdr->data_length;
+ }
+
+ if (send_req(sock, hdr, data, wlen))
+ return -EFAULT;
+
+ ret = do_read(sock, (char *)rsp, sizeof(*rsp));
+ if (ret < 0) {
+ DBPRT("failed to read a response\n");
+ return -EFAULT;
+ }
+
+ if (rlen > rsp->data_length)
+ rlen = rsp->data_length;
+
+ if (rlen) {
+ ret = do_read(sock, data, rlen);
+ if (ret < 0) {
+ DBPRT("failed to read the response data\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
diff --git a/sheepdev/sheepdev.h b/sheepdev/sheepdev.h
index 23c93ff..323178c 100644
--- a/sheepdev/sheepdev.h
+++ b/sheepdev/sheepdev.h
@@ -81,6 +81,13 @@ struct sheepdev {
struct sheepdog_inode *inode;
};
+/* connect.c */
+int connect_to(struct socket **sock, const char *addr, int port);
+int send_req(struct socket *sock, struct sd_req *hdr, void *data,
+ unsigned int wlen);
+int do_read(struct socket *sock, char *buf, const size_t length);
+int exec_req(struct socket *sock, struct sd_req *hdr, void *data);
+
/* proc.c */
int sheep_proc_init(void);
void sheep_proc_destroy(void);
--
1.7.11.7
More information about the sheepdog
mailing list